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博客

相关推荐
VidDown19 小时前
自动给视频挑一张能看的封面:帧评分、构图与批量生成
python·ffmpeg·音视频·视频
可乐鸡翅yeah_2 天前
HLS 业务 Referer‑Policy 网页元标签引发播放异常排错
前端·javascript·网络·ffmpeg·php·音视频
开开心心就好3 天前
本地文件搜索工具推荐,占用小速度还快
智能手机·ffmpeg·ocr·word·音视频·网络攻击模型·安全架构
我科绝伦(Huanhuan Zhou)3 天前
oracle坏块导致备份不了
数据库·oracle·ffmpeg
RS迷途小书童3 天前
Python+FFmpeg提取大疆无人机MP4内嵌mov_text遥测SRT字幕并做完整性校验
python·ffmpeg·大疆·srt字幕·dji
开开心心就好3 天前
视频压缩工具推荐,画质效果很能打
智能手机·ffmpeg·ocr·word·排序算法·音视频·散列表
可乐鸡翅yeah_3 天前
业务中 M3U8 水印相关坑,硬水印和动态水印区别
前端·网络·数据库·ffmpeg·m3u8在线
redfred4 天前
HyperFrames 部署教程:5.6 万 Star 开源「写 HTML 出视频」框架,Windows 从零上手(CLI 三条命令 + 7 个避坑)
ffmpeg·开源·自动化·html·音视频
Arcai10244 天前
PostgreSQL数据备份和恢复完全指南
数据库·postgresql·ffmpeg·备份一体机·备份软件·smartstor·智备科技
可乐鸡翅yeah_4 天前
FFmpeg 生成 HLS 独立分片 independent‑segments 参数到底有什么用
javascript·ffmpeg·音视频·safari·m3u8