在知识星球分享的文章,顺便也在公众号发表一下,不足之处,欢迎指正。

一个关于音视频领域专业问答的小圈子!!

最近在做 Seek 相关功能时遇到的问题排查,顺便也学到了一些新的东西,和大家分享下。

在视频播放时执行 Seek 到任意点的操作,一般都是 Seek 到任意点往前最近的 I 帧,然后再逐帧解码到指定时间点。

这里可以优化,假设当前时间和指定时间在一个 GOP 内,就可以不用 seek ,直接顺序向下解码就好。

而正是这个优化出现了一点问题,现象如下:

已经判断播放点 A 和 Seek 点 B 不在一个 GOP 内,然后执行 av_seek_frame 方法还是把时间点 A 所在 GOP 全部解码了,导致播放上出现了卡顿。

这里就很奇怪了,明明判断不在一个 GOP ,那 Seek 时就应该从时间点 B 所在 GOP 的 I 帧开始解码, 但执行时还是解码了上一个 GOP 的内容。

到底是判断是否同一个 GOP 的函数出问题了还是 Seek 方法有问题呢?

带着疑问开始深入源码探索。

FFmpeg 没有直接提供判断两帧是否同一个 GOP 的方法,所以通过 av_index_search_timestamp 方法得到传入时间点最近的 I 帧的 index 索引,如果两个时间点的索引相同则表示为同一个 GOP 内,因为最近的 I 帧相同。

然而 av_index_search_timestamp 方法是通过 AVIndexEntry 中的 timestamp 来判断的,它是一个 DTS 值,通过二分查找得到最近的索引。

在没有 B 帧的情况下,I 帧的 PTS 等于 DTS ,所以判断不会出问题。然而正是有了 B 帧,如果 I 帧的 PTS 和 DTS 不相等的话,那么上面的判断相当于是拿一个 PTS 值和 I 帧的 DTS 比较是否同一个 GOP 了。

如果将错就错,判断 GOP 时得到结论是非同一个 GOP ,那么 Seek 也应该是非同一个 GOP ,但现实恰恰相反,Seek 当做了同一个 GOP ,这里面肯定有计算出问题了,继续深入源码。

通过在 mov.c 源码中看到了如下的操作:

static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, int flags)
{MOVStreamContext *sc = st->priv_data;FFStream *const sti = ffstream(st);int sample, time_sample, ret;unsigned int i;// Here we consider timestamp to be PTS, hence try to offset it so that we// can search over the DTS timeline.timestamp -= (sc->min_corrected_pts + sc->dts_shift);ret = mov_seek_fragment(s, st, timestamp);if (ret < 0)return ret;sample = av_index_search_timestamp(st, timestamp, flags);av_log(s, AV_LOG_TRACE, "stream %d, timestamp %"PRId64", sample %d\n", st->index, timestamp, sample);// 省略部分代码

注意到如下一行代码:

timestamp -= (sc->min_corrected_pts + sc->dts_shift);

也就是说我们传入的时间都会被减上一个值,然后再执行 av_index_search_timestamp 方法,而这个值导致判断 GOP 和 Seek 之间的关键帧索引出问题了。

正如代码中的注释所示,假设传入的时间是 PTS 值,然后给它减去偏移以得到 DTS 值,因为 av_index_search_timestamp 方法就通过 DTS 进行比较的嘛。

出现问题的原因就是 seek 的时间点正好在 I 帧的 PTS 和 DTS 范围之间了,执行 seek 时减去偏差值就小于 DTS 了,所以变成了同一个 GOP 。

现在要解决问题就是如何得到 sc->min_corrected_pts + sc->dts_shif 之和,然后判断 GOP 时减去它以修正得到 DTS 值。

还好通过遍历源码发现它的值是不会运行时改变的,一旦决定了就定下来了。另外我们可以用第一个 I 帧的 DTS 值作为偏移值。

auto indexEntry = avStream->index_entries;auto nbIndexEntry = avStream->nb_index_entries;for (int i = 0; i < nbIndexEntry; ++i) {if (indexEntry[i].flags == AVINDEX_KEYFRAME) {DTSOffset = indexEntry[i].timestamp;return;}}

如果没有 B 帧,DTS 值为 0 ,有 B 帧,那么首帧的 DTS 值就可以用来做偏差值进行计算了。

一个音视频领域专业问答的小圈子!

推荐阅读:

音视频开发工作经验分享 || 视频版

OpenGL ES 学习资源分享

开通专辑 | 细数那些年写过的技术文章专辑

Android NDK 免费视频在线学习!!!

你想要的音视频开发资料库来了

推荐几个堪称教科书级别的 Android 音视频入门项目

觉得不错,点个在看呗~

Seek 策略以及在有 B 帧情况下的处理相关推荐

  1. 如何在不影响网络的情况下构建边缘计算策略

    阅读本文之前先问一下自己这个问题:"为什么我需要使用边缘计算?" 随着越来越多的科技公司宣称他们提供"边缘智能"的能力,边缘计算吸引了众多公司高管们的关注.哪个 ...

  2. 【数据竞赛】99%情况下都有效的特征筛选策略--Null Importance。

    作者:杰少 Null Importance特征筛选 简介 目前数据量越来越大,数据特征维度也越来越高,这不仅对我们的计算存储带来了较大的挑战,与此同时,还会对模型的效果带来较大的损益. 如何既能节省内 ...

  3. enti下载器_短跑enti策略:如何在不破坏软件的情况下改进软件

    enti下载器 我们的代码已被破坏了几个星期. 编译器错误,测试失败,行为错误困扰着我们的团队. 为什么? 因为我们被盲目蛙跳打了. 通过对关键组件进行多次并发更改以希望对其进行改进,我们已经从其丑陋 ...

  4. 短跑enti策略:如何在不破坏软件的情况下改进软件

    我们的代码已被破坏了几个星期. 编译器错误,测试失败,错误行为困扰着我们的团队. 为什么? 因为我们被盲目蛙跳打了. 通过对关键组件进行多次并发更改以希望对其进行改进,我们已经从其丑陋但稳定且可工作的 ...

  5. 在不同的库存情况下,亚马逊CPC广告的投放策略会有什么改变呢?

    说到开广告之于库存的意义,很多亚马逊卖家第一反应就是开广告可以处理库存,盘活库存,提升资金周转率,当你库存太多的时候,可以通过广告引流和低价甩掉库存:在不同的库存情况下,亚马逊CPC广告的投放策略会不 ...

  6. 三网融合情况下,实时语音通信技术的研究

    随着技术和标准的不断成熟,伴随着"三网合一"的大潮,VoIP可望成为下一代电信基础设施结构的杨心,使未来各电信业务综合统一在IP网络上成为可能,导致数据的融合和未来电信市场的重组, ...

  7. 三网融合情况下,实时语音通信技术解决之道

    随着技术和标准的不断成熟,伴随着"三网合一"的大潮,VoIP可望成为下一代电信基础设施结构的杨心,使未来各电信业务综合统一在IP网络上成为可能,导致数据的融合和未来电信市场的重组, ...

  8. 1.什么情况下发生GC

    目录 一:jvm运行时数据区的划分 二:堆区的划分(where) 三:什么情况下发生GC(when) 四:哪些内存需要回收(垃圾对象who) 五:GC如何回收(how) 六:jvm的内存回收过程 七: ...

  9. ⽬标⾏动及稠密环境未知情况下,⽆⼈机跟踪的系统解决⽅案

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 本文是对<Fast-Tracker:A Robust Aerial System for Tra ...

  10. 园艺智慧_园艺日:如何在完全远程的情况下运行技术债务清理日

    园艺智慧 Just like financial debt, you have to be wise about the technical debt you are building up over ...

最新文章

  1. CUDA之nvidia-smi命令详解---gpu
  2. 《Adobe AIR权威指南》——《Flex 3权威指南》作者新作
  3. postgresql创建表
  4. mysql数据库搜索字符_在MySQL数据库中快速搜索字符串?
  5. html小球跳跃技术原理,弹跳的小球.html · web-project-songyu/原生js小例子 - Gitee.com...
  6. docker私有仓库harbor配置helm chart仓库(安装helm chart插件)
  7. 数学中R,Z,N,Q都代表什么意思?
  8. enum in c language
  9. QT3与QT4中uic的使用差异---李家凯老师
  10. 我的手绘2013.01.27
  11. Node.js的完全卸载与下载安装及各种npm、nvm、nrm配置(保姆式教程---提供全套安装包)---node.js的安装与配置(0)
  12. java hibernate4 学习心得
  13. 3.1 scrapy框架 -- 安装与基本使用
  14. 大型互联网产品的全链路压测
  15. Shader编程教程_Shader新手入门视频教程_Shader编程从入门到精通
  16. PowerBi包含什么,以及每一个的介绍
  17. 计算机三种桌面图标,例举win7电脑桌面图标排列方式
  18. 尚医通——后台搭建——MybatisPlus自动填充和乐观锁
  19. Android Notification取消声音 取消弹出
  20. 集福啦!你想要的“福”这里都有~

热门文章

  1. 【Sutcliffe Pentagons】奇幻派的漂流
  2. 微信分享 无法获取到分享状态的问题-微信分享功能调整
  3. 谈谈UG二次开发程序入口
  4. PE装到移动硬盘的资料寻回办法
  5. SLAM notes
  6. 小米手机相机的专业模式
  7. axis2 异常OMElement
  8. python系列13:python中Path常用功能
  9. oracle normsinv函数,统计函数NormSDist和NormSInv函数实现
  10. 2021年安全生产模拟考试(建筑起重信号司索工模拟考试题库)安考星