You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用FFmpeg libavformat API封装已编码x264帧为MP4容器

解决思路:跳过编码步骤,直接封装已编码的H264帧

你现在走了个不必要的弯路——因为已经用x264完成了帧编码,完全不需要再初始化FFmpeg的H264编码器。我们只需要把已编码帧的元数据告诉libavformat,然后把x264输出的NALU(网络抽象层单元)直接封装到MP4容器里就行。下面是具体的修正方案:

核心步骤拆解

  1. 初始化输出上下文和流(和你之前的逻辑类似,但跳过编码器初始化)
  2. 配置AVStream的CodecParameters:这是解决你所有错误的关键,必须同步x264编码的核心参数
  3. 打开输出文件并写入文件头
  4. 将x264的NALU封装为FFmpeg的AVPacket,写入容器
  5. 写入文件尾并清理资源

修正后的代码示例

1. 初始化输出上下文和流

AVFormatContext* mAVFormatContext = NULL;
int ret = avformat_alloc_output_context2(&mAVFormatContext, NULL, NULL, "gen_vid.mp4");
if (ret < 0) {
    fprintf(stderr, "Failed to create output context\n");
    return ret;
}

AVStream* mAVStream = avformat_new_stream(mAVFormatContext, NULL);
if (!mAVStream) {
    fprintf(stderr, "Failed to allocate output stream\n");
    return AVERROR(ENOMEM);
}

2. 配置CodecParameters(重中之重)

你需要从x264编码器的参数中获取这些值,或者手动填入你编码时设置的参数:

AVCodecParameters* codecpar = mAVStream->codecpar;

// 必须设置的核心参数
codecpar->codec_id = AV_CODEC_ID_H264;
codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
codecpar->width = width; // 和x264编码时一致的视频宽度
codecpar->height = height; // 和x264编码时一致的视频高度
codecpar->format = AV_PIX_FMT_YUV420P; // x264默认输出的像素格式,根据你的实际配置调整

// 设置时间基:和x264编码时的时间基保持一致
mAVStream->time_base = (AVRational){1, 30}; // 假设你的帧率是30fps
codecpar->time_base = mAVStream->time_base;

// 导入x264的SPS/PPS作为extradata(MP4容器必须依赖这个才能解码)
x264_param_t* x264_params = x264_encoder_parameters(h); // h是你的x264编码器句柄
uint8_t* extradata = NULL;
int extradata_size = x264_encoder_headers(h, &extradata, NULL);
if (extradata_size > 0) {
    codecpar->extradata = av_mallocz(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
    memcpy(codecpar->extradata, extradata, extradata_size);
    codecpar->extradata_size = extradata_size;
    x264_free(extradata); // 释放x264分配的内存
}

3. 打开文件并写入头

if (!(mAVFormatContext->oformat->flags & AVFMT_NOFILE)) {
    ret = avio_open(&mAVFormatContext->pb, "gen_vid.mp4", AVIO_FLAG_WRITE);
    if (ret < 0) {
        fprintf(stderr, "Could not open output file\n");
        return ret;
    }
}

// 写入文件头
ret = avformat_write_header(mAVFormatContext, NULL);
if (ret < 0) {
    fprintf(stderr, "Failed to write header: %s\n", av_err2str(ret));
    return ret;
}

4. 处理x264的已编码帧(替换你原来的fwrite逻辑)

现在需要把x264输出的NALU封装成FFmpeg的AVPacket,再写入容器:

int delayed_frame_counter = 0;
x264_picture_t pic_out;
x264_nal_t* nal;
int i_nal;

while (x264_encoder_delayed_frames(h)) {
    printf("Writing delayed frame %u\n", delayed_frame_counter++);
    int i_frame_size = x264_encoder_encode(h, &nal, &i_nal, NULL, &pic_out);
    if (i_frame_size < 0) {
        fprintf(stderr, "Failed to encode delayed frame\n");
        return i_frame_size;
    } else if (i_frame_size > 0) {
        // 遍历所有NALU单元
        for (int i = 0; i < i_nal; i++) {
            AVPacket pkt = {0};
            av_init_packet(&pkt);

            // 设置数据包内容
            pkt.data = nal[i].p_payload;
            pkt.size = nal[i].i_payload;
            pkt.stream_index = mAVStream->index;

            // 转换时间戳:从x264的时间基转换为FFmpeg容器的时间基
            pkt.pts = av_rescale_q(pic_out.i_pts, mAVStream->time_base, mAVFormatContext->streams[0]->time_base);
            pkt.dts = pkt.pts; // 如果没有B帧,dts和pts一致;有B帧的话需要从x264获取对应dts
            pkt.duration = av_rescale_q(1, mAVStream->time_base, mAVFormatContext->streams[0]->time_base); // 单帧时长

            // 写入数据包
            ret = av_interleaved_write_frame(mAVFormatContext, &pkt);
            if (ret < 0) {
                fprintf(stderr, "Failed to write frame: %s\n", av_err2str(ret));
                return ret;
            }
            av_packet_unref(&pkt);
        }
    }
}

5. 写入文件尾并清理资源

// 写入文件尾
av_write_trailer(mAVFormatContext);

// 释放资源
if (!(mAVFormatContext->oformat->flags & AVFMT_NOFILE)) {
    avio_close(mAVFormatContext->pb);
}
avformat_free_context(mAVFormatContext);

对你之前错误的解释

  1. "Could not find a valid device"错误:你调用了avcodec_open2,FFmpeg默认选择了v4l2m2m硬件编码器,但你的环境没有对应设备——这完全没必要,因为你不需要重新编码
  2. "dimensions not set"错误:你没有给codecpar设置width和height,容器不知道视频的分辨率
  3. "Could not find tag for codec none"错误:codecpar的codec_id默认是AV_CODEC_ID_NONE,必须手动设置为AV_CODEC_ID_H264

内容的提问来源于stack exchange,提问作者PJD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:03:01