FFmpeg Muxing(封装)

ffmpeg学习十一:封装音视频到同一个文件(muxing.c源码分析) 这一节学习怎么把音频流和视频按一定的格式封装成一个文件。ffmpeg所给的例子muxing.c很好的演示封装的过程,因此,这一节主要是学习muxing.c这个文件。 这个文件的路径为:doc/examples/muxing.c 首先感受下,运行结果如下: 直接执行./muxing xxx.xxx即可 这里插讲以下使用ffmpeg生成gif的命令: 当我们执行muxing可执行文件的时候 阅读详情

首发地址,会更错

本文主要参考雷神的最简单的基于FFmpeg的封装格式处理:视音频复用器(muxer) 与官方例子doc/examples/muxing.c 。

FFmpeg解封装流程

其中,AVFormatContext、AVPacket等重要的结构体请看:FFmpeg重要结构体(转自雷神) 。

以上步骤主要方法的简单说明。

(1)avformat_alloc_output_context2

构造输出的AVFormatContext。

(2)avformat_new_stream

将新的流添加到AVFormatContext中。

(3)avformat_write_header

写入文件头

(4)av_interleaved_write_frame

通过解封装文件(或者创建)得到的AVPacket数据写入到文件中。

(5)av_write_trailer

写入文件尾

代码实现

/**
 * @author 秦城季
 * @email xhunmon@126.com
 * @Blog https://qincji.gitee.io
 * @date 2021/01/04
 * description: FFmpeg 封装  <br>
 */

#include <stdio.h>

#define __STDC_CONSTANT_MACROS

#ifdef _WIN32
//Windows
extern "C"
{
#include "libavformat/avformat.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavformat/avformat.h>
#ifdef __cplusplus
};
#endif
#endif

/*
FIX: H.264 in some container format (FLV, MP4, MKV etc.) need 
"h264_mp4toannexb" bitstream filter (BSF)
  *Add SPS,PPS in front of IDR frame
  *Add start code ("0,0,0,1") in front of NALU
H.264 in some container (MPEG2TS) don't need this BSF.
*/
//'1': Use H.264 Bitstream Filter 
#define USE_H264BSF 0

/*
FIX:AAC in some container format (FLV, MP4, MKV etc.) need 
"aac_adtstoasc" bitstream filter (BSF)
*/
//'1': Use AAC Bitstream Filter 
#define USE_AACBSF 0

int main(int argc, char *argv[]) {
    AVOutputFormat *ofmt = NULL;
    //Input AVFormatContext and Output AVFormatContext
    AVFormatContext *ifmt_ctx_v = NULL, *ifmt_ctx_a = NULL, *ofmt_ctx = NULL;
    AVPacket pkt;
    int ret, i;
    int videoindex_v = -1, videoindex_out = -1;
    int audioindex_a = -1, audioindex_out = -1;
    int frame_index = 0;
    int64_t cur_pts_v = 0, cur_pts_a = 0;
    int writing_v = 1, writing_a = 1;

    const char *in_filename_v = "source/kobe.h264";
    const char *in_filename_a = "source/kobe.aac";

    const char *out_filename = "output/kobe.flv";//Output file URL
    remove(out_filename);
    //Input
    if ((ret = avformat_open_input(&ifmt_ctx_v, in_filename_v, 0, 0)) < 0) {
        printf("Could not open input file.");
        goto end;
    }
    if ((ret = avformat_find_stream_info(ifmt_ctx_v, 0)) < 0) {
        printf("Failed to retrieve input stream information");
        goto end;
    }

    if ((ret = avformat_open_input(&ifmt_ctx_a, in_filename_a, 0, 0)) < 0) {
        printf("Could not open input file.");
        goto end;
    }
    if ((ret = avformat_find_stream_info(ifmt_ctx_a, 0)) < 0) {
        printf("Failed to retrieve input stream information");
        goto end;
    }
    //Output
    avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
    if (!ofmt_ctx) {
        printf("Could not create output context\n");
        ret = AVERROR_UNKNOWN;
        goto end;
    }
    ofmt = ofmt_ctx->oformat;

    for (i = 0; i < ifmt_ctx_v->nb_streams; i++) {
        //Create output AVStream according to input AVStream
        if (ifmt_ctx_v->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            AVStream *out_stream = avformat_new_stream(ofmt_ctx, ifmt_ctx_v->streams[i]->codec->codec);
            videoindex_v = i;
            if (!out_stream) {
                printf("Failed allocating output stream\n");
                ret = AVERROR_UNKNOWN;
                goto end;
            }
            videoindex_out = out_stream->index;

            //Copy the settings of AVCodecContext
            if (avcodec_copy_context(out_stream->codec, ifmt_ctx_v->streams[i]->codec) < 0) {
                printf("Failed to copy context from input to output stream codec context\n");
                goto end;
            }
            out_stream->codec->codec_tag = 0;
            if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
                out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
            break;
        }
    }

    for (i = 0; i < ifmt_ctx_a->nb_streams; i++) {
        //Create output AVStream according to input AVStream
        if (ifmt_ctx_a->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
            AVStream *out_stream = avformat_new_stream(ofmt_ctx, ifmt_ctx_a->streams[i]->codec->codec);
            audioindex_a = i;
            if (!out_stream) {
                printf("Failed allocating output stream\n");
                ret = AVERROR_UNKNOWN;
                goto end;
            }
            audioindex_out = out_stream->index;

            //Copy the settings of AVCodecContext
            if (avcodec_copy_context(out_stream->codec, ifmt_ctx_a->streams[i]->codec) < 0) {
                printf("Failed to copy context from input to output stream codec context\n");
                goto end;
            }
            out_stream->codec->codec_tag = 0;
            if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
                out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
            break;
        }
    }
    /* open the output file, if needed */
    if (!(ofmt->flags & AVFMT_NOFILE)) {
        if (avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE)) {
            fprintf(stderr, "Could not open '%s': %s\n", out_filename,
                    av_err2str(ret));
            goto end;
        }
    }

    //Write file header
    if (avformat_write_header(ofmt_ctx, NULL) < 0) {
        fprintf(stderr, "Error occurred when opening output file: %s\n",
                av_err2str(ret));
        goto end;
    }

    while (writing_v || writing_a) {
        AVFormatContext *ifmt_ctx;
        int stream_index = 0;
        AVStream *in_stream, *out_stream;
        if (writing_v && (!writing_a || av_compare_ts(cur_pts_v, ifmt_ctx_v->streams[videoindex_v]->time_base,
                                                      cur_pts_a, ifmt_ctx_a->streams[audioindex_a]->time_base) <= 0)) {
            ifmt_ctx = ifmt_ctx_v;
            stream_index = videoindex_out;
            if (av_read_frame(ifmt_ctx, &pkt) >= 0) {
                do {
                    in_stream = ifmt_ctx->streams[pkt.stream_index];
                    out_stream = ofmt_ctx->streams[stream_index];

                    if (pkt.stream_index == videoindex_v) {
                        //FIX:No PTS (Example: Raw H.264)
                        //Simple Write PTS
                        if (pkt.pts == AV_NOPTS_VALUE) {
                            //Write PTS
                            AVRational time_base1 = in_stream->time_base;
                            //Duration between 2 frames (us)
                            int64_t calc_duration = (double) AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
                            //Parameters
                            pkt.pts = (double) (frame_index * calc_duration) /
                                      (double) (av_q2d(time_base1) * AV_TIME_BASE);
                            pkt.dts = pkt.pts;
                            pkt.duration = (double) calc_duration / (double) (av_q2d(time_base1) * AV_TIME_BASE);
                            frame_index++;
                        }

                        cur_pts_v = pkt.pts;
                        break;
                    }
                } while (av_read_frame(ifmt_ctx, &pkt) >= 0);
            } else {
                writing_v = 0;
                continue;
            }
        } else {
            ifmt_ctx = ifmt_ctx_a;
            stream_index = audioindex_out;
            if (av_read_frame(ifmt_ctx, &pkt) >= 0) {
                do {
                    in_stream = ifmt_ctx->streams[pkt.stream_index];
                    out_stream = ofmt_ctx->streams[stream_index];

                    if (pkt.stream_index == audioindex_a) {

                        //FIX:No PTS
                        //Simple Write PTS
                        if (pkt.pts == AV_NOPTS_VALUE) {
                            //Write PTS
                            AVRational time_base1 = in_stream->time_base;
                            //Duration between 2 frames (us)
                            int64_t calc_duration = (double) AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
                            //Parameters
                            pkt.pts = (double) (frame_index * calc_duration) /
                                      (double) (av_q2d(time_base1) * AV_TIME_BASE);
                            pkt.dts = pkt.pts;
                            pkt.duration = (double) calc_duration / (double) (av_q2d(time_base1) * AV_TIME_BASE);
                            frame_index++;
                        }
                        cur_pts_a = pkt.pts;
                        break;
                    }
                } while (av_read_frame(ifmt_ctx, &pkt) >= 0);
            } else {
                writing_a = 0;
                continue;
            }
        }

        //Convert PTS/DTS
        pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base,
                                   (AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
        pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base,
                                   (AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
        pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
        pkt.pos = -1;
        pkt.stream_index = stream_index;

        printf("Write 1 Packet. size:%5d\tpts:%lld\n", pkt.size, pkt.pts);
        //Write
        if (av_interleaved_write_frame(ofmt_ctx, &pkt) < 0) {
            printf("Error muxing packet\n");
            break;
        }
        av_free_packet(&pkt);
    }

    printf("Write file trailer.\n");
    //Write file trailer
    av_write_trailer(ofmt_ctx);

    end:
    avformat_close_input(&ifmt_ctx_v);
    avformat_close_input(&ifmt_ctx_a);
    /* close output */
    if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
        avio_close(ofmt_ctx->pb);
    avformat_free_context(ofmt_ctx);
    if (ret < 0 && ret != AVERROR_EOF) {
        printf("Error occurred.\n");
        return -1;
    }
    return 0;
}

测试文件下载地址: Kobe.aac 、 Kobe.h264 。

参考

  • https://blog.youkuaiyun.com/leixiaohua1020/article/details/39802913


深入剖析FFmpeg封装队列溢出:从“Too many packets buffered”到max_muxing_queue_size调优 本文深入剖析了FFmpeg封装队列溢出问题,从常见的“Too many packets buffered”错误出发,详细解析了max_muxing_queue_size参数的调优方法。通过实际案例和性能测试,提供了系统化的解决方案,帮助开发者平衡内存占用与处理稳定性,有效应对低帧率视频、时间戳异常等复杂场景。 阅读详情

相关推荐

FFmpeg示例之muxing.c

最近在看muxing的过程,就顺便调试了下FFmpeg的示例muxing.c说明 路径: doc/examples/muxing.c 使用方法: $muxing output.mp4 即传入输出文件名,会根据文件扩展名,选择合适的编码器。 输出信息: 10s视频: Stream #0:0: Video: h264, yuv420p, 352x288, 400 kb/s, 25 tbn

yue huang的视频编解码专栏 2711

ffmpeg 解复用

#include #include #include #include int main(int argc ,char  *argv[]) { //注册所有类型 av_register_all(); // if(argc>=3&&argc { printf("please  input  video file !!! \n"); return  -1;

fengfeifengfei的专栏 1041

别再傻傻分不清了!用Python的PyAV库5分钟搞懂视频封装(Muxing)与解封装(Demuxing)

本文通过Python的PyAV库详细讲解了视频封装(Muxing)与解封装(Demuxing)的实战操作,帮助开发者快速整合或提取音视频及字幕文件。文章包含环境配置、代码示例及常见问题解决方案,适合需要处理多媒体文件的开发者学习。

weixin_30509393的博客 301

ffmpeg-muxing原理分析

ffmpeg-muxing原理分析 前言: 源码文件所在路径:/doc/example/muxing.c muxing产生一个人工合成的音频流和视频流,编码后合成为一个输出文件。输出文件格式由文件后缀确定。(flv,avi,mp4,ts等格式) 例子使用方法: ./muxing 1.avi //会产生一个带音视频同步的视频 1、简介 muxing.c实现的功能就是凭空造出一个视频文件,完全是无...

qinyi_style的博客 2373

别再傻傻分不清了!用FFmpeg和PyAV搞定视频封装与解封装(附Python代码实战)

本文详细解析了视频封装(Muxing)与解封装(Demuxing)的核心概念,对比了FFmpeg命令行与PyAV库的实战应用。通过Python代码示例和FFmpeg命令,帮助开发者高效处理视频、音频和字幕流,适用于媒体文件合并、提取等场景,提升视频处理效率。

weixin_30443075的博客 329

【FFmpeg编程进阶】(19)muxing.c 示例,封装音视频代码流程学习

【FFmpeg编程进阶】(19)muxing.c 示例,封装音视频代码流程学习1. 运行结果2. 重写后的muxing.cpp 代码(带注释) ffmpeg 源代码中提供了一个muxing.c ,其中演示了如何 encode 和 muxing 音视频的流程, 为方便学习,我把它的代码使用 VS2019 工程重新写了下。 1. 运行结果 编译运行 VS2019 工程后,生成 video/video.mp4 文件,播放命令为 ffplay video/video.mp4 , 其中的视频流和音频流是muxing.

|~~~热爱生活、努力学习的小伙汁~~~| 1292

FFmpeg —— 10.示例程序(四):音视频分离(分离为AAC、H264格式)

参考:https://blog.youkuaiyun.com/leixiaohua1020/article/details/39802819 流程图 程序源码 /* * * 本程序可以将封装格式中的视频码流数据和音频码流数据分离出来 * */ #include <stdio.h> #define __STDC_CONSTANT_MACROS extern "C" { ...

天空的博客 1万+

ffmpeg muxing.c demo 流程图和源代码

/* * Copyright (c) 2003 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including..

无极生太极 438

ffmpeg4.2.2 封装(muxing)文件

#include<libavformat/avformat.h> int main(int argc,char* argv[]) { AVFormatContext *inFmtCtxVideo = NULL,*inFmtCtxAudio = NULL,*outFmtCtx = NULL; int ret = 0,i = 0,frameIndex = 0; int inputVideoIndex = -1,outputVideoIndex = -1; i...

想挣五斗米的博客 1817

生物信息学工具链搭建:用conda一键搞定MCScanX所有依赖(Ubuntu20.04实测)

本文详细介绍了在Ubuntu20.04系统上使用conda一键部署MCScanX及其所有依赖的高效方法,解决了传统源码编译安装中的依赖冲突问题。通过conda环境管理工具,研究者可以快速搭建生物信息学工具链,实现基因组共线性分析的高效运行,显著提升研究效率。

backprop5master的博客 247

【架构设计】DDD 到底解决了什么问题

DDD作为架构设计思想帮助微服务控制规模复杂度,那它是怎么做到的呢?第一章提出了架构的根本目是解决系统复杂度,并简要说明系统复杂度的六个来源及通用解法,为我们设计架构提供了清晰可执行的操作思路。

DreamSun的博客 1160

ffmpeg mux时间戳介绍

概述 ffmpeg提供了很多官方demo,路径:ffmpeg-4.1.3/doc/examples。编译方法:make examples。本文讲述muxing.c这个示例,重点解析时间戳的生成。 使用命令:muxing test.mp4,自动填充video和audio数据,并在当前路径下生成test.mp4文件。 前提知识 AVStream中的time_base 以秒为单位,表示封装格式的采样率...

lyy901135的博客 1078

基于人脸识别的智能门禁系统设计

在当前的技术背景下,本文精心打造了一款前沿的视频识别门禁控制系统。在进行调试的时候使用的软件是Keil,编写完代码,生成文件后用下载器下载到单片机上,就能够进行程序的调试了,本次设计实现了预先设定的目标,达到了预期的效果。本次设计的人脸识别的门禁控制系统其硬件部分是以STM32F103C8T6为核心的单片机,采用0V2640摄像头对人员的人脸识别,采用矩阵按键对系统的操作以及密码的输入,使用蜂鸣器来作为报警模块,开门装置是电子锁控制,显示设备采用OLED液晶显示,无线模块在一番思索后选择了蓝牙模块传输。

2401_86147581的博客 1296

FFmpeg实战指南:从H264裸流到MP4封装的全流程解析

本文详细解析了使用FFmpeg将H264裸流封装为MP4文件的全流程。从核心概念辨析到命令行一键操作,再到深入底层的C代码实现,重点解决了时间戳转换、元数据优化等关键问题,并提供了实战避坑指南,帮助开发者高效完成视频封装,确保视频在各种播放器中的兼容性。

www00的博客 684

从Protocol到硬件控制:揭秘高通UEFI中ABL与XBL的协作机制

本文深入解析了高通UEFI架构中ABL与XBL的协作机制,重点探讨了Protocol通信在硬件控制中的关键作用。通过对比传统GPIO控制方式,揭示了Protocol架构在安全性、可维护性和灵活性方面的优势,并提供了关机充电场景的实战案例分析及调试技巧。

weixin_29185199的博客 430

Xilinx ISE系列教程(2):LED点灯工程、仿真、bit下载和mcs固化

bit流生成配置选项很多,支持生成bit/bin/ascii格式的bin文件,是否压缩,配置速度,配置管脚的上下拉,用户ID,数据加载速度,SPI总线宽度,是否支持Readback,程序加密等等。,在之后的文章,我们会以Xilinx Spartan-6系列FPGA XC6SLX16为例,不涉及FPGA开发知识,仅仅是工具的使用,介绍Xilinx ISE开发环境的使用教程和使用技巧。bit文件下载之后,可以看到LED按照我们设计的1s周期闪烁起来了,但是此时如果断电,重新上电程序就丢失了。...

whik1194的博客 2278

muxing.c

doc/examples/muxing.c /* * Copyright (c) 2003 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentat

闲云野鹤专栏 866

笔试题-2023-乐鑫-数字IC设计【纯净题目版】

笔试题-2023-乐鑫-数字IC设计【纯净题目版】

w0shishabi的博客 1777

FFmpeg实战指南:将H.264视频流高效封装为MP4格式

本文详细介绍了如何使用FFmpeg将H.264视频流高效封装为MP4格式。通过对比封装与转码的区别,解析时间基等核心概念,并提供完整的C语言代码示例,指导开发者从零实现封装流程。文章重点解决了时间戳换算、播放兼容性等常见问题,旨在帮助用户无损、快速地将原始H.264流转换为广泛兼容的MP4文件。

f6g7h8i9j的博客 659

Codex 接入国产大模型指南:客户端与 CLI 双端实战

CC Switch是目前最流行的 Codex / Claude Code 模型切换工具,内置了协议转换功能,支持几乎所有主流国产模型。核心原理Codex → 本地 8317 端口(CC Switch)→ 协议转换 → 国产模型 API整个过程对 Codex 完全透明,Codex 以为自己在跟标准的 Responses API 对话。用户类型推荐方案理由新手 / 不想折腾配置简单,免费额度够用追求稳定体验通义千问(原生接入)官方兼容,功能最完整企业用户自建 AI 网关可控性强,支持多用户管理预算有限。

篮球界最会写bug的人;程序猿中打球最菜的人。 573

通过Power Platform自定义D365 CE 业务需求 - 4. 使用Power Automate

Power Automate构建块Power Automate中的连接器流的类型和用途流中的动态值和表达式使用变量、循环和条件在Power Automate中处理审批业务场景、用例和实现Power Virtual Agent的概念Power Virtual Agent的构建块配置Power Virtual Agent示例在公共网站/门户中部署Power Virtual Agent业务场景、用例和实现。

Martin-Mei的博客 558

别再傻傻分不清了!用FFmpeg命令行5分钟搞定视频封装与解封装

本文详细介绍了如何使用FFmpeg命令行快速掌握视频封装与解封装的核心技巧。通过muxer和demuxer的实战操作,读者可以轻松合并视频、音频和字幕,或从视频中提取特定内容,大幅提升多媒体处理效率。文章还提供了高级封装技巧和疑难问题排查方法,适合各类用户快速上手。

weixin_30876945的博客 410

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

FFmpeg 内存H264+PCM发布RTMP

背景 因为项目需要,得从外部获取视频264和音频PCM或者g711编解码数据,然后发布成rtmp出来。目前,网上似乎找不到这样的文章,很多发布RTMP都是用从音视频文件读取后再发布出来,因此记录分享,若有不对的地方,欢迎批评指出。 思路 做这个项目,大体思路是参考FFmpeg的muxing.c。muxing.c主要做的就是输出一个音视频格式,其中它的音频和视频数据都是通过算法生成原始的数据(YUV...

RzzZ的博客 2390

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

FFmpeg的那些坑-Too many packets buffered for output stream

原因 原因是有些视频数据有问题,导致视频处理过快,容器封装时队列溢出。 解决办法 增大容器封装队列大小,比如 -max_muxing_queue_size 1024 1 ffmpeg -i test.mp4 -i watermark.png -max_muxing_queue_size 1024 -acodec copy -preset veryfast -filter_complex "ov...

az44yao的专栏 2620
上一篇: FFmpeg Demuxing(解封装)
下一篇: FFmpeg Remuxing(重新封装)
秦城季
博客等级 码龄10年 46粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值