当前位置: 首页 > article >正文

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;

    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

    /* 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;
        }
        //音频的packed格式的数据,都存在data[0]中,并且是连续的;stereo planer格式才会在data[0]和data[1]中存放
        //packed :LLRRLLRRLLRRLLRR
        //planer :LLLLLLLL....RRRRRRRRR....
        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;
}

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


http://www.kler.cn/a/472678.html

相关文章:

  • 2025新春烟花代码(二)HTML5实现孔明灯和烟花效果
  • 3D机器视觉的类型、应用和未来趋势
  • 深度学习与计算机视觉 (博士)
  • 课题推荐——基于GPS的无人机自主着陆系统设计
  • Wi-Fi Direct (P2P)原理及功能介绍
  • 年会抽奖Html
  • idea 编辑竖列:alt +shift+insert
  • Python的Matplotlib库应用(超详细教程)
  • C++ ——— 匿名对象
  • Spring AI零起点搭建AI应用
  • spring:xml声明bean的多种方式。
  • 电脑32位和64位之区别(Difference between 32-Bit and 64 Bit Computers)
  • Python —— 常用的字符串方法
  • STM32-笔记39-SPI-W25Q128
  • python matplotlib.pyplot中绘制带文字标注的箭头,使其指向某一特定数据点
  • 使用SpringBoot-data-mongodb操作MongoDB
  • 总结2024,迎接2025
  • 一套极简易的直流无刷电机(Deng FOC)开发套件介绍
  • 企业开通部署 Azure OpenAI 流程:如何创建一个AI聊天机器人
  • 【深度学习基础】线性神经网络 | 线性回归的简洁实现
  • 单片机死机问题处理
  • (2023|NIPS,LLaVA-Med,生物医学 VLM,GPT-4 生成自指导指令跟随数据集,数据对齐,指令调优)
  • 简易CPU设计入门:算术逻辑单元(一)
  • 技术选型深度解析:Qt、PyQt与Vue在界面开发中的权衡与抉择
  • Linux 文件的特殊权限—ACL项目练习
  • 协方差矩阵