stream-deploy/ZLM/3rdpart/media-server/librtsp/source/sdp/sdp-aac.c

159 lines
6.5 KiB
C++

// RFC6184 RTP Payload Format for H.264 Video
#include "mpeg4-aac.h"
#include "sdp-payload.h"
#include "base64.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
// RFC6416 RTP Payload Format for MPEG-4 Audio/Visual Streams
int sdp_aac_latm(uint8_t *data, int bytes, const char* proto, unsigned short port, int payload, int sample_rate, int channel_count, const void* extra, int extra_size)
{
// In the presence of SBR, the sampling rates for the core encoder/
// decoder and the SBR tool are different in most cases. Therefore,
// this parameter SHALL NOT be considered as the definitive sampling rate.
// profile-level-id --> ISO/IEC 14496-3:2009 audioProfileLevelIndication values
static const char* pattern =
"m=audio %hu %s %d\r\n"
"a=rtpmap:%d MP4A-LATM/%d/%d\r\n"
"a=fmtp:%d profile-level-id=%d;object=%d;cpresent=0;config=";
int r, n;
uint8_t config[6];
struct mpeg4_aac_t aac;
//aac.profile = MPEG4_AAC_LC;
//aac.channel_configuration = (uint8_t)channel_count;
//aac.sampling_frequency_index = (uint8_t)mpeg4_aac_audio_frequency_from(sample_rate);
r = mpeg4_aac_audio_specific_config_load((const uint8_t*)extra, extra_size, &aac);
if (r < 0) return r;
sample_rate = 0 == sample_rate ? mpeg4_aac_audio_frequency_to(aac.sampling_frequency_index) : sample_rate;
channel_count = 0 == channel_count ? aac.channel_configuration : channel_count;
assert(aac.sampling_frequency_index == (uint8_t)mpeg4_aac_audio_frequency_from(sample_rate));
assert(aac.channel_configuration == channel_count);
r = mpeg4_aac_stream_mux_config_save(&aac, config, sizeof(config));
if (r < 0) return r;
// the "rate" parameter indicates the RTP timestamp "clock rate".
// The default value is 90000. Other rates MAY be indicated
// only if they are set to the same value as the audio sampling rate
sample_rate = 0 == sample_rate ? 90000 : sample_rate;
n = snprintf((char*)data, bytes, pattern, port,
proto && *proto ? proto : "RTP/AVP",
payload, payload, sample_rate, channel_count,
payload, mpeg4_aac_profile_level(&aac), aac.profile);
if (n + r * 2 + 1 > bytes)
return -ENOMEM; // don't have enough memory
n += (int)base16_encode((char*)data + n, config, r);
if (n + 2 > bytes)
return -ENOMEM; // don't have enough memory
data[n++] = '\r';
data[n++] = '\n';
return n;
}
// RFC 3640 3.3.1. General (p21)
int sdp_aac_generic(uint8_t *data, int bytes, const char* proto, unsigned short port, int payload, int sample_rate, int channel_count, const void* extra, int extra_size)
{
// a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding parameters > ]
// For audio streams, <encoding parameters> specifies the number of audio channels, default value is 1.
// streamType: AudioStream --> ISO/IEC 14496-1:2010 streamType Values
// profile-level-id --> ISO/IEC 14496-3:2009 audioProfileLevelIndication values
// When using SDP, the clock rate of the RTP time stamp MUST be expressed using the "rtpmap" attribute.
// If an MPEG-4 audio stream is transported, the rate SHOULD be set to the same value as the sampling rate of the audio stream.
// If an MPEG-4 video stream transported, it is RECOMMENDED that the rate be set to 90 kHz.
static const char* pattern =
"m=audio %hu %s %d\r\n"
"a=rtpmap:%d mpeg4-generic/%d/%d\r\n"
"a=fmtp:%d streamtype=5;profile-level-id=%d;mode=AAC-hbr;sizeLength=13;indexLength=3;indexDeltaLength=3;config=";
int r, n;
struct mpeg4_aac_t aac;
r = mpeg4_aac_audio_specific_config_load((const uint8_t*)extra, extra_size, &aac);
if (r < 0) return r;
sample_rate = 0 == sample_rate ? mpeg4_aac_audio_frequency_to(aac.sampling_frequency_index) : sample_rate;
channel_count = 0 == channel_count ? aac.channel_configuration : channel_count;
assert(aac.sampling_frequency_index == (uint8_t)mpeg4_aac_audio_frequency_from(sample_rate));
assert(aac.channel_configuration == channel_count);
n = snprintf((char*)data, bytes, pattern, port, proto && *proto ? proto : "RTP/AVP", payload, payload, sample_rate, channel_count, payload, mpeg4_aac_profile_level(&aac));
if (n + extra_size * 2 + 1 > bytes)
return -ENOMEM; // don't have enough memory
// For MPEG-4 Audio streams, config is the audio object type specific
// decoder configuration data AudioSpecificConfig()
n += (int)base16_encode((char*)data + n, extra, extra_size);
if (n + 2 > bytes)
return -ENOMEM; // don't have enough memory
data[n++] = '\r';
data[n++] = '\n';
return n;
}
/// @return >0-ok, <=0-error
int sdp_aac_latm_load(uint8_t* data, int bytes, const char* config)
{
int n;
uint8_t buf[128];
struct mpeg4_aac_t aac;
n = (int)strlen(config);
if (n / 2 > sizeof(buf))
return -E2BIG;
n = (int)base16_decode(buf, config, n);
n = mpeg4_aac_stream_mux_config_load(buf, n, &aac);
return n <= 0 ? n : mpeg4_aac_audio_specific_config_save(&aac, data, bytes);
}
/// @return >0-ok, <=0-error
int sdp_aac_mpeg4_load(uint8_t* data, int bytes, const char* config)
{
int n;
n = (int)strlen(config);
if (n / 2 > bytes)
return -E2BIG;
return (int)base16_decode(data, config, n);
}
#if defined(_DEBUG) || defined(DEBUG)
void sdp_aac_test(void)
{
// rfc3640
//const unsigned char celpcbr[] = { "440E00" }; // 16000/1 streamtype=5; profile-level-id=14
//const unsigned char celpvbr[] = { "440F20" }; // 16000/1 streamtype=5; profile-level-id=14
//const unsigned char aaclbr[] = { "1388" }; // 22050/1 streamtype=5; profile-level-id=14
//const unsigned char aachbr[] = { "11B0" }; // 48000/6 streamtype=5; profile-level-id=16
const uint8_t config[] = { 0x11, 0x90, };
//const char* mpeg4_generic_sdp = "m=audio 0 RTP/AVP 96\r\na=rtpmap:96 mpeg4-generic/48000/2\r\na=fmtp:96 streamtype=5; profile-level-id=15; mode=AAC-hbr; config=1190; SizeLength=13; IndexLength=3; IndexDeltaLength=3; Profile=1\r\n";
const char* mpeg4_generic_sdp = "m=audio 0 RTP/AVP 96\r\na=rtpmap:96 mpeg4-generic/48000/2\r\na=fmtp:96 streamtype=5;profile-level-id=41;mode=AAC-hbr;sizeLength=13;indexLength=3;indexDeltaLength=3;config=1190\r\n";
//const char* mp4a_latm_sdp = "m=audio 0 RTP/AVP 96\r\na=rtpmap:96 MP4A-LATM/48000/2\r\na=fmtp:96 profile-level-id=9;object=8;cpresent=0;config=9128B1071070\r\n";
uint8_t buffer[256];
//struct mpeg4_aac_t aac;
//int n;
assert((int)strlen(mpeg4_generic_sdp) == sdp_aac_generic(buffer, sizeof(buffer), "RTP/AVP", 0, 96, 48000, 2, config, sizeof(config)));
assert(0 == memcmp(mpeg4_generic_sdp, buffer, strlen(mpeg4_generic_sdp)));
assert(sizeof(config) == sdp_aac_mpeg4_load(buffer, sizeof(buffer), "1190"));
assert(0 == memcmp(config, buffer, sizeof(config)));
}
#endif