上个月发了一篇 FFMPEG发送AAC及接收AAC 的文章,其中对于LATM,ffmpeg的SDP其实是只针对ffmpeg自己实现的AAC编解码模块的,并不支持FDK-AAC,主要是config字段是有误的。按我们上次的SDP如下:
v=0 o=- 0 0 IN IP4 127.0.0.1 s=You'll Never See Me Again c=IN IP4 127.0.0.1 t=0 0 a=tool:libavformat 57.56.100 m=audio 5000 RTP/AVP 97 b=AS:46 a=rtpmap:97 MP4A-LATM/16000/2 a=fmtp:97 profile-level-id=40;cpresent=0;config=400028203fc0
其中config对应的是400028203fc0。FDK-AAC如果使用latm其实是生成的并不一定是这样的config。之前学习其发送报文的时候,跟踪了下代码。当然,后续其可能会有所更新,目前跟踪的代码是ffmpeg 3.3版本的。在sdp.c中的函数sdp_write_media_attributes,AAC的SDP生成如下:
case AV_CODEC_ID_AAC:
if (fmt && fmt->oformat && fmt->oformat->priv_class &&
av_opt_flag_is_set(fmt->priv_data, "rtpflags", "latm")) {
config = latm_context2config(fmt, p);
if (!config)
return NULL;
av_strlcatf(buff, size, "a=rtpmap:%d MP4A-LATM/%d/%d\r\n"
"a=fmtp:%d profile-level-id=%d;cpresent=0;config=%s\r\n",
payload_type, p->sample_rate, p->channels,
payload_type, latm_context2profilelevel(p), config);
} else {
if (p->extradata_size) {
config = extradata2config(fmt, p);
} else {
/* FIXME: maybe we can forge config information based on the
* codec parameters...
*/
av_log(fmt, AV_LOG_ERROR, "AAC with no global headers is currently not supported.\n");
return NULL;
}
if (!config) {
return NULL;
}
av_strlcatf(buff, size, "a=rtpmap:%d MPEG4-GENERIC/%d/%d\r\n"
"a=fmtp:%d profile-level-id=1;"
"mode=AAC-hbr;sizelength=13;indexlength=3;"
"indexdeltalength=3%s\r\n",
payload_type, p->sample_rate, p->channels,
payload_type, config);
}
break;
其config其实是由函数latm_context2config得到的。而latm_context2config函数实现如下:
static char *latm_context2config(AVFormatContext *s, AVCodecParameters *par)
{
/* MP4A-LATM
* The RTP payload format specification is described in RFC 3016
* The encoding specifications are provided in ISO/IEC 14496-3 */
uint8_t config_byte[6];
int rate_index;
char *config;
for (rate_index = 0; rate_index < 16; rate_index++)
if (avpriv_mpeg4audio_sample_rates[rate_index] == par->sample_rate)
break;
if (rate_index == 16) {
av_log(s, AV_LOG_ERROR, "Unsupported sample rate\n");
return NULL;
}
config_byte[0] = 0x40;
config_byte[1] = 0;
config_byte[2] = 0x20 | rate_index;
config_byte[3] = par->channels << 4;
config_byte[4] = 0x3f;
config_byte[5] = 0xc0;
config = av_malloc(6*2+1);
if (!config) {
av_log(s, AV_LOG_ERROR, "Cannot allocate memory for the config info.\n");
return NULL;
}
ff_data_to_hex(config, config_byte, 6, 1);
config[12] = 0;
return config;
}
这部分字段的生成,有些是写死的,部分是根据当前的声道数以及rate_index生成。并不是FDK-AAC通过函数aacEncInfo来获取编码信息,通过AACENC_InfoStruct结构体中的成员变量confBuf来获取config配置的。所以,如果使用ffmpeg进行latm带外发包的话,其实config可能是错误的,会导致解码失败。不过LATM是支持带内携带SMC配置的。但是,还是不能通过ffmpeg的latm_parse_packet或ff_rtp_send_latm,因为这两个函数都是使用带外传输的方式。至于如何在SDP中区别带内/带外。下次好好说一下RFC3016,就可以知道了!这里简单记录下,自己踩的ffmpeg的坑。希望后续有人实现的时候,能更快的避开这个坑。
转载请注明: 转载自elkPi.com
本文链接地址: ffmpeg fdk-aac发包问题