使用FFmpeg将H.264码流封装为MP4

一、调用流程

初始化FFmpeg库 创建输入/输出上下文 配置视频流参数 写入文件头 循环读取H.264数据包 时间戳处理与封装 资源释放


二、关键步骤详解

1. 初始化FFmpeg库
c 复制代码
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>

avformat_network_init();  // 若需网络功能(可选)
av_register_all();       // 旧版本需注册,新版本可省略
2. 创建输入/输出上下文
c 复制代码
// 打开H264裸流输入
AVFormatContext *in_fmt_ctx = NULL;
if (avformat_open_input(&in_fmt_ctx, "input.h264", NULL, NULL) != 0) {
    fprintf(stderr, "无法打开输入文件\n");
    return -1;
}
avformat_find_stream_info(in_fmt_ctx, NULL);  // 获取流信息

// 创建MP4输出上下文
AVFormatContext *out_fmt_ctx = NULL;
avformat_alloc_output_context2(&out_fmt_ctx, NULL, NULL, "output.mp4");
if (!out_fmt_ctx) {
    fprintf(stderr, "无法创建输出文件\n");
    return -1;
}

// 打开输出文件IO
if (!(out_fmt_ctx->oformat->flags & AVFMT_NOFILE)) {
    if (avio_open(&out_fmt_ctx->pb, "output.mp4", AVIO_FLAG_WRITE) < 0) {
        fprintf(stderr, "无法打开输出IO\n");
        return -1;
    }
}
3. 配置视频流参数
c 复制代码
// 从输入流复制编解码参数到输出流
AVStream *in_stream = in_fmt_ctx->streams[0];
AVStream *out_stream = avformat_new_stream(out_fmt_ctx, NULL);
avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);

// 设置时间基(关键!)
out_stream->time_base = (AVRational){1, 30};  // 假设帧率30fps
4. 写入文件头
c 复制代码
if (avformat_write_header(out_fmt_ctx, NULL) < 0) {
    fprintf(stderr, "写入文件头失败\n");
    return -1;
}
5. 数据包处理与封装
c 复制代码
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;

while (av_read_frame(in_fmt_ctx, &pkt) >= 0) {
    // 时间戳重计算(防止音画不同步)
    if (pkt.pts != AV_NOPTS_VALUE)
        pkt.pts = av_rescale_q(pkt.pts, in_stream->time_base, out_stream->time_base);
    if (pkt.dts != AV_NOPTS_VALUE)
        pkt.dts = av_rescale_q(pkt.dts, in_stream->time_base, out_stream->time_base);

    pkt.stream_index = out_stream->index;  // 更新流索引
    av_interleaved_write_frame(out_fmt_ctx, &pkt);  // 写入封装文件
    av_packet_unref(&pkt);
}
6. 收尾处理
c 复制代码
av_write_trailer(out_fmt_ctx);  // 写入文件尾

// 释放资源
avformat_close_input(&in_fmt_ctx);
if (out_fmt_ctx && !(out_fmt_ctx->oformat->flags & AVFMT_NOFILE))
    avio_closep(&out_fmt_ctx->pb);
avformat_free_context(out_fmt_ctx);

三、注意事项

  1. 时间戳同步

    • 必须通过av_rescale_q重计算时间戳,否则会导致播放速度异常或音画不同步。
    • 若输入流无时间戳,需手动生成递增的PTS/DTS。
  2. 编解码参数兼容性

    • MP4封装要求H.264流包含SPS/PPS信息(通常位于extradata中),若裸流缺失需手动插入。
  3. 封装失败 :检查输入是否为标准H.264 Annex B格式(起始码0x00000001),否则需通过h264_mp4toannexb过滤器转换。

  4. 性能优化

    • 使用av_interleaved_write_frame而非av_write_frame,确保数据包交错写入(避免音视频交错问题)。

    • 启用faststart标志可将MOOV原子移至文件头,便于网络播放:

      c 复制代码
      AVDictionary *options = NULL;
      av_dict_set(&options, "movflags", "faststart", 0);
      avformat_write_header(out_fmt_ctx, &options);
相关推荐
xcLeigh4 小时前
HTML5实现好看的视频播放器(三种风格,附源码)
前端·音视频·html5
别动哪条鱼5 小时前
SDL 函数对各对象缓冲区的影响
网络·数据结构·ffmpeg
lusasky5 小时前
H.264 (AVC) 与 H.265 (HEVC) 全方位对标
h.265·h.264
骄傲的心别枯萎7 小时前
RV1126 NO.57:ROCKX+RV1126人脸识别推流项目之读取人脸图片并把特征值保存到sqlite3数据库
数据库·opencv·计算机视觉·sqlite·音视频·rv1126
好游科技8 小时前
IM即时通讯系统:安全可控、功能全面的社交解决方案全解析
安全·音视频·webrtc·im即时通讯·私有化部署im即时通讯·社交app
EasyDSS8 小时前
视频直播点播平台EasyDSS构建高并发、低延迟的远程教学直播新模式
音视频
GIOTTO情8 小时前
多模态舆情监测技术深度解析:Infoseek 如何实现 AI 造假与短视频舆情的精准捕捉?
人工智能·音视频
音视频牛哥8 小时前
C# 开发工业级 RTSP/RTMP 播放器实战:基于 SmartMediakit 的低延迟与高可靠性设计
音视频·rtsp播放器·rtmp播放器·windows rtsp播放器·windows rtmp播放器·c# rtsp播放器·c# rtmp播放器
JellyDDD9 小时前
【悬赏】Android WebRTC 数字人项目回声问题排查(AEC / AudioMode)
音视频·webrtc
于是我说9 小时前
如何判断一个视频到底是真实 MP4 直链,还是流媒体M3U8
网络·音视频