ffmpeg aac s16 encode_audio.c

用ffmpeg库时,用代码对pcm内容采用aac编码进行压缩,出现如下错误。

aac @ 000002bc5edc6e40 Format aac detected only with low score of 1, misdetection possible!

aac @ 000002bc5edc8140 Error decoding AAC frame header.

aac @ 000002bc5edc8140 More than one AAC RDB per ADTS frame is not implemented. Update your FFmpeg version to the newest one from Git. If the problem still occurs, it means that your file has a feature which has not been implemented.

aac @ 000002bc5edc8140 Multiple frames in a packet.

aac @ 000002bc5edc8140 Sample rate index in program config element does not match the sample rate index configured by the container.

aac @ 000002bc5edc8140 Too large remapped id is not implemented. Update your FFmpeg version to the newest one from Git. If the problem still occurs, it means that your file has a feature which has not been implemented.

aac @ 000002bc5edc8140 If you want to help, upload a sample of this file to https://streams.videolan.org/upload/ and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)

aac @ 000002bc5edc8140 Sample rate index in program config element does not match the sample rate index configured by the container.

aac @ 000002bc5edc8140 channel element 1.3 is not allocated

aac @ 000002bc5edc8140 SBR was found before the first channel element.

aac @ 000002bc5edc8140 channel element 3.6 is not allocated

aac @ 000002bc5edc8140 channel element 2.12 is not allocated

aac @ 000002bc5edc8140 Assuming an incorrectly encoded 7.1 channel layout instead of a spec-compliant 7.1(wide) layout, use -strict 1 to decode according to the specification instead.

aac @ 000002bc5edc8140 channel element 3.12 is not allocated

aac @ 000002bc5edc6e40 Packet corrupt (stream = 0, dts = NOPTS).

aac @ 000002bc5edc8140 channel element 1.9 is not allocated

aac @ 000002bc5edc6e40 Estimating duration from bitrate, this may be inaccurate

aac @ 000002bc5edc6e40 Could not find codec parameters for stream 0 (Audio: aac (LTP), 3.0, fltp, 505 kb/s): unspecified sample rate

Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options

过程分析:

数据源是无压缩的pcm数据(cr:44100, cn=2(stereo) , format:s16 ) 。

同样的内容如果使用命令行进行压缩

ffmpeg -i E:/video/out.pcm -ar 44100 -b 128K -ac 2 -c:a aac_mf E:/video/out1.aac -y

进行压缩,发现能进行播放。

(ffmpeg中的aac不支持s16格式数据,aac_mf才支持,可以用ffmpeg -h encoder=aac 查看)

使用代码进行压缩出现上图右边的错误。测试代码是从ffmpeg/doc/example/encode_audio.c 上进行更改的。

没有进入ffmpeg源码进行调试,只能从现有的结果进行分析,发现代码生成的内容大小是没有问题的,但是被ffmpeg错误解析。猜测应该是数据包头解析错误。但是因为之前没有做过aac编码,真是瞎子摸象,一句一句的修改测试,无果。

最后在网上找到一个能运行的demo才解决问题:FFmpeg简单使用:音频编码 ---- pcm转aac_avframe 音频 aac-CSDN博客

最后发现原因是aac编码后的数据包写入文件时需要额外写入数据包头,而demo中的代码太简单,根本没有这个步骤,下面是代码示例:

复制代码
static void get_adts_header(AVCodecContext *ctx, uint8_t *adts_header, int aac_length)
{
    uint8_t freq_idx = 0;    //0: 96000 Hz  3: 48000 Hz 4: 44100 Hz
    switch (ctx->sample_rate) {
    case 96000: freq_idx = 0; break;
    case 88200: freq_idx = 1; break;
    case 64000: freq_idx = 2; break;
    case 48000: freq_idx = 3; break;
    case 44100: freq_idx = 4; break;
    case 32000: freq_idx = 5; break;
    case 24000: freq_idx = 6; break;
    case 22050: freq_idx = 7; break;
    case 16000: freq_idx = 8; break;
    case 12000: freq_idx = 9; break;
    case 11025: freq_idx = 10; break;
    case 8000: freq_idx = 11; break;
    case 7350: freq_idx = 12; break;
    default: freq_idx = 4; break;
    }
    uint8_t chanCfg = ctx->channels;
    uint32_t frame_length = aac_length + 7;
    adts_header[0] = 0xFF;
    adts_header[1] = 0xF1;
    adts_header[2] = ((ctx->profile) << 6) + (freq_idx << 2) + (chanCfg >> 2);
    adts_header[3] = (((chanCfg & 3) << 6) + (frame_length  >> 11));
    adts_header[4] = ((frame_length & 0x7FF) >> 3);
    adts_header[5] = (((frame_length & 7) << 5) + 0x1F);
    adts_header[6] = 0xFC;
}

static void encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt,
                   FILE *output)
{
    int ret;

    /* send the frame for encoding */
    ret = avcodec_send_frame(ctx, frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending the frame to the encoder\n");
        exit(1);
    }

    /* read all the available output packets (in general there may be any
     * number of them */
    while (ret >= 0) {
        ret = avcodec_receive_packet(ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
            fprintf(stderr, "Error encoding audio frame\n");
            exit(1);
        }
        //额外写入包头
        uint8_t aac_header[7];
        get_adts_header(ctx, aac_header, pkt->size);

        size_t len = 0;
        len = fwrite(aac_header, 1, 7, output);
        if(len != 7) {
            fprintf(stderr, "fwrite aac_header failed\n");
            return -1;
        }

//        printf("%d:%d\n",count++,pkt->pts);
        fwrite(pkt->data, 1, pkt->size, output);
        //av_packet_unref(pkt);
    }
}


int main(int argc, char **argv)
{
    const char *filename;
    const AVCodec *codec;
    AVCodecContext *c= NULL;
    AVFrame *frame;
    AVPacket *pkt;
    int i, j, k, ret;
    FILE *f;
    uint16_t *samples;
    float t, tincr;
    filename="E:/video/out.aac";

    /* find the MP2 encoder */
    //codec = avcodec_find_encoder(AV_CODEC_ID_MP2);
    //codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    //printf("%s\n",avcodec_get_id( AV_CODEC_ID_AAC_LATM));

    codec = avcodec_find_encoder_by_name("aac_mf");
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        exit(1);
    }
    c = avcodec_alloc_context3(codec);
    if (!c) {
        fprintf(stderr, "Could not allocate audio codec context\n");
        exit(1);
    }

    /* put sample parameters */
    c->bit_rate = 64000;

    /* check that the encoder supports s16 pcm input */
    c->sample_fmt = AV_SAMPLE_FMT_S16;
    if (!check_sample_fmt(codec, c->sample_fmt)) {
        fprintf(stderr, "Encoder does not support sample format %s",
                av_get_sample_fmt_name(c->sample_fmt));
        exit(1);
    }
    //c->profile = FF_PROFILE_AAC_LOW;  c->bit_rate为0,c->profile设置才会有效

    /* select other audio parameters supported by the encoder */
    c->sample_rate    = select_sample_rate(codec);
    ret = select_channel_layout(codec, &c->ch_layout);
    if (ret < 0)
        exit(1);

    c->channels = c->ch_layout.nb_channels;

//sample_rate(cr)=44100,表示1秒钟有44100个采样点。格式为s16 + stereo表示双通道,每通道16位(short) packed格式,(S16P 表示双通道通道16位planar格式)
//也就是一个采样点需要4个字节来保存。这里的frame_size 表示采样点个数。
    c->frame_size=512;//手动设置frame_size

//	声音的timebase设置为采样率或其倍数,因为PTS是int64的。如果timebase刚好等于sample_rate,
//	那么更具pts计算公式 audio_pts = n*frame_size*timebase/sample_rate = n*frame_size
//	这样对时间的pts设置极为方便。
    c->time_base=av_make_q(c->sample_rate,1);//手动设置time_base,



    /* open it */
    if (avcodec_open2(c, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        exit(1);
    }

    f = fopen(filename, "wb");
    if (!f) {
        fprintf(stderr, "Could not open %s\n", filename);
        exit(1);
    }

    /* packet for holding encoded output */
    pkt = av_packet_alloc();
    if (!pkt) {
        fprintf(stderr, "could not allocate the packet\n");
        exit(1);
    }

    /* frame containing input raw audio */
    frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "Could not allocate audio frame\n");
        exit(1);
    }

    frame->nb_samples     = c->frame_size;
    frame->format         = c->sample_fmt;
    ret = av_channel_layout_copy(&frame->ch_layout, &c->ch_layout);
    if (ret < 0)
        exit(1);
    frame->channels = c->channels;
	frame->pts = 0;   //初始化pts

//音频的packed格式的数据,都存在data[0]中,并且是连续的;stereo planer格式才会将左右两个通道分开在data[0]和data[1]中存放,av_frame_get_buffer会为frame按照参数申请缓存。
//packed :LLRRLLRRLLRRLLRR
//planer :LLLLLLLL....RRRRRRRRR....
    /* allocate the data buffers */
    ret = av_frame_get_buffer(frame, 0);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate audio data buffers\n");
        exit(1);
    }

    /* encode a single tone sound */
    t = 0;
    uint8_t *buffer = malloc(frame->nb_samples*frame->ch_layout.nb_channels*av_get_bytes_per_sample(frame->format));
    tincr = 2 * M_PI * 440.0 / c->sample_rate;
    for (i = 0; i < 200; i++) {
        /* make sure the frame is writable -- makes a copy if the encoder
         * kept a reference internally */
        ret = av_frame_make_writable(frame);
        if (ret < 0)
            exit(1);
        samples = (uint16_t*)buffer;

        for (j = 0; j < c->frame_size; j++) {
            samples[2*j] = (int)(sin(t) * 10000);

            for (k = 1; k < c->ch_layout.nb_channels; k++)
                samples[2*j + k] = samples[2*j];
            t += tincr;
        }

        ret = av_samples_fill_arrays(frame->data, frame->linesize,
                                     buffer, frame->channels,frame->nb_samples,
                                     frame->format, 0);

        frame->pts += frame->nb_samples;
        encode(c, frame, pkt, f);
    }

    /* flush the encoder */
    encode(c, NULL, pkt, f);

    free(buffer);

    fclose(f);

    av_frame_free(&frame);
    av_packet_free(&pkt);
    avcodec_free_context(&c);

    return 0;
}

7-5ADTS格式_哔哩哔哩_bilibili

AAC ADTS格式分析&AAC编码(adts_header详解)_adts header-CSDN博客

相关推荐
Yeauty1 天前
用 Whisper 转录前,你不用再离开 Rust
开发语言·rust·ffmpeg·音视频·视频
paokuflying2 天前
ffmpeg提取视频中的音频
ffmpeg·音视频
Tirzano2 天前
java 精简使用ffmpeg
java·开发语言·ffmpeg
兵叔物联4 天前
基于FFmpeg的短视频自动剪辑工具
ffmpeg·音视频
霸道流氓气质6 天前
视频预览链路三件套:ZLMediaKit · MediaMTX · FFmpeg 完全指南
ffmpeg·音视频
xgc_java6 天前
在Java里把ONNX/OpenCV/FFmpeg跑稳:28篇bytedeco实战小册完整指南
java·opencv·ffmpeg
鲲穹AI全能助理12 天前
实用音频合成工具分享:灵境配音 使用场景与功能说明
ffmpeg·音视频
我是Superman丶12 天前
Windows系统FFmpeg官方下载+完整安装配置保姆级教程(2026最新版)
windows·ffmpeg
luoyayun36113 天前
Qt + FFmpeg 视频工具:视频一键压缩功能实现
qt·ffmpeg·音视频·视频压缩
雪的季节13 天前
ffmpeg源码国内gitee下载
ffmpeg·gitee