本次尝试在视频A中的任意位置插入视频B.

在上一篇中,我们通过调整PTS可以实现视频的加减速。这只是对同一个视频的调转,本次我们尝试对多个视频进行合并处理。

Concat如何运行

ffmpeg提供了一个concat滤镜来合并多个视频,例如:要合并视频Video A和Video B,通过调用

ffmpeg -i va.mp4 -i vb.mp4 -filter_complex "[0][1]concat[out]" -map '[out]' -y output.mp4

concat支持多个Input Source,上面的命令只合并了两个视频,通过生成concat流程图可以看到一些细节:

echo "movie=va.mp4[0];movie=vb.mp4[1];[0][1]concat,nullsink" | graph2dot -o graph.tmp
dot -Tpng graph.tmp -o graph.png

这是concat典型用法,循环读取输入源,然后通过修改pts完成合并。

concat是顺序修改,如果需要在video A中某个时间点插入video B,那么concat就无法完成了。 顺序合并是通过修改PTS实现,那么变序合并也可以通过修改PTS来实现,下面借助concat的逻辑来看看如何实现变序合并。

变序合并

为了方便说明问题,我们来看一下顺序和变序不同点到底在哪里。

  • 问题分析

我们仍然假设需要合并的两个视频分别是Video A和Video B, 需要将Video B插入在Video A中。AF表示Video A的帧, BF表示Video B的帧。

顺序合并

        +---------------------------------------------------------------------------------------------------------------+
| AF1 AF2 AF3 AF4 AF5 AF6 AF7 BF1 BF2 BF3 BF4 BF5 BF6 |
| |--------------|--------------|--------------|--------------|--------------|--------------|---> |
|Time 0 10 20 30 40 50 60 |
|PTS 0 100 200 250 300 350 400 500 600 650 700 750 800 |
+---------------------------------------------------------------------------------------------------------------+

顺序合并就是读取Video B的帧,然后将pts以Video A结束时的PTS为基准进行修改。

变序合并

        +---------------------------------------------------------------------------------------------------------------+
| AF1 AF2 AF3 AF4 BF1 BF2 BF3 BF4 BF5 BF6 AF5 AF6 AF7 |
| |--------------|--------------|--------------|--------------|--------------|--------------|---> |
|Time 0 10 20 30 40 50 60 |
|PTS 0 100 200 250 300 350 400 500 600 650 700 750 800 |
+---------------------------------------------------------------------------------------------------------------+

变序合并时先读取Video A的帧,当达到规定的PTS时,开始读取Video B的帧,然后以A截断时的PTS为基准重新计算PTS。当Video B所有的帧都处理完毕之后,在从截断处开始重新处理Video A的帧。

从上面两个图来看,问题好像不是很难解决。 只要达到截断的条件,就去处理另外一个视频,等待视频处理完毕之后。再返回来处理被截断的视频。

但在实现的道路上有如下三个问题需要解决:

  1. 如何判断到达插入时间点
  2. 如何判断视频处理完毕
  3. 如何从断点处重新读取Frame

下面就需要逐个问题解决了。

  • 如何判断到达插入时间点

因为我们是需要在视频A中插入视频B,所以需要首先找到插入点。 而根据时间来判断插入点无疑是最简单的一种形式,计算时间就可以依靠前几篇中介绍的PTS知识了。

当从视频源中读取到每帧后,我们通过帧的PTS和Time-Base根据pts * av_q2d(time_base)转换成播放时间。 这样第一个问题就顺利解决。

当找到插入点后,我们需要暂存当前的位置,等待插入结束后,需要从断点处重新加载帧。

  • 如何判断视频处理完毕

执行插入本质就是读取视频B的数据帧,然后修改PTS值。但我们需要得知视频B已经处理完毕,这样才能返回到视频A的断点处继续处理。 所以如何获取到视频处理完毕就是第二个问题。

如果抛开ffmpeg来说,处理视频本质也是一个IO流(从视频文件中读取的IO流),当判断到IO流结束时(通过seek来判断EOF)时就是视频处理完毕的时候。 但ffmpeg将这一层屏蔽掉了,也就是在filter中是无法直接获取到IO流状态的。

ffmpeg在屏蔽的同时,也提供了一种判断方式。filter在处理完每一帧之后,需要确认下一帧的状态(有下一帧/无下一帧),所以如果ffmpeg在读取到下一帧时返回了无下一帧,那就表示当前视频处理完毕。

通过ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)来获取下一帧的状态,当返回的ret>0表示没有下一帧,这个时候就可以通过判断当前处理状态来决定是否关闭输出流。

        if 当前处理视频B
切换到视频A的断点
else 当前处理视频A
关闭所有的输入流
关闭输出流
  • 如何从断点处重新读取Frame

这是最后一个待解决的问题了,当视频B的数据都处理完之后,就需要从视频A的断点处重新读取数据帧。上面说到对视频流的读取,本质就是对一个文件的IO流处理,而在IO时都会有一个指针来表示当前位置。

ff_inlink_acknowledge_status有两个作用,一方面获取下一帧,另一方面是确认当前帧处理结束。 换言之,当调用ff_inlink_acknowledge_status之后,ffmpeg会将IO流的指针向后移动到下一帧的起始位置,如果移动失败,则表示没有下一帧了。 如果移动成功,那么下次ff_inlink_consume_frame读取帧时,就从这个位置开始读取。

因此如何从断点处重新读取Frame其实不是问题,只要断点处的帧被确认处理结束了,ffmpeg会自动的移到下一帧位置。当我们将输入源切换到视频A时,就自动从断点处开始读取帧了。

  • 伪代码实现

通过下面的伪代码简要描述上述的过程:

        通过ff_outlink_get_status判断输出流状态
if 输出流已关闭
退出 for {
通过ff_inlink_consume_frame 获取下一帧 通过frame->pts * av_q2d(time_base)计算时间 if 时间达到插入点
修改当前状态, 进入暂存状态。 通过push_frame处理每一帧
} 通过ff_inlink_acknowledge_status确认帧状态 if 当前是暂存状态
切换到视频B if 没有下一帧
if 当前是视频B && 当前是暂存状态
关闭视频B
切换回视频A if 当前是视频A && 当前是暂存状态
关闭视频A
关闭输出流

大致就是这个处理流程, 完整代码可以参考iconcat里面的代码。

新手学习FFmpeg - 调用API完成两个视频的任意合并的更多相关文章

  1. 新手学习FFmpeg - 调用API完成录屏

    调用FFMPEG Device API完成Mac录屏功能. 调用FFMPEG提供的API来完成录屏功能,大致的思路是: 打开输入设备. 打开输出设备. 从输入设备读取视频流,然后经过解码->编码 ...

  2. 新手学习FFmpeg - 调用API编写实现多次淡入淡出效果的滤镜

    前面几篇文章聊了聊FFmpeg的基础知识,我也是接触FFmpeg不久,除了时间处理之外,很多高深(滤镜)操作都没接触到.在学习时间处理的时候,都是通过在ffmpeg目前提供的avfilter基础上面修 ...

  3. 新手学习FFmpeg - 调用API完成录屏并进行H.264编码

    Screen Record H.264 目前在网络传输视频/音频流都一般会采用H.264进行编码,所以尝试调用FFMPEG API完成Mac录屏功能,同时编码为H.264格式. 在上一篇文章中,通过调 ...

  4. 新手学习FFmpeg - 调用API完成视频的读取和输出

    在写了几个avfilter之后,原本以为对ffmpeg应该算是入门了. 结果今天想对一个视频文件进行转码操作,才发现基本的视频读取,输出都搞不定. 痛定思痛,仔细研究了一下ffmpeg提供的examp ...

  5. 新手学习FFmpeg - 调用API计算关键帧渲染时间点

    通过简单的计算来,线上I帧在视频中出现的时间点. 完整代码请参考 https://andy-zhangtao.github.io/ffmpeg-examples/ 名词解释 首先需要明确以下名词概念: ...

  6. 新手学习FFmpeg - 调用API调整视频局部速率

    通过修改setpts代码实现调整视频部分的播放速率. 完整代码可参考: https://andy-zhangtao.github.io/ffmpeg-examples/ 在前面提到了PTS/DTS/T ...

  7. 新手学习FFmpeg - 通过API完成filter-complex功能

    本篇尝试通过API实现Filter Graph功能. 源码请参看 https://andy-zhangtao.github.io/ffmpeg-examples/ FFmpeg提供了很多实用且强大的滤 ...

  8. 新手学习FFmpeg - 通过API实现可控的Filter调用链

    虽然通过声明[x][y]avfilter=a=x:b=y;avfilter=xxx的方式可以创建一个可用的Filter调用链,并且在绝大多数场合下这种方式都是靠谱和实用的. 但如果想精细化的管理AVF ...

  9. 新手学习FFmpeg - 如何编写Kubernetes资源文件

    Kubernetes API的使用方式 Kubernetes API属于声明式API编程, 它和常用的命令式编程有一些区别. 通俗的说,命令式编程是第一人称,我要做什么,我要怎么做. 操作系统最喜欢这 ...

随机推荐

  1. spring-boot-plus V1.2.1 发布 文件上传下载和静态资源访问

    [V1.2.1-RELEASE] 2019.08.21 ⭐️ New Features 文件上传保存到服务器指定目录 文件下载 访问上传的图片等资源 启用项目静态资源访问,可访问static/temp ...

  2. error LNK2001: unresolved external symbol "__declspec(dllimport)

    作为C++的小白,出现这个错误,是最头痛的.针对这种问题,我搜了网上的相关答案,很多都是在教Project ---> Settings中改动相关设置.我改了之后,问题依旧没有解决.后面查了这种问 ...

  3. 100天搞定机器学习|day45-53 推荐一本豆瓣评分9.3的书:《Python数据科学手册》

    <Python数据科学手册>共五章,每章介绍一到两个Python数据科学中的重点工具包.首先从IPython和Jupyter开始,它们提供了数据科学家需要的计算环境:第2章讲解能提供nda ...

  4. Keras实例教程(2)

    https://blog.csdn.net/baimafujinji/article/details/78385745

  5. Codeforces 246C

    题意略. 思路: 我们将数组中的数字从大到小排列,分别考虑取前0 + 1,1 + 1,2 + 1.....个的情况. 所谓i + 1的意思是,取前i个的时候,同时取第[i + 1],[i + 2],. ...

  6. Leetcode之深度优先搜索(DFS)专题-1020. 飞地的数量(Number of Enclaves)

    Leetcode之深度优先搜索(DFS)专题-1020. 飞地的数量(Number of Enclaves) 深度优先搜索的解题详细介绍,点击 给出一个二维数组 A,每个单元格为 0(代表海)或 1( ...

  7. [转]Android ImageView的scaleType属性与adjustViewBounds属性

    Android ImageView的scaleType属性与adjustViewBounds属性   ImageView的scaleType的属性有好几种,分别是matrix(默认).center.c ...

  8. 转载-SpringBoot开发案例之整合日志管理

    转载:https://cloud.tencent.com/developer/article/1097579 有一种力量无人能抵挡,它永不言败生来倔强.有一种理想照亮了迷茫,在那写满荣耀的地方. 00 ...

  9. 美团张志桐:美团 HTTP 服务治理实践

    2019 年 7 月 6 日,OpenResty 社区联合又拍云,举办 OpenResty × Open Talk 全国巡回沙龙·上海站,美团基础架构部技术专家张志桐在活动上做了<美团 HTTP ...

  10. matplotlib绘制矢量图像(svg),pdf and ps文件

    机器学习的过程中处理数据,会遇到数据可视化的问题. 大部分都是利用python的matplotlib库进行数据的可视化处理. plt.show() 默认都是输出.png文件,图片只要稍微放大一点,就糊 ...