引言
FFmpeg 是强大的开源音视频处理库,能实现多种音视频操作。本文将分享如何用 FFmpeg 把 H.264 视频文件转码为 MP4 格式。
代码整体思路
代码把转码功能封装在 TranceVideo
类中,通过一系列步骤完成 H.264 到 MP4 的转码,包括初始化、打开输入文件、获取视频流信息、确定输出格式、创建输出文件、转码并写入帧数据,最后清理资源。
详细步骤
1. 初始化
在类的构造函数里,进行基础的初始化操作:
cpp
// 注册 FFmpeg 所有组件
av_register_all();
// 分配输入和输出格式上下文
inFormatContext = avformat_alloc_context();
outFormatContext = avformat_alloc_context();
// 分配 AVPacket 用于存储编码后的数据
pkt = (AVPacket*)malloc(sizeof(AVPacket));
// 初始化视频流索引为 -1
videoIndex = -1;
先注册 FFmpeg 组件,接着分配输入输出格式上下文和 AVPacket
内存,同时初始化视频流索引。
2. 打开输入文件
cpp
// 打开 H.264 文件
avformat_open_input(&inFormatContext, filepath, nullptr, nullptr);
// 获取视频流信息
avformat_find_stream_info(inFormatContext, nullptr);
// 查找视频流索引
for (int i = 0; i < inFormatContext->nb_streams; ++i) {
if (inFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoIndex = i;
break;
}
}
使用 avformat_open_input
打开文件,avformat_find_stream_info
获取流信息,再遍历流找到视频流索引。
3. 准备输出文件
cpp
// 猜测输出文件格式
outputFormat = av_guess_format(nullptr, output_filepath, nullptr);
// 设置输出格式
outFormatContext->oformat = outputFormat;
// 打开输出文件的 I/O 流
avio_open(&outFormatContext->pb, output_filepath, AVIO_FLAG_WRITE);
// 创建新的视频流
AVStream *newStream = avformat_new_stream(outFormatContext, nullptr);
// 复制原视频流的编解码器参数
avcodec_parameters_copy(newStream->codecpar, inFormatContext->streams[videoIndex]->codecpar);
// 写入输出文件头信息
avformat_write_header(outFormatContext, nullptr);
先猜测输出格式,设置到输出格式上下文,打开输出文件 I/O 流,创建新视频流,复制编解码器参数,最后写入文件头信息。
4. 转码处理
cpp
while (av_read_frame(inFormatContext, pkt) == 0) {
if (pkt->stream_index == videoIndex) {
// 处理时间戳和时长
if (pkt->pts == AV_NOPTS_VALUE) {
// 计算 pts、dts 和 duration
} else if (pkt->pts < pkt->dts) {
continue;
}
// 时间基转换
pkt->dts = av_rescale_q_rnd(pkt->dts, in_time_base, out_time_base, ...);
pkt->pts = av_rescale_q_rnd(pkt->pts, in_time_base, out_time_base, ...);
pkt->duration = av_rescale_q(pkt->duration, in_time_base, out_time_base);
pkt->pos = -1;
pkt->flags |= AV_PKT_FLAG_KEY;
pkt->stream_index = 0;
// 写入一帧数据到输出文件
av_interleaved_write_frame(outFormatContext, pkt);
}
// 重置 AVPacket
av_packet_unref(pkt);
}
循环读取输入文件帧数据,处理视频帧的时间戳和时长,进行时间基转换,最后写入输出文件。
5. 清理资源
cpp
// 写入输出文件尾信息
av_write_trailer(outFormatContext);
// 关闭输出文件 I/O 流
avio_close(outFormatContext->pb);
// 释放输出格式上下文
av_free(outFormatContext);
// 关闭输入文件上下文
avformat_close_input(&inFormatContext);
// 释放输入格式上下文
av_free(inFormatContext);
写入文件尾信息,关闭输入输出文件上下文并释放资源。
总结
通过上述步骤,实现了 H.264 到 MP4 的转码。使用 FFmpeg 时,要注意资源分配与释放,以及时间戳和时长的转换,同时完善错误处理,避免程序崩溃。此代码可作为日后复习和应用的参考。