准备

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.释放空间,关闭文件

源码

#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
#endifint main(int argc, char* argv[]) {AVOutputFormat* ofmt = NULL;//Input AVFormatContext and Output AVFormatContextAVFormatContext* 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 URLif ((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;}//Outputavformat_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 AVStreamif (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 AVCodecContextif (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 AVStreamif (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 AVCodecContextif (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 headerif (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 PTSif (pkt.pts == AV_NOPTS_VALUE){//Write PTSAVRational 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);//Parameterspkt.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 PTSif (pkt.pts == AV_NOPTS_VALUE){//Write PTSAVRational 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);//Parameterspkt.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/DTSpkt.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);//Writeif (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 trailerav_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文件中相关推荐

  1. vlc(window)分离mp4文件中的音视频

    20210903----追加: <vlc-提取mp4解复用模块> ============================================================= ...

  2. ffmpeg解码H.264视频数据,MFC播放视频

    ffmpeg 是一个完整的视频流解决方案,开源且有良好的跨平台性,ffmpeg具有强大的多媒体数据处理能力,能够实现视频的采集,多种视频格式间转换,给视频添加水印等多种功能,已被 VLC.Mplaye ...

  3. ffmpeg开发之旅(3):AAC编码格式分析与MP4文件封装(MediaCodec+MediaMuxer)

    ffmpeg开发之旅(3):AAC编码格式分析与MP4文件封装(MediaCodec+MediaMuxer) (原文链接:http://blog.csdn.net/andrexpert/article ...

  4. 最简单的基于FFmpeg的封装格式处理:视音频分离器(demuxer)

    ===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...

  5. 最简单的基于FFmpeg的封装格式处理:视音频复用器(muxer)

    ===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...

  6. 【Android RTMP】安卓直播推流总结 ( 直播服务器搭建 | NV21 图像采集 | H.264 视频编码 | PCM 音频采集 | AAC 音频编码 | RTMP 包封装推流 )

    文章目录 一. 安卓直播推流专栏博客总结 二. 相关资源介绍 三. GitHub 源码地址 四. 整体 Android 直播推流数据到服务器并观看直播演示过程 Android 直播推流流程 : 手机采 ...

  7. 使用FFMPEG分离mp4/flv文件中的264视频和aac音频

     准备 ffmpeg 4.4 一个MP4或flv格式的视频文件 分离流程 大致分为以下几个简单步骤: 1.使用avformat_open_input 函数打开文件并初始化结构AVFormatConte ...

  8. 使用ffmpeg从mp4文件中提取视频流到h264文件中

    注释: -i 2018.mp4:  是输入的MP4文件 -codec copy: 从mp4中拷贝 -bsf: h264_mp4toannexb: 从mp4拷贝到annexB封装 -f h264: 采用 ...

  9. php合并播放mp4文件_如何将百度的流畅版视频m3u8合并为正确的mp4文件?

    本帖最后由 autoav 于 2020-10-16 11:05 编辑 我在百度网盘保存了很多视频,很多视频本身比较大,手机看的话,只要下载流畅版就可以了,但是只能用百度网盘app看,我想合并成mp4文 ...

最新文章

  1. input子系统分析(转)
  2. docker-runc not installed on system 问题
  3. base64格式的图片上传阿里云
  4. Linux netstat查看网络连接信息
  5. 「原理」AB测试-详细过程和原理解读
  6. RT-Thread 简介及架构
  7. stm32 SysTick
  8. C/C++——打开文件存储数据的各种方式
  9. 【今日CV 计算机视觉论文速览 第127期】Fri, 7 Jun 2019
  10. 类的静态成员函数和静态成员变量的使用
  11. LG电子成功进行太赫兹频段6G无线信号传输,距离超过100米
  12. HTML 转 PDF的两种实现方式
  13. 3ds Max 中的导航控件SteeringWheels入门介绍
  14. Windows如何查看.db数据库文件
  15. ps cs6选择并遮住在哪
  16. Unity3d 给人物模型添加动画
  17. 全国大江大河实时水情数据下载
  18. maven install 提示:Process terminated
  19. 胜利大逃亡 --- bfs记录
  20. 腾讯(大连)研发一面-20190620

热门文章

  1. Win11删除EFI分区
  2. Java-数据结构:树,这份资料可帮你解决95%的问题
  3. unittest之TestSuite类详解
  4. 【转】Log4j详细使用教程
  5. android 解锁过程,Android-解锁与刷机(以一加为例)
  6. 爬取哔哩哔哩网站数据
  7. 盘点大数据商业智能的十大戒律
  8. 【干货】Redis在Java开发中的基本使用和巧妙用法
  9. python画三维(3D)图
  10. 多线程并发中什么是竞争条件?