使用FFmpeg将pcm数据编码为aac
发布日期:2021-06-28 18:55:53 浏览次数:3 分类:技术文章

本文共 4917 字,大约阅读时间需要 16 分钟。

代码对一些数据没做判断,仅仅是做个备忘!请谨慎参考!

#include 
#include
void f32le_convert_to_fltp(float *f32le, float *fltp, int nb_samples) { float *fltp_l = fltp; // 左通道 float *fltp_r = fltp + nb_samples; // 右通道 for (int i = 0; i < nb_samples; i++) { fltp_l[i] = f32le[i * 2]; fltp_r[i] = f32le[i * 2 + 1]; }}static void get_adts_header(AVCodecContext *ctx, uint8_t *adts_header, int aac_length) { uint8_t freq_idx = 0; 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;}void encode_audio(AVCodecContext *codec_ctx, AVFrame *frame, AVPacket *pkt, FILE *out_aac) { int ret; ret = avcodec_send_frame(codec_ctx, frame); while (!ret) { ret = avcodec_receive_packet(codec_ctx, pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { printf("EAGAIN OR EOF\n"); return; } else if (ret < 0) { printf("error 6\n"); exit(1); } if ((codec_ctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) { uint8_t aac_header[7];//7个字节的adts header get_adts_header(codec_ctx, aac_header, pkt->size); ret = fwrite(aac_header, 1, 7, out_aac); if (ret != 7) { fprintf(stderr, "fwrite aac_header failed\n"); return -1; } } fwrite(pkt->data, 1, pkt->size, out_aac); }}/** * @brief 音频编码 PCM编码为AAC * @param argc * @param argv * @return */int main(int argc, char **argv) { AVCodecContext *codec_ctx; AVCodec *codec; FILE *in_pcm; FILE *out_aac; AVPacket *pkt; AVFrame *frame; int ret; if(argc != 3){ printf("param error\n"); exit(1); } in_pcm = fopen(argv[1], "rb"); out_aac = fopen(argv[2], "wb"); codec = avcodec_find_encoder(AV_CODEC_ID_AAC); if (!codec) { printf("error 1\n"); exit(1); } codec_ctx = avcodec_alloc_context3(codec); codec_ctx->codec_id = AV_CODEC_ID_AAC; codec_ctx->sample_rate = 44100; codec_ctx->bit_rate = 512 * 1024; codec_ctx->channels = 2; codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO; codec_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; codec_ctx->profile = FF_PROFILE_AAC_LOW; codec_ctx->codec_type = AVMEDIA_TYPE_AUDIO; codec_ctx->time_base = (AVRational){1, codec_ctx->sample_rate}; codec_ctx->flags = AV_CODEC_FLAG_GLOBAL_HEADER; ret = avcodec_open2(codec_ctx, codec, NULL); if (ret) { printf("error 2\n"); exit(1); } frame = av_frame_alloc(); frame->nb_samples = codec_ctx->frame_size; frame->channels = 2; frame->channel_layout = AV_CH_LAYOUT_STEREO; frame->format = codec_ctx->sample_fmt; ret = av_frame_get_buffer(frame, 0); int nb_samples = 0; if (ret) { printf("error 3\n"); exit(1); } pkt = av_packet_alloc(); av_init_packet(pkt); int bytes_per_frame = av_get_bytes_per_sample(AV_SAMPLE_FMT_FLTP) * frame->nb_samples * frame->channels; uint8_t *in_buf = (uint8_t *)av_mallocz(bytes_per_frame); uint8_t *in_buf_temp = (uint8_t *)malloc(bytes_per_frame); if (!in_buf_temp) { printf("in_buf_temp malloc failed\n"); return 1; } while (fread(in_buf, 1, bytes_per_frame, in_pcm) == bytes_per_frame) { ret = av_frame_make_writable(frame); //fltp如果是按照packeted方式存储的,需要先转换成planar方式// memset(in_buf_temp, 0, bytes_per_frame);// f32le_convert_to_fltp((float *)in_buf, (float *)in_buf_temp,// frame->nb_samples); ret = av_samples_fill_arrays(frame->data, frame->linesize, in_buf/*in_buf_temp*/, frame->channels, frame->nb_samples, frame->format, 0); if (ret < 0) { printf("error 4\n"); exit(1); } frame->pts = nb_samples; nb_samples += frame->nb_samples; encode_audio(codec_ctx, frame, pkt, out_aac); memset(in_buf, 0, bytes_per_frame); } encode_audio(codec_ctx, NULL, pkt, out_aac);end: fclose(in_pcm); fclose(out_aac); avcodec_free_context(&codec_ctx); av_frame_free(&frame); av_packet_free(&pkt); printf("Hello World!\n"); return 0;}

 

转载地址:https://blog.csdn.net/XTASK/article/details/117711849 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:使用FFmpeg将S16格式音频数据重采样为FLTP格式
下一篇:Uncaught ReferenceError: $axure is not defined

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月19日 07时05分42秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

安卓开发视频教学!10天用Flutter撸了个高仿携程App,内含福利 2019-04-29
安卓主板开发!Android之内存泄漏调试学习与总结,社招面试心得 2019-04-29
安卓前端开发框架!完美讲解内存缓存LruCache实现原理,吐血整理 2019-04-29
安卓前端开发框架!轻松获得一线大厂面试offer,附答案 2019-04-29
安卓前端开发!Android性能优化之APK优化,赶快收藏备战金九银十! 2019-04-29
安卓定制系统开发!这是一份面向Android开发者的复习指南,系列篇 2019-04-29
安卓客户端开发!如何试出一个Android开发者真正的水平?分享PDF高清版 2019-04-29
安卓平板app开发!实战讲述Flutter跨平台框架应用,附大厂真题面经 2019-04-29
安卓开发包!大佬手把手教你如何仿写出大厂的APP,含BATJM大厂 2019-04-29
Android事件分发机制及设计思路,先收藏了 2019-04-29
Android事件分发机制收藏这一篇就够了,不吃透都对不起自己 2019-04-29
Android内存泄漏总结,offer拿到手软 2019-04-29
Android内存泄漏总结,成功拿下大厂offer 2019-04-29
来看看移动端小程序技术的前世今生!讲的明明白白! 2019-04-29
来看看这份超全面的《Android面试题及解析》,大厂面经合集 2019-04-29
4面字节跳动拿到Offer,已拿到offer 2019-04-29
4面字节跳动拿到Offer,真香! 2019-04-29
4面阿里拿到P7Offer,赶紧收藏! 2019-04-29
6年老Android面经总结,大牛最佳总结 2019-04-29
7年老Android一次坑爹的面试经历,赶快收藏备战金九银十! 2019-04-29