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

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

最近在做 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. python3 asyncio loop 使用线程池原理
  2. 阿里云首发Dubbo3.0 + Nacos2.0
  3. C++11 并发指南三(Lock 详解)
  4. Shell脚本IF条件判断和判断条件总结
  5. iPhone 12开启5G续航锐减 苹果官方回应了!
  6. cms是什么意思啊_美团面试官问我:ZGC 的 Z 是什么意思?
  7. 数据安全的四个新挑战有哪些
  8. java2wsdl_Java2WSDL之java实现
  9. oracle strsplit函数,oracle splitstr 函数
  10. 百度搜索引擎推出“熊掌号”,保护原创作者权益
  11. java安装教程(eclipse)
  12. 爬虫爬出来的数据不全_Web Scraper教程(二)爬虫入门之当当畅销书爬取
  13. TGA文件转YUV文件
  14. Day03-JavaScript01
  15. 英语作文模板句型,考试必背!
  16. 简易的本地音乐播放器 适用于Java初学者
  17. python的invalid syntax是什么意思_python 中 出现 invalid syntax 是什么意思 我是新手 求告知。...
  18. 看完秒懂ICA(含MATLAB和python代码)
  19. (王爽)汇编语言-课程设计二完整版
  20. python气象绘图速成_Python气象绘图Day-By-Day

热门文章

  1. 越狱软件可带来千万量级用户
  2. python实现ORC/文字识别之pytesseract
  3. NLP之人机对话系统
  4. ubuntu: 由unity转gnome3安装出错及解决
  5. c++随笔-删除文件
  6. 从阿里云迁移域名至 Amazon Route 53 帮你了解域名迁移
  7. 关于泛型中包含级联的List转化为json数据的处理
  8. BootStrap实现一个简单的界面
  9. jquery禁止鼠标右键 原生js禁止鼠标右键
  10. 使用chrome浏览器插件抢小米8