上个月发了一篇 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发包问题