丢帧的出现

说起视频播放器大家都很熟悉了,覆盖各种平台,使用简单操作方面,但是视频播放器里面的原理却非常的复杂,牵扯到很多方面的知识点。

今天我们来探讨一下当视频解码和渲染的总时间大于了视频指定的时间时,就会出现声音比画面快的情况,单个画面延后的时间在人眼不能察觉的范围内还是能接受的,但是如此累计起来就会造成这个延迟的加大,导致后面声话完全不同步,这是不能接受的。

那么为了解决这种问题,视频“丢帧”就出现了。

视频播放原理

我们看到的视频其实就是一幅一幅的图片组成的,就和电影一样的原理,在很短的时间内连续把这些图片展示出来,这样就达到了视频连续的效果,比如每秒中展示25幅图片。

而在这25幅图片中某几幅(不能太多)图片没有展示出来,我们也是很难察觉的,这就是我们“丢帧”的基础了。

如果图片丢失多了,明眼人一眼就看出来了,那么就不用再讨论“丢帧”了,而是不会看你的这个视频了。

视频编码过程(H264)

现在视频编码比较流行的就是H264编码,它的压缩(编码)模式有很多种,适合于不同的场景,比如网络直播、本地文件、UDP传输等都会采样不同的压缩(编码)模式。

h264编码器会把一幅幅的图片压缩(编码)成体积很小的一个一个的单元(NALU),并且这些一个一个的单元之间并不是完全独立的。

比如:有10幅图片,经过编码后,第一幅图片会单独生成一个单元,而第二个图片编码后生成的单元只会包含和第一幅图片不同的信息(有可能第二幅图片和第一幅图片只有一个文字不一样,那么第二个单元编码后的数据就仅仅包含了这个文字的信息,这样的结果就是体积非常小),然后后面编码后的第三个、第四个单元一直到第十个单元都只包含和前一个单元或几个单元不同的信息(当然实际编码时很复杂的),这样的结果就是一个原本只有1G大小的一组图片编码后可能只有十多兆大小,大大减小了存储空间和传输数据量的大小。

H264中 I帧、P帧、B帧的含义

前面提到的第一幅图片是被单独编码成一个单元(NALU)的,在H264中我们定义关键帧(用字母I表示,I帧,包含一幅图片的所有信息,可独立解码成一幅完整的图片)。

后面的第二个单元一直到第十个单元中的每一个单元我们定义为P帧(差别帧,因为它不包含完整的画面,只包含和前面帧的差别的信息,不能独立解码成一幅完整的图片,需要和前面解码后的图片一起才能解码出完整的图片)。

当然H264中还有B帧(双向帧,需要前后的数据才能解码成单独的图片),这就是我们经常听说的视频的I帧、P帧、B帧。

视频解码过程(H264)

通过前面的讲解,相信大家对视频编码后图片的变化过程有了大概的了解了(了解过程就行,具体技术细节就不用追究了),那么我们的重点就来了,播放器播放视频的过程就和图片编码成视频单元(NALU)的过程相反,而是把我们编码后的I帧、P帧、B帧中的信息解码后,依照编码顺序还原出原来的图片,并按照一定的时间显示(比如每秒显示25幅图片,那么每幅图片之间的间隔就是40ms,也就是每隔40ms显示一幅图片)。

请注意这里的一定的时间(这里的40ms)里面播放器需要做许多的事情:

  1. 读取视频文件或网络数据

  2. 识别读取的数据中的视频相关的数据

  3. 解析出里面的每一个单元(NALU),即每一帧(I、P、B)

  4. 然后把这些帧解码出完整的图片(I帧可以解码成完整图片,P、B帧则不可以,需要参考其他帧的数据)

  5. 最后按照一定的时间间隔把解码出来的图片显示出来

大多数情况下,播放器所在设备的软硬件环境的解码能力都是可以让播放器在这个一定时间(比如40ms)内完成图片的显示的,这种情况下就是最好不过的了。

而也有设备软硬件环境的解码能力不能在这个一定时间(比如40ms)内完成图片的显示,但是呢又相差不大(比如相差几毫秒),但是随着解码的次数增加,这个时间就会累计,后面就有可能相差几秒、几十秒、几分钟等,这样就需要“丢帧”操作了。

开始丢帧

丢帧丢帧,怎么丢,丢掉哪些帧我们怎么决定呢,这就要从视频图像是怎么解码得到的原理下手了,不然随便丢帧的话,最容易出现的情况就是花屏,导致视频基本不能看。下面我就举个例子来说明怎样丢帧:

比如我们的视频规定的是隔40ms(每秒25帧,且没秒的第一帧是I帧)显示一幅图片,而我们的设备解码能力有限,最快的解码出一幅图片的时间也需要42ms,这样本来该在40ms出显示第一幅图片,但是由于解码时间花了42ms,那么这一幅图片就在42ms时才显示出来。

比规定的时间(40ms)延迟了(42-40)2ms,当我们连续解码24幅图片时,这个延迟就到了20 * 2ms = 40ms,假设这个40ms的延迟已经很大了,再加大延迟就会造成我们明显感觉到视频的声音和画面不同步了。

所以我们就需要把后面的(25-24)1帧没解码的给丢了不显示(因为此时解码24帧的时间已经消耗了24*42=1008ms了,也就是说下一个40ms该显示第二秒的第一帧了,如果再显示第一秒的最后一帧,这样就会发生明显不同步的现象了),而是接着第二秒的数据开始解码显示,这样我们就成功的丢掉了一帧数据,来尽量保证我们的声音和画面同步了。

丢帧优化

前面提到的都是理想情况(每秒25帧,并且每一秒的第一帧都是I帧,能独立解码出图像,不依赖其他帧)下的丢帧,而不理想的情况(2个I帧直接的间隔不是定长的,比如第一个I帧和第二个I帧直接间隔24个其他帧,而第三个I帧和第二个I帧之间相差35个其他帧)则是经常遇到的。

这种情况下我们就不能写死解码播放24帧然后丢掉第25帧,因为可能出现丢掉25帧后的下一帧仍然不是I帧,这样解码就会解不出完整的图片,显示出来的画面就会有花屏,影响体验。

那么比较好的办法就是,我们定义一个内存缓冲区域,尽量在这个区域里面包含2个及以上的I帧(注意是解码前),比如:播放器从第一个关键帧开始解码播放,由于解码能力有限,当理论时间应该马上解码显示第二个关键帧时,而此时播放器还在解码这个关键帧之前的第5帧,也就是说播放器还得再解码5帧才能到这个关键帧,那么我们就可以把这5帧给丢掉了,不解码了,直接从这个关键帧开始解码,这样就能保证在每个关键帧解码播放时都和理论播放的时间几乎一致,让人察觉不到不同步现象,而还不会造成花屏的现象。

这种丢帧个人觉得才是比较不错的方案。

FFMpeg解码伪代码

bool dropPacket = false;
while(true)
{AVPacket *pkt = getVideoPacket();if(audioClock >= lastKeyFrameClock + offsetTime)//当前音频时间已经超过了下一帧关键帧之前了,就需要丢帧了{dropPacket = true;}if(pkt->flags == KEY_FRAME)//关键帧不丢{dropPacket = false;}if(dropPacket){av_packet_free(pkt);av_free(&pkt);pkt = NULL;continue;}//正常解码...
}

最后来一张出自灵魂画手的丢帧图:

来源:https://blog.csdn.net/ywl5320/article/details/86514391

技术交流,欢迎加我微信:ezglumes ,拉你入技术交流群。

私信领取相关资料

推荐阅读:

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

OpenGL ES 学习资源分享

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

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

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

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

觉得不错,点个在看呗~

视频播放器选择怎样的丢帧策略~~相关推荐

  1. RTSP播放器网页web无插件直播流媒体音视频播放器EasyPlayer-RTSP-Android解码获取视频帧的方法

    应用场景 EasyPlayer-RTSP在多年与VLC的对标过程中,积累了广泛的应用场景,EasyPlayer-RTSP底层与上层全部自主开发,自主知识产权,可实战测试. EasyPlayer-RTS ...

  2. 【开源】知乎视频播放器 Griffith 介绍

    Griffith 是什么? Griffith 是一个基于 React 的视频播放器,目前已在知乎 web 和 mobile web 内使用,并在 GitHub 上开源. 开源地址及示例 GitHub ...

  3. 知乎视频播放器 Griffith 开源了~

    知乎视频播放器 Griffith 开源介绍 Griffith 是什么? Griffith 是一个基于 React 的视频播放器,目前已在知乎 web 和 mobile web 内使用,并在 GitHu ...

  4. 自定义视频播放器与慢放滚轮

    受同学之邀,帮忙自定义一控件.需求是:开发慢放滚轮,用手指拨动实现帧级的慢速播放,滚轮可双向拨动,其滚动具有惯性,滚动速度决定视频播放的速度.需求很明朗,可我却是一头雾水.说实话,在此之前我还没有自定 ...

  5. 【黑马Android】(11)音乐播放器/视频播放器/照相机/常见对话框/notification通知/样式和主题/帧动画/传感器/应用程序反编译与安装

    音乐播放器api <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns: ...

  6. 视频播放器的新选择——Mplayer WW编译版

    在细说Mplayer WW版之前,先说一下我之前试用的几款视频播放器. 使用时间最长--K-Lite Mega Code Pack.无捆绑,全格式支持,无需设置即可使用,附带多个配置工具,可选用Med ...

  7. pyQT 视频播放器(三) 实现视频截图、获取每一帧数据

    pyQT 视频播放器(三) 实现视频截图.获取每一帧数据 背景 方法调研 详细代码说明 最终效果 总结: 参考资料 背景 在 "PyQt5 实现视频播放器(二) ,详细版本 ,适合新手入门& ...

  8. Android中视频播放器的选择,MediaPlayer、ExoPlayer、ijkplayer简单对比

    MediaPlayer 在Android系统中对于视频播放器有原生的实现MediaPlayer, 以及将MediaPlayer,SurfaceView封装在一起的VideoView, 两者都只是使用硬 ...

  9. html选择本地文件视频并播放器,使HTML5视频播放器播放不同的文件(Make a HTML5 video player play a different file)...

    使HTML5视频播放器播放不同的文件(Make a HTML5 video player play a different file) 在播放视频时,我无法让HTML5播放器播放不同的视频,我尝试更改 ...

最新文章

  1. Delegate成员变量和Event的区别
  2. tensor torch 构造_详解Pytorch中的网络构造
  3. 汇编语言之大小写转换问题
  4. 服务器03系统怎么设置网站,Windows 2003系统路由服务的配置方法
  5. 设备树下的platform 驱动编写
  6. c语言实现linux下的top命令来获取cpu利用率_有用的一篇笔记,linux 调优各项监控指标...
  7. PowerShell 2.0 实践(十一)管理 TFS 2010 (2)
  8. 《Programming WPF》学习(一)Hello WPF
  9. Android 常用操作
  10. centos 6 与 centos 7 服务开机启动、关闭设置的方法
  11. oracle数据库基本讲解(菜鸟篇)
  12. VS2005、vs2008+WinXPDDK+DDKWizard配置驱动开发环境
  13. Unity3d学习之路-简单打飞碟小游戏
  14. rman异机恢复 Linux _RAC至Win_Single Instance note
  15. Common Electrical I/O (CEI)
  16. win10关机后cpu风扇还在转_win10系统关机后风扇还转的解决方法
  17. 【菜鸟学开发系统】学生成绩管理系统(二)
  18. 长期有耐心读后感-20221010
  19. android蓝牙耳机来电铃声,Android实现积极连接蓝牙耳机
  20. seo与sem的关系和区别

热门文章

  1. 推荐一些适合程序员使用的手机壁纸?
  2. 融入STEAM教育的劳动技能课程
  3. DSPE-PEG-FA Folic acid PEG DSPE 磷脂-聚乙二醇-叶酸溶于有机溶剂
  4. 感量越大抑制频率约低_磁环抗干扰选择
  5. 中睿天下亮相2022电力行业信息化年会
  6. (java版)L1-020 帅到没朋友 (20分)
  7. 期货市场技术分析07_摆动指数和相反意见理论
  8. 首师大附中OJ系统 0004 我们的社团
  9. VUE+Canvas实现输入文字生成对应的字体图片小功能
  10. 最新完整代码:使用word2vec预训练模型进行增量训练(两种保存方式对应的两种加载方式)适用gensim各种版本