ffmpeg fdk-aac发包问题

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

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Scroll to top