我们知道多媒体文件是由多个stream组成,每个stream对应不同的内容。比如视频,音频,字幕。

如果要用A视频的图像,B视频的音乐,生成C视频。原理就是提取出A视频的视频流数据,B视频的的音频流数据,写入C视频的视频流和音频流中。

流程图如下

#include <stdlib.h>
#include <libavutil/log.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include <libavcodec/codec_par.h>
int make_out_file(double start_time, double end_time, char *audio_file_name, char *video_file_name, char *out_file_name);int main(int argc, char *argv[])
{//输入4个参数  argv1 开始时间  argv2 结束时间  argv3 输入文件  argv3 输出文件double start_time, end_time;char *audio_file_name, *video_file_name, *out_file_name;av_log_set_level(AV_LOG_INFO);if (argc < 6){av_log(NULL, AV_LOG_ERROR, "输入参数错误");return -1;}start_time = atoi(argv[1]);end_time = atoi(argv[2]);audio_file_name = argv[3];video_file_name = argv[4];out_file_name = argv[5];int ret = make_out_file(start_time, end_time, audio_file_name, video_file_name, out_file_name);return ret;
}AVFormatContext *open_input_file(char *file_name)
{int ret = 0;AVFormatContext *fmt_ctx = NULL;ret = avformat_open_input(&fmt_ctx, file_name, NULL, NULL);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "打开输入文件失败 %s", file_name);return fmt_ctx;}ret = avformat_find_stream_info(fmt_ctx, NULL);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "获取输入文件流信息失败 %s", file_name);return fmt_ctx;}av_dump_format(fmt_ctx, 0, file_name, 0);return fmt_ctx;
}int createStream(AVFormatContext *ofmt_ctx, AVStream *in_stream)
{AVStream *out_stream = avformat_new_stream(ofmt_ctx, NULL);int ret = 0;if (!out_stream){av_log(NULL, AV_LOG_ERROR, "创建输出流失败");return -1;}ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "copy 流参数错误");return ret;}out_stream->codecpar->codec_tag = 0;return ret;
}int write_data(AVFormatContext* in_fmt_ctx, int in_index, AVFormatContext* out_fmt_ctx, int out_index,double start_time, double end_time){AVPacket pkt;av_init_packet(&pkt);pkt.size = 0;pkt.data = NULL;int base_pts = 0;int base_dts = 0;int ret = 0;ret = av_seek_frame(in_fmt_ctx, -1, start_time * AV_TIME_BASE, AVSEEK_FLAG_ANY);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "移动的上下文到指定时间失败");return ret;}//写音频while (1){AVStream *in_stream, *out_stream;ret = av_read_frame(in_fmt_ctx, &pkt);if (ret < 0)break;if (pkt.stream_index != in_index){av_packet_unref(&pkt);continue;}in_stream = in_fmt_ctx->streams[in_index];out_stream = out_fmt_ctx->streams[out_index];//如果当前时间超过了要截取的时间,直接跳出循环if (av_q2d(in_stream->time_base) * pkt.pts > end_time){av_packet_unref(&pkt);break;}//设置输出文件的dts和pts// av_log(NULL, AV_LOG_INFO, "writefreame pkt.pts = %lld\n", pkt.pts);if (base_pts == 0 || base_dts == 0){base_dts = base_pts = pkt.pts;av_log(NULL, AV_LOG_INFO, "writefreame  base_pts = %d\n", base_pts);}av_log(NULL, AV_LOG_INFO, "writefreame  pkt.pts = %lld, dts = %lld\n", pkt.pts, pkt.dts);pkt.pts = av_rescale_q_rnd(pkt.pts - base_pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);pkt.dts = av_rescale_q_rnd(pkt.dts - base_dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);pkt.duration = (int)av_rescale_q((int64_t)pkt.duration, in_stream->time_base, out_stream->time_base);pkt.pos = -1;pkt.stream_index = out_index;av_log(NULL, AV_LOG_INFO, "writefreame 22222 pkt.pts = %lld, dts = %lld\n", pkt.pts, pkt.dts);ret = av_write_frame(out_fmt_ctx, &pkt);av_packet_unref(&pkt);if (ret < 0)break;}return ret;
}int make_out_file(double start_time,double end_time,char *audio_file_name,char *video_file_name,char *out_file_name)
{int ret = 0;AVFormatContext *i_audio_fmt_ctx = NULL, *i_video_fmt_ctx = NULL, *ofmt_ctx = NULL;//第一步获取输入上下文i_audio_fmt_ctx = open_input_file(audio_file_name);if (!i_audio_fmt_ctx){ret = -1;goto __ERROR;}i_video_fmt_ctx = open_input_file(video_file_name);if (!i_audio_fmt_ctx){ret = -1;goto __ERROR;}//第二步获取输出上下文ret = avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_file_name);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "获取输出文件上下文失败");goto __ERROR;}int video_stream_index = av_find_best_stream(i_video_fmt_ctx,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,-1);av_log(NULL, AV_LOG_ERROR, "输入文件的视频频流索引是 videoStreamIndex=%d", video_stream_index);int audio_stream_index = av_find_best_stream(i_audio_fmt_ctx,AVMEDIA_TYPE_AUDIO,-1,-1,NULL,-1);av_log(NULL, AV_LOG_ERROR, "输入文件的视频频流索引是 videoStreamIndex=%d", audio_stream_index);//第三步为输出文件创建输出流int out_video_stream_index = -1;int out_audio_stream_index = -1;ret = createStream(ofmt_ctx, i_video_fmt_ctx->streams[video_stream_index]);if(ret < 0){goto __ERROR;}out_video_stream_index = 0;ret = createStream(ofmt_ctx, i_audio_fmt_ctx->streams[audio_stream_index]);if(ret < 0){goto __ERROR;}out_audio_stream_index = 1;av_dump_format(ofmt_ctx, 0, out_file_name, 1);//第四步为输出文件创建AvIOContextif (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)){ret = avio_open(&(ofmt_ctx->pb), out_file_name, AVIO_FLAG_WRITE);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "创建输出文件IO上下文失败");goto __ERROR;}}//第五步写输出文件头ret = avformat_write_header(ofmt_ctx, NULL);if (ret < 0){av_log(NULL, AV_LOG_ERROR, "写多媒体文件头失败");goto __ERROR;}//第六步读取指定时间段的数据,然后进行时间戳转化,再写入输出文件ret = write_data(i_video_fmt_ctx, video_stream_index, ofmt_ctx, out_video_stream_index,start_time, end_time);if (ret < 0){goto __ERROR;}          ret =  write_data(i_audio_fmt_ctx, audio_stream_index, ofmt_ctx, out_audio_stream_index,start_time, end_time);if (ret < 0){goto __ERROR;}   //第七步写多媒体文件尾巴av_write_trailer(ofmt_ctx);__ERROR://第八步释放资源if (i_audio_fmt_ctx){avformat_close_input(&i_audio_fmt_ctx);avformat_free_context(i_audio_fmt_ctx);}if (i_video_fmt_ctx){avformat_close_input(&i_video_fmt_ctx);avformat_free_context(i_video_fmt_ctx);}if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE)){avio_closep(&(ofmt_ctx->pb));}if (ofmt_ctx){avformat_free_context(ofmt_ctx);}return ret;
}

坚持输出,才能不停的输入。

学习基础,才能学得更深。

学习要慢点再慢点。

学习原理,对抗碎片。

ffmpeg 为视频添加背景音乐---单音频轨道stream相关推荐

  1. java操作ffmpeg为视频添加背景音乐

    最近学习仿抖音微信小程序遇到一个坑,视频中使用以下语句为视频添加背景音乐 ffmpeg.exe -i input.mp4 -i 音乐.mp3 -t 7 -y 新视频.mp4 ,然而我怎么尝试都不行,上 ...

  2. 【ffmpeg 给视频添加背景音乐,去掉视频背景音乐原声】

    解决办法: 方法1: 先去掉视频原声,再给视频加背景音乐 去掉原视频音轨 E:\anzhuangbao\ffmpeg\bin\ffmpeg -i G:\hi.mp4 -c:v copy -an G:\ ...

  3. ffmpeg给视频添加背景音乐

    In the end, it's not the years in your life that count. It's the life in your years. 最终,重要的不是活了多少年,而 ...

  4. Android之FFmpeg(3)--添加为视频添加背景音乐

    既然开始了FFmpeg开发,那不做个Demo,怎么知道你的猜想,你的学的东西到底对不对呢?嗯,所以我们今儿个做个demo,为视频添加背景音乐! Activity的代码如下(其实就一个按钮): 加载na ...

  5. python设置背景音乐_python给视频添加背景音乐并改变音量的具体方法

    用到给视频添加背景音乐,并改变音量.记录一下,与碰到同样问题的朋友共享. import subprocess inmp4='E:/PycharmProjects/untitled2/hecheng/1 ...

  6. Golang 给视频添加背景音乐 | Golang工具

    目录 前言 环境依赖 代码 总结 前言 本文提供给视频添加背景音乐,一如既往的实用主义. 主要也是学习一下golang使用ffmpeg工具的方式. 环境依赖 ffmpeg环境安装,可以参考我的另一篇文 ...

  7. 第三章 添加背景音乐与音频剪辑

    ​第三章 添加背景音乐与音频剪辑 3.1为视频添加音乐的方法 音乐是短视频的重要组成部分之一,一段适合视频的音乐能为视频锦上添花,本节主要讲解添加背景音乐的多种操作方法. 3.1.1给视频添加背景音乐 ...

  8. python给视频添加声音_python给视频添加背景音乐并改变音量的具体方法

    用到给视频添加背景音乐,并改变音量.记录一下,与碰到同样问题的朋友共享. import subprocess inmp4='E:/PycharmProjects/untitled2/hecheng/1 ...

  9. html怎样把视频作为背景音乐,如何为视频添加背景音乐

    视频后期制作中,给视频添加背景音乐是不可缺少的其中一步.因为视频配上音乐,给观者视觉冲击的同时,也能让人有听觉上的触动.音乐与视频画面结合并相互影响着,烘托氛围,这才是完美的视频作品.不过背景音乐只是 ...

最新文章

  1. 3D游戏设计和创作工具学习教程 3D Game Design Creation Tools
  2. Lammps 问题集锦
  3. 不懂技术的人不要对懂技术的人说这很容易实现
  4. 树网的核 Vijos1362 NOIP2007 树结构 直径 暴搜
  5. ZOJ 2432 Greatest Common Increasing Subsequence(最长公共上升子序列+路径打印)
  6. AutoCAD .net 二次开发官方教程及源码C#版(4)-(源码下载)
  7. python3多线程编程_Python 3-多线程编程
  8. 【Matlab】设置绘图窗口大小及颜色
  9. Flink:动态表上的连续查询
  10. 只能用光盘启动怎么办?
  11. 雪亮工程视频监控应用系统解决方案
  12. Uipath打包流程为.nupkg文件
  13. java动态数组输入_java中如何使用动态数组?代码示例
  14. access网格线方向微为垂直_设置ACCESS2010背景和网格线
  15. EASYUI 登陆框界面
  16. 张朝阳一天只睡4小时?不知道,反正我每天都睡足7小时
  17. 一个网站直接跳转引起的一些思考
  18. feign 传 MultipartFile Error converting request body 序列化 错误
  19. 从信息传播角度来看链路预测
  20. 既然阻塞 I/O 会使线程休眠,为什么 Java 线程状态却是 RUNNABLE?

热门文章

  1. 识字小程序—hanzi-writer-miniprogram实现临摹笔画动画播放等
  2. 广义图标与界面中的图标
  3. moment判断日期时间是否在另一个日期时间之前
  4. 解决opencv imwrite()影像全黑
  5. Java架构师 每日微笔记 0001
  6. Licheepi zero SPI Flash 系统编译
  7. 自编小程序,保持编程达人眼睛
  8. 罗振宇“时间的朋友”跨年演讲:为做事的人服务 准确抓住小趋势
  9. pgsql数据替换替换换行符
  10. 各类PDA及手机硬重启方法