新手学习FFmpeg - 调用API计算关键帧渲染时间点
通过简单的计算来,线上I帧在视频中出现的时间点。 完整代码请参考 https://andy-zhangtao.github.io/ffmpeg-examples/
名词解释
首先需要明确以下名词概念:
- I/P/B 帧(具体差异请参看 https://www.jianshu.com/p/18af03556431 )
I帧: 内部编码帧(关键帧)
P帧: 前向预测帧(根据I帧计算差值)
B帧: 双向预测帧(根据I帧和P帧计算差值) - PTS: 帧显示的时间刻度(在哪个时间点显示此帧)
- DTS: 帧解码的时间刻度(在哪个时间点解码此帧)
- Timestamp: 帧在视频内部的时间戳
- Time_base: 视频表示时间的"刻度"
处理流程
视频内没有绝对时间,只有相对时间(相对视频起始位置)。例如在播放器中看到的时间进度条"00:00:05"表示的是当前看到的帧是在相对起始时间点(00:00:00)解码并渲染的。
而"00:00:05"只是为了让用户方便理解而展现出来的,在视频内部则是使用时间戳来保存的,"00:00:05"可能相对的时间戳则是"5000000µs"(不考虑四舍五入)。
那么时间戳又是怎么计算出来的呢?此时就需要通过PTS和Time_base来配合计算。
首先来看Time_base。 Time_base好比一把尺子,上面标满了刻度,例如(1,60)表示时间刻度就是1/60,每个时间单位就是1/60秒。 如果是(1,1000)就表示每个时间单位是1微秒。
上面说到pts是显示的时间刻度, 也就是占用了多少时间刻度。 换算成大白话就是pts占用了多少个刻度,而time_base表示每个刻度是多长。
然而这有什么用呢?Time_base最重要的作用是用来统一”时间节奏"的。 例如视频A编码时采用1/1000的time_base,则某个帧的pts保存为465000。 当对视频A进行解码时,换成了1/9000的time_base,此时时间刻度不一致了,就需要通过pts*encode_time_base来换算成解码时的timestamp,这样才能保证正确解码。
编码实现
上面是理论介绍,下面来看如何通过代码来计算timestamp和换算成time.
这次只需要显示每帧的pts,time_base,time因此不需要初始化output, 只要初始化input即可。
初始化输入源
按照前几篇介绍的初始化思路,只需要按照打开文件->判断视频流->初始化解码器这样的步骤就可以了。
+------------------------+ +-------------------------+
| avformat_open_input | ------------>|avformat_find_stream_info|
+------------------------+ +-------------------------+
|
|
|
\|/
+-----------------------------+ +-------------------------+
|avcodec_parameters_to_context| <---------| avcodec_find_decoder |
+-----------------------------+ +-------------------------+
avcodec_parameters_to_context尤其需要关注,这个函数会根据输入源的编码信息来初始化用户指定的编码上下文。如果编码信息不匹配或者设置错误时,会出现莫名的解码错误。一般调用这个函数后,大多数的解码错误都能消失。
计算Time
time_base是一个struct
typedef struct AVRational{
int num; ///< Numerator
int den; ///< Denominator
} AVRational;
num 表示的是分子,den表示分母。 对于time_base来说num就是1,den表示每一秒等分了多少份。 上面说过通过pts*time_base就可以得出时间戳,所以需要计算出每个时间刻度具体代表多少,所以通过av_q2d得出每个刻度具体值。
在循环读入解码后的帧数据之后,可以直接通过iframe->pts来读取当前帧的pts值,然后再乘以刻度值就可以得出当前时间戳iframe->pts * av_q2d(_time_base)。
伪代码如下:
while av_read_frame {
avcodec_send_packet
...
while avcodec_receive_frame {
...
iframe->pts * av_q2d(_time_base)
...
}
}
新手学习FFmpeg - 调用API计算关键帧渲染时间点的更多相关文章
- 新手学习FFmpeg - 调用API完成录屏
调用FFMPEG Device API完成Mac录屏功能. 调用FFMPEG提供的API来完成录屏功能,大致的思路是: 打开输入设备. 打开输出设备. 从输入设备读取视频流,然后经过解码->编码 ...
- 新手学习FFmpeg - 调用API调整视频局部速率
通过修改setpts代码实现调整视频部分的播放速率. 完整代码可参考: https://andy-zhangtao.github.io/ffmpeg-examples/ 在前面提到了PTS/DTS/T ...
- 新手学习FFmpeg - 调用API编写实现多次淡入淡出效果的滤镜
前面几篇文章聊了聊FFmpeg的基础知识,我也是接触FFmpeg不久,除了时间处理之外,很多高深(滤镜)操作都没接触到.在学习时间处理的时候,都是通过在ffmpeg目前提供的avfilter基础上面修 ...
- 新手学习FFmpeg - 调用API完成录屏并进行H.264编码
Screen Record H.264 目前在网络传输视频/音频流都一般会采用H.264进行编码,所以尝试调用FFMPEG API完成Mac录屏功能,同时编码为H.264格式. 在上一篇文章中,通过调 ...
- 新手学习FFmpeg - 调用API完成两个视频的任意合并
本次尝试在视频A中的任意位置插入视频B. 在上一篇中,我们通过调整PTS可以实现视频的加减速.这只是对同一个视频的调转,本次我们尝试对多个视频进行合并处理. Concat如何运行 ffmpeg提供了一 ...
- 新手学习FFmpeg - 调用API完成视频的读取和输出
在写了几个avfilter之后,原本以为对ffmpeg应该算是入门了. 结果今天想对一个视频文件进行转码操作,才发现基本的视频读取,输出都搞不定. 痛定思痛,仔细研究了一下ffmpeg提供的examp ...
- 新手学习FFmpeg - 通过API实现可控的Filter调用链
虽然通过声明[x][y]avfilter=a=x:b=y;avfilter=xxx的方式可以创建一个可用的Filter调用链,并且在绝大多数场合下这种方式都是靠谱和实用的. 但如果想精细化的管理AVF ...
- 新手学习FFmpeg - 通过API完成filter-complex功能
本篇尝试通过API实现Filter Graph功能. 源码请参看 https://andy-zhangtao.github.io/ffmpeg-examples/ FFmpeg提供了很多实用且强大的滤 ...
- 新手学习FFmpeg - 如何编写Kubernetes资源文件
Kubernetes API的使用方式 Kubernetes API属于声明式API编程, 它和常用的命令式编程有一些区别. 通俗的说,命令式编程是第一人称,我要做什么,我要怎么做. 操作系统最喜欢这 ...
随机推荐
- alluxio源码解析-层次化存储(4)
层次化存储-特性介绍: https://www.alluxio.org/docs/1.6/cn/Tiered-Storage-on-Alluxio.html 引入分层存储后,Alluxio管理的数据块 ...
- Logback配置文件这么写,TPS提高10倍
通过阅读本篇文章将了解到 1.日志输出到文件并根据LEVEL级别将日志分类保存到不同文件 2.通过异步输出日志减少磁盘IO提高性能 3.异步输出日志的原理 配置文件logback-spring.xml ...
- springmvc异步处理
好久没有写过博客了,都是看大牛的文章,略过~~ 突然感觉成长在于总结!废话不多说,开干 由于是公司项目,所以不方便给出代码,看图操作 在项目util目录下创建工具类TaskExecutorConfig ...
- Codeforces 436D Pudding Monsters
题意简述 开始有无限长的一段格子,有n个格子种有布丁怪兽,一开始连续的布丁怪兽算一个布丁怪兽. 每回合你可以将一个布丁怪兽向左或右移动,他会在碰到第一个布丁怪兽时停下,并与其合并. 有m个特殊格子,询 ...
- tk.mybatis扩展通用接口
一.tk.mybatis已经为我们封装好了许多拆箱即用的通用mapper,但在实际的项目开发中想必不少小伙伴在数据库设计中都会采用逻辑删除这种方案,再去使用通用的mapper接口就不行了.这时候就需要 ...
- Alfred上可提高工作效率的Workflow推荐
温馨提示:本文中Alfred是Mac平台的工具,不适用于其他平台. Alfred是Mac平台上被很多人吹爆的一款效率提升软件,我刚毕业工作的时候就看到公司内网有人推荐,但没有尝试. 后来我跳槽后自己买 ...
- python-day16
一.正则表达式 regular expression -----regex 验证匹配正则表达式使用单个字符串来描述.匹配一系列匹配某个句法规则的字符串.在很多文本编辑器里,正则表达式通常被用来检索.替 ...
- 多线程之pthread, NSThread, NSOperation, GCD
关于多线程会有一系列如下:多线程之概念解析 多线程之pthread, NSThread, NSOperation, GCD 多线程之NSThread 多线程之NSOperation 多线程之GCD p ...
- Container及其内部进程监控剖析
目前市场上的虚拟化技术种类很多,例如moby(docker).LXC.RKT等等.在带来方便应用部署和资源充分利用的好处的同时,如何监控相应Container及其内部应用进程成为运维人员不可避免遇到的 ...
- .net必问的面试题系列之面向对象
上个月离职了,这几天整理了一些常见的面试题,整理成一个系列给大家分享一下,机会是给有准备的人,面试造火箭,工作拧螺丝,不慌,共勉. 1.net必问的面试题系列之基本概念和语法 2.net必问的面试题系 ...