【FFmpeg 3.x API应用四】音频编码
2018-02-13 16:58
393 查看
摘要
这篇文章介绍音频编码,示例程序是读取上一节生成的PCM格式的音频文件,对其进行编码输出。初始化
这个必备的操作就不多说了。void AudioEncoding::init() { avcodec_register_all(); }
配置编解码器CodecContext
查找编码器。在视频编码那一节我们使用avcodec_find_encoder_by_name("libx264")函数根据编码器名字查找对应的编码器,在这里我们可以使用编码器ID来查找对应的编码器,指定MP3编码器。
根据编码器申请CodecContext。
配置CodecContext各项参数。
打开CodecContext,完成初始化。
bool AudioEncoding::initCodecContext() { // 根据编码器ID查找对应的编码器 const AVCodec *enc = avcodec_find_encoder(AV_CODEC_ID_MP3); if (!enc) { printf("Failed to find codec\n"); return true; } mCodecCtx = avcodec_alloc_context3(enc); if (!mCodecCtx) { printf("Failed to allocate the codec context\n"); return true; } mCodecCtx->bit_rate = 128000; //码率 128k mCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16P; //使用上一节生成的pcm文件,对应的采样格式 mCodecCtx->sample_rate = 44100; //采样率 mCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO; //双声道立体声 mCodecCtx->channels = 2; //声道数 //完成初始化 if (avcodec_open2(mCodecCtx, enc, NULL) < 0) { printf("Failed to open encodec\n"); return true; } return false; }
音频编码,保存mp3文件
申请一个frame结构,对其进行相应的配置。循环读取pcm文件数据进行处理。
把读取的pcm数据填充到frame中,即解码写文件的逆过程。
对frame结构进行编码,接收编码后的packet。
持续接收延时编码后的数据packet。
bool AudioEncoding::readFrameProc(const char * input, const char * output) { //输入文件out_s16le.pcm,输出文件Out.mp3 FILE *pcmFd = fopen(input, "rb"); FILE *outFd = fopen(output, "wb"); if (!outFd || !pcmFd) { fprintf(stderr, "Could not open file\n"); return true; } //申请frame AVFrame *frame = av_frame_alloc(); if (!frame) { printf("Failed to allocate video frame\n"); return true; } //配置frame frame->format = mCodecCtx->sample_fmt; frame->nb_samples = mCodecCtx->frame_size; frame->channel_layout = mCodecCtx->channel_layout; //为frame申请存放媒体数据的buff if (av_frame_get_buffer(frame, 0) < 0) { printf("Failed to allocate the video frame data\n"); return true; } int num = 0; AVPacket pkt; //循环读取pcm文件 while (!feof(pcmFd)) { av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; if (av_frame_make_writable(frame)) { return true; } int sampleBytes = av_get_bytes_per_sample(mCodecCtx->sample_fmt); // AV_SAMPLE_FMT_S16P // 读取pcm文件,填充frame.data结构 for (int i = 0; i < frame->nb_samples; i++) for (int ch = 0; ch < mCodecCtx->channels; ch++) fread(frame->data[ch] + i*sampleBytes, 1, sampleBytes, pcmFd); //音频编码,发送frame接收packet avcodec_send_frame(mCodecCtx, frame); int ret = avcodec_receive_packet(mCodecCtx, &pkt); if (!ret) { printf("Write frame %3d (size=%5d)\n", num++, pkt.size); fwrite(pkt.data, 1, pkt.size, outFd); av_packet_unref(&pkt); } } printf("------------- get delayed data --------------------\n"); //持续接收编码延迟的数据 for (;;) { avcodec_send_frame(mCodecCtx, NULL); int ret = avcodec_receive_packet(mCodecCtx, &pkt); if (ret == 0) { printf("Write frame %3d (size=%5d)\n", num++, pkt.size); fwrite(pkt.data, 1, pkt.size, outFd); av_packet_unref(&pkt); } else if (ret == AVERROR_EOF) { printf("Write frame complete\n"); break; } else { printf("Error encoding frame\n"); break; } } fclose(outFd); fclose(pcmFd); av_frame_free(&frame); return false; }
释放系统资源
AudioEncoding::~AudioEncoding() { avcodec_free_context(&mCodecCtx); }
示例程序代码
上述示例的完整代码可以从Github下载: https://github.com/lmshao/FFmpeg-Basic 。相关文章推荐
- 【FFmpeg 3.x API应用二】视频编码
- 【FFmpeg 3.x API应用三】音频解码
- 利用ffmpeg提供的库(API)进行音频与视频的编码并生成文件
- 【FFmpeg 3.x API应用一】视频解码
- KnockoutJS 3.X API 第五章 高级应用(4) 自定义处理逻辑
- ffmpeg应用x264编码, 编码参数解析
- FFMpeg中apiexample.c例子分析——编码分析
- WebRTC VideoEngine综合应用示例(三)——集成X264编码和ffmpeg解码
- FFMpeg中apiexample.c例子分析——编码分析
- 【FFMpeg视频开发与应用基础】二、调用FFmpeg SDK对YUV视频序列进行编码
- 编码音频aac的时候 (avcodec_encode_audio2)提示FFMPEG more samples than frame size 的错误
- FFmpeg浅尝辄止(四)——音频的解码和编码
- ffmpeg音频编码
- 第四周 使用API和C编码中的嵌入式汇编 来应用同一个系统调用
- ffmpeg音频编码
- ffmpeg--音频的解码和编码
- KnockoutJS 3.X API 第五章 高级应用(5) 使用预处理扩展Knockout绑定语法
- ffmpeg音频编码
- WebRTC VideoEngine综合应用示例(三)——集成X264编码和ffmpeg解码
- 数据压缩原理与应用 MPEG音频编码