FFmpeg 编解码处理系列笔记: [0]. FFmpeg时间戳详解 [1]. FFmpeg编解码处理1-转码全流程简介 [2]. FFmpeg编解码处理2-编解码API详解 [3]. FFmpeg编解码处理3-视频编码 [4]. FFmpeg编解码处理4-音频编码
基于 FFmpeg 4.1 版本。
1. 音频编码
编码使用 avcodec_send_frame() 和 avcodec_receive_packet() 两个函数。
音频编码的步骤: [1] 初始化打开输出文件时构建编码器上下文 [2] 音频帧编码 [2.1] 将滤镜输出的音频帧写入音频 FIFO [2.2] 按音频编码器中要求的音频帧尺寸从音频 FIFO 中取出音频帧 [2.3] 为音频帧生成 pts [2.4] 将音频帧送入编码器,从编码器取出编码帧 [2.5] 更新编码帧流索引 [2.6] 将帧中时间参数按输出封装格式的时间基进行转换
1.1 打开视频编码器
完整源码在 open_output_file() 函数中,下面摘出关键部分:
// 3. 构建AVCodecContext if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO || dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) // 音频流或视频流 { // 3.1 查找编码器AVCodec,本例使用与解码器相同的编码器 AVCodec *encoder = NULL; if ((dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) && (strcmp(v_enc_name, "copy") != 0)) { encoder = avcodec_find_encoder_by_name(v_enc_name); } else if ((dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) && (strcmp(a_enc_name, "copy") != 0)) { encoder = avcodec_find_encoder_by_name(a_enc_name); } else { encoder = avcodec_find_encoder(dec_ctx->codec_id); } if (!encoder) { av_log(NULL, AV_LOG_FATAL, "Necessary encoder not found\n"); return AVERROR_INVALIDDATA; } // 3.2 AVCodecContext初始化:分配结构体,使用AVCodec初始化AVCodecContext相应成员为默认值 AVCodecContext *enc_ctx = avcodec_alloc_context3(encoder); if (!enc_ctx) { av_log(NULL, AV_LOG_FATAL, "Failed to allocate the encoder context\n"); return AVERROR(ENOMEM); } // 3.3 AVCodecContext初始化:配置图像/声音相关属性 /* In this example, we transcode to same properties (picture size, * sample rate etc.). These properties can be changed for output * streams easily using filters */ if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { enc_ctx->height = dec_ctx->height; // 图像高 enc_ctx->width = dec_ctx->width; // 图像宽 enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio; // 采样宽高比:像素宽/像素高 /* take first format from list of supported formats */ if (encoder->pix_fmts) // 编码器支持的像素格式列表 { enc_ctx->pix_fmt