使用FFMPEG库封装264视频和acc音频数据到MP4文件中

这篇具有很好参考价值的文章主要介绍了使用FFMPEG库封装264视频和acc音频数据到MP4文件中。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

准备

ffmepeg 4.4

一段H264的视频文件

一段acc格式的音频文件

封装流程

1.使用avformat_open_input分别打开视频和音频文件,初始化其AVFormatContext,使用avformat_find_stream_info获取编码器基本信息

2.使用avformat_alloc_output_context2初始化输出的AVFormatContext结构

3.使用函数avformat_new_stream给输出的AVFormatContext结构创建音频和视频流,使用avcodec_parameters_copy方法将音视频的编码参数拷贝到新创建的对应的流的codecpar结构中

4.使用avio_open打开输出文件,初始化输出AVFormatContext结构中的IO上下文结构

5.使用avformat_write_header写入流的头信息到输出文件中

6.根据时间戳同步原则交错写入音视频数据,并对时间戳信息进行设置和校准

7.写入流预告信息到输出文件中(moov)

8.释放空间,关闭文件

使用FFMPEG库封装264视频和acc音频数据到MP4文件中

 

源码



#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



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 = "D:/测试工程/sound/ffmpeg_demo.h264";
    const char* in_filename_a = "D:/测试工程/sound/ffmpeg_demo.aac";

    const char* out_filename = "D:/测试工程/sound/muxing.mp4";//Output file URL


    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]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {

            AVStream* out_stream = avformat_new_stream(ofmt_ctx, nullptr);
            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_parameters_copy(out_stream->codecpar, ifmt_ctx_v->streams[i]->codecpar) < 0) {
                printf("Failed to copy context from input to output stream codec context\n");
                goto end;
            }


            break;
        }
    }

    for (i = 0; i < ifmt_ctx_a->nb_streams; i++) {
        //Create output AVStream according to input AVStream
        if (ifmt_ctx_a->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {

            AVStream* out_stream = avformat_new_stream(ofmt_ctx, nullptr);
            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_parameters_copy(out_stream->codecpar, ifmt_ctx_a->streams[i]->codecpar) < 0) {
                printf("Failed to copy context from input to output stream codec context\n");
                goto end;
            }
            out_stream->codecpar->codec_tag = 0;
            if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
                ofmt_ctx->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': %d\n", out_filename,
                ret);
            goto end;
        }
    }

    //Write file header
    if (avformat_write_header(ofmt_ctx, NULL) < 0) {
        fprintf(stderr, "Error occurred when opening output file: %d\n",
            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++;
                            printf("frame_index:  %d\n ", 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_packet_unref(&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;
}

小结

这里需要几个概念简单说明下:

tbr  表示每秒帧数

tbn 表示数据流的实际真实帧率的倒数

如:使用FFMPEG库封装264视频和acc音频数据到MP4文件中文章来源地址https://www.toymoban.com/news/detail-500533.html

到了这里,关于使用FFMPEG库封装264视频和acc音频数据到MP4文件中的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 20231005使用ffmpeg旋转MP4视频

    20231005使用ffmpeg旋转MP4视频 2023/10/5 12:21 百度搜搜:ffmpeg 旋转90度 https://zhuanlan.zhihu.com/p/637790915 【FFmpeg实战】FFMPEG常用命令行 https://blog.csdn.net/weixin_37515325/article/details/127817057 FFMPEG常用命令行 5.视频旋转 顺时针旋转90度:ffmpeg -i test.mp4 -vf \\\"transpose=1\\\" out.mp4//顺时针旋转90° 逆时针

    2024年02月07日
    浏览(31)
  • FFmpeg从入门到入魔(3):提取MP4中的H.264和AAC

        最近在开发中遇到了一个问题,即无法提取到MP4中H264流的关键帧进行处理,且保存到本地的AAC音频也无法正常播放。经过调试分析发现,这是由于解封装MP4得到的H264和AAC是ES流,它们缺失解码时必要的 起始码 / SPS / PPS 和 adts头 。 1. MP4格式解析 1.1 MP4简介  MP4封装格式是

    2023年04月16日
    浏览(33)
  • 使用ffmpeg将多个TS视频拼接成mp4视频

    点击下面网址下载对应版本安装 https://ffmpeg.org/download.html   下载好之后添加环境变量 添加成功之后在cmd窗口输入ffmpeg,显示如下结果则为成功  合并单个文件或者少量文件时,通过以下命令合并 多个ts视频可以编辑一个txt文档,file.txt 注意:这里必须是单引号,双引号会报错 进入

    2024年02月11日
    浏览(61)
  • FFMPEG mp4封装实现

    FFMPEG mp4录像 author:lyn date:2022.09.28 version: ffmpeg4.1.3 1.mp4数据结构 2.ffmpeg mp4封装实现 3.mp4函数调用关系 4.参考资料 1.mp4数据结构 1.1mp4简介 MP4或称MPEG-4第14部分(英语:MPEG-4 Part 14)是一种标准的数字多媒体容器格式。MPEG-4第14部分的扩展名为 .mp4 ,以存储数字音频及数字视频

    2023年04月08日
    浏览(21)
  • C# 使用ffmpeg将图片保存为mp4视频

    使用 FFmpeg 这个强大的多媒体处理工具,可以轻松地将一系列图片转换为一个 MP4 视频文件。以下是一个基本的命令行示例来完成这个任务: 命令参数说明: -framerate 25 :设置输入图像序列的帧率,这里表示每秒25帧。 -i image-%03d.jpg :指定输入文件格式,这里的  %03d  是一个

    2024年04月27日
    浏览(32)
  • OpenCV 报错:FFMPEG: tag 0x34363258/‘X264‘ is not supported with codec id 27 and format ‘mp4 / MP4‘

    首先说一下报错的地方,是在使用VideoWriter保存视频时: 出现如下错误: 经过查找网上资料,发现是cv2.VideoWriter_fourcc()参数存在问题, 解决方法: 将 修改为: 即可完美解决问题。

    2024年02月07日
    浏览(49)
  • ffmpeg从MP4中取出wav音频

    要从 MP4 文件中提取出 WAV 音频,你可以使用 FFmpeg 工具。请按照以下步骤进行操作: 1. 下载 FFmpeg:首先,你需要下载 FFmpeg 工具。你可以在 FFmpeg 官方网站(https://ffmpeg.org/)上找到适用于 Windows 的预编译版本。下载后,解压缩到一个方便的位置。 2. 打开命令提示符:按下

    2024年02月03日
    浏览(36)
  • 基于FFmpeg的封装格式MP4(TS)

    每一帧音频或视频都有一个持续时间:duration: 采样频率是指将模拟声音波形进行数字化时,每秒钟抽取声波幅度样本的次数。 。正常人听觉的频率范围大约在20Hz~20kHz之间,根据奈奎斯特采样理论,为了保证声音不失真,采样频率应该在40kHz左右。常用的音频采样频率有8k

    2024年02月03日
    浏览(32)
  • 音视频知识:MPEG-4、H264、MP4、AAC之间的关系

    MPEG-4 一种编码标准。是国际标准化组织 (ISO) 主要针对消费类应用,已经针对运动图像压缩定义的标准。MPEG(Moving Picture Experts Group)标准包括 MPEG1、MPEG2与 MPEG4。 MPEG-4标准目前分为27个部分,统称为ISO/IEC14496国际标准。其中第10部分(ISO/IEC 14496-10)就是熟悉的高级视频编码

    2024年02月14日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包