简介
SGPlayer 是一款基于 AVPlayer、FFmpeg 的媒体资源播放器框架。支持全景视频,RTMP、RTSP 等直播流;同时支持 iOS、macOS、tvOS 三个平台。本文将采用图解+说明的方式把关键模块的实现原理介绍给大家。

发起原因
关于视频播放,苹果提供的 AVPlayer 在性能上有着十分出色的表现,在无特需求且资源可控的时,首选一定是它。但随着 VR 和直播的兴起,仅使用 AVPlayer 很多时候已经无法满足需求。出于性能考虑,又不能完全抛弃 AVPlayer,毕竟在点播时有着明显的优势。而在现有的开源项目中,普遍定位比较单一,并不能兼顾 AVPlayer、直播、VR。这样一来,需同时使用3款播放器才能满足需求,即点播使用 AVPlayer,直播使用一个独立的播放器,VR 使用一个独立的播放器。这样处理3套不同的接口和回调事件,着实很让人崩溃!SGPlayer 的出现大大简化了这一过程。

组成结构 和 播放流程

SGPlayer 播放流程图
上图展示了 SGPlayer 的播放流程和主要组件,下面简单介绍图中各组件的分工

SGPlayer
SGPlayer是一个抽象的播放器外壳,它本身并不具备播放功能。仅作为和外界交互的载体。真正的播放由内部的 SGAVPlayer 和 SGFFPlayer 完成。而画面绘制由内部的 SGDisplayView 完成。

SGPlayerDecoder
SGPlayerDecoder 是播放内核的选择器,根据资源类型动态选择使用 SGAVPlayer 或 SGFFPlayer 进行播放,可通过更改其配置参数,来自定义播放内核的选择策略。

SGAVPlayer
SGAVPlayer 是基于 AVPlayer 封装而成,视频画面输出至 SGDsiplayView,并根据视频类型(全景或平面)进行展示。音频由系统处理无需额外操作。

SGFFPlayer
SGFFPlayer 是基于 FFmpeg 封装而成,支持近所有的主流视频格式。视频画面同样输出至 SGDsiplayView。音频则输出至 SGAudioManager,再由 SGAudioManager 使用 Audio Unit 进行播放。

SGDisplayView
SGDisplayView 负责视频画面的绘制。它本身不会绘制视频画面,仅作为绘制层的父视图使用,真正的绘制由内部的 AVPlayerLayer 和 SGGLViewController 完成,选择规则如下表所示。

Player 平面 全景
SGAVPlayer AVPlayerLayer SGGLViewController
SGFFPlayer SGGLViewController SGGLViewController

SGAudioManager
SGAudioManager 负责声音的播放和音频事件的处理。内部使用 AUGraph 做了一层混音,通过混音可以设置声音的输出音量大小等操作。

小结
了解了各组件的功能,重新梳理一下完整的播放过程

SGPlayer 收到播放请求。
由 SGPlayerDecoder 根据资源类型分发给 SGAVPlayer 或 SGFFPlayer 进行播放。
如果使用 SGAVPlayer 播放,根据视频类型将画面输出给 SGDisplayView 中的 AVPlayerLayer 或 SGGLViewController。
如果使用 SGFFPlayer 播放,将视频画面输出给 SGDisplayView,音频输出至 SGAudioManager。
通过抽象的 SGPlayer 将真正负责播放的 SGAVPlayer 和 SGFFPlayer 屏蔽起来,这样可以保证无论资源是何种类型,对外仅暴露一套统一的接口和回调,将播放内核间的差异内部消化,尽可能降低使用成本。

全景图像原理
全景图像与平面图像本质都是一张 2D 图片,区别在于展示时的载体。对于平面图而言,用于展示的模型是一个矩形,仅需将图像上的像素一一对应在矩形上即可;而全景图像展示的模型是一个球,需要将图像上的每一个像素都对应到球面相应位置上。在绘制流程上二者的差别并不大,仅在贴图规则和呈现方式上略有区别。

贴图规则

全景图像 贴图规则

把平面图片贴到球面上的过程和地球仪很相似。以上图为例,左侧图片中的每一个像素,都可以在右侧球面上找到对应的位置。下面列举一个关键的对应关系。

直线AB 上所有的点都与 点J 对应,同理 直线CD 上所有的点都与 点K 对应。

直线MN 上的点与 赤道 上的点一一对应。
直线AC/BD 上的点与绿 色经线前半面 上的点一一对应。
直线EF 上的点与 绿色经线后半面 上的点一一对应。

呈现方式

全景图像 观看视角

上图展示了全景图像的呈现方式,不同于平面,全景图像需将观景点放在球心,站在球心观看球面上的图像。最终将 曲面ABCD 在 平面ABCD 上的投影显示到屏幕上。

小结
这部分内容在实现上涉及到很多 OpenGL 的内容,需要具备一些 OpenGL 的基础。在双眼模式下还需要做 畸变校正 和 色散校正 来保证画面被真实的还原。具体实现可以查看 SGGLViewController。

SGFFPlayer 运作流程

SGFFPlayer 运作流程

上图展示了 SGFFPlayer 的协作流程图,下面简单介绍图中各组件

线程模型
SGFFPlayer 中共有4个线程。与图中4个蓝色圆圈对应。

  • 数据读取 - Read Packet Loop

  • 视频解码 - Video Decode Loop

  • 视频绘制 - Video Display Loop

  • 音频播放 - Audio Playback Loop
    图中隐藏掉了线程的控制条件。在4个线程的协作下完成整个播放过程。

SGVideoDecoder
SGVideoDecoder 是视频解码器,初始化时可配置同步、异步解码,以及是否开启硬解。上图中采用的是异步解码,默认的解码线程对应关系如下表所示。

解码 平面 全景
软件解码 异步 同步
硬件解码 异步 异步

同步解码在收到视频包后立即解码,并存入视频帧队列。
异步解码在收到视频包后仅存入音频包队列,当独立的解码线程取出音频包并完成解码后,再存入视频帧队列。

SGAudioDecoder
SGAudioDecoder 是音频解码器,采用同步解码,收到音频包后立即解码,并存入音频帧队列。

数据队列 SGFFPacketQueue、SGFFFrameQueue
SGFFPacketQueue 是包队列,用于管理解码前的数据包(AVPacket)。
SGFFFrameQueue 是帧队列,用于管理解码后的帧(SGFFVideoFrame 或 SGFFAudioFrame)。
它们都支持数据的同步获取和异步获取,同步获取是通过条件变量(NSCondition)实现。当队列中没有足够数据时,会阻塞当前线程,直到向队列中添加新元素时,线程才会被唤醒。

帧复用池 SGFFFramePool
该部分并没有在上图中体现,但能避免一些不必要的性能开销。由于音频帧和视频帧的数量很大,1分钟的视频就包含几千帧的数据。如果每一帧都新创建的话会造成不必要的资源浪费。通过 SGFFFramePool 创建的 SGFFFrame 在使用完成后不会立即释放,而是被复用池回收,以供下次使用,达到仅创建最小数量的帧对象的目的。

音视频同步
常用的同步当时有3种

  • 音频时钟

  • 视频时钟

  • 自制时钟

在 SGFFPlayer 中,优先使用音频时钟,当视频中没有音轨时,会使用视频时钟进行同步。

小结
了解了各组件的功能,以视频异步解码为例,重新梳理一下整个流程

  • 数据读取线程读取到数据包,根据数据包类型分发给音频解码器或视频解码器。

  • 如果为音频包,音频解码器收到音频包的同时进行解码,并将解码后的音频帧存入音频帧队列。

  • 如果为视频包,由于视频解码器是异步解码,仅将视频包放入视频包队列,等待视频解码线程来队列中取视频包。

  • 视频解码线程循环从视频包队列中取出视频包,同时解码,并将解码后的视频帧存入视频帧队列。

  • 音频播放线程循环在音频帧队列中取出音频帧并播放。

  • 视频展示线程循环在视频帧队列中取出视频帧并绘制。

到这里SGFFPlayer的运作流程已经很清晰了,只需在各个环节中加入对应的条件控制,就可以完成播放功能了。

总结
关于 SGPlayer 的原理就阐述到这里,由于本文以理论为主,所以并没有贴代码。感兴趣的同学可以在 GitHub 上找到全部的代码实现。希望对大家能有所帮助。

原创作者:程序员Single
原文链接:https://www.jianshu.com/p/0b3f886b6be0
校验:逆流的鱼yuiop

一种支持多种流媒体协议的播放内核相关推荐

  1. Live Streaming Protocol--三种主流的流媒体协议MEPG DASH,HLS,Smooth Streaming及其manifest 文件字段解释

    文章目录 MPEG DASH协议 Manifest.mpd 1. Manifest.mpd简介 2. Manifest.mpd字段 HLS协议 1. manifest.m3u8字段 2. ts文件 s ...

  2. netty 支持多种通讯协议

    通讯协议,指的是把Netty通讯管道中的二进制流转换为对象.把对象转换成二进制流的过程.转换过程追根究底还是ChannelInboundHandler.ChannelOutboundHandler的实 ...

  3. EasyPlayer开源流媒体移动端播放器推出RTSP-RTMP-HTTP-HLS全功能Pro版

    EasyPlayerPro介绍 Android EasyPlayerPro专业版全功能播放器,是由EasyDarwin开源团队维护的一款支持RTSP.RTMP.HTTP.HLS多种流媒体协议的播放器版 ...

  4. RTMPLive多流媒体协议转无插件直播协议(RTMP)解决方案

    随着互联网以及科技水平的发展,对于互联网服务,PC不再是唯一选择,智能手机.平板电脑.特定的移动终端等都是可选择的用户终端硬件方式,因此,我们需要一款能将安防协议,电视广播协议以及其他各种格式的流媒体 ...

  5. SkeyeRTMPLive多流媒体协议转无插件直播协议(RTMP)解决方案

    随着互联网以及科技水平的发展,对于互联网服务,PC不再是唯一选择,智能手机.平板电脑.特定的移动终端等都是可选择的用户终端硬件方式,因此,我们需要一款能将安防协议,电视广播协议以及其他各种格式的流媒体 ...

  6. Mocha NTA基于单采集器实现的多种流协议分析

    业内主流的Flow协议技术         网络业界基于流(Flow)的分析技术主要有NetFlow.sFlow.cFlow和NetStreem四种.NetFlow是Cisco公司的独有技术,它既是一 ...

  7. 三种主流流媒体协议比较

    一.介绍 在流媒体协议中,常用的流媒体协议主要有 HTTP协议,RTSP协议和RTMP协议. 在国内视频网站多采用HTTP+MP4或者HTTP+FLV协议传输视频,而国外使用RTMP,RTSP等专门的 ...

  8. 设计并实现同时支持多种视频格式的流媒体点播系统

    我之前有篇文章介绍过如果实现一个C/S模式的Flv点播系统,Flv格式简单,处理起来也比较轻松,不过,实际工作中,需要点播的影片,岂会只有Flv这一种格式.我们常见的几种视频格式,随便哪一个都要比Fl ...

  9. android能播放4k视频格式,安卓APP,无广告支持多种格式的万能视频播放器

    原标题:安卓APP,无广告支持多种格式的万能视频播放器 万能视频播放器 万能视频播放器是一款专业的视频播放工具.它支持所有视频格式,支持 4K/超高清视频文件,并且能够高清播放.它是安卓手机和平板上欣 ...

  10. LiveNVR监控流媒体Onvif/RTSP功能支持海康摄像头通过海康SDK接入支持回看倍速播放海康设备存储的设备录像

    LiveNVR功能支持海康摄像头通过海康SDK接入支持回看倍速播放海康设备存储的设备录像 1.流媒体服务说明 2.支持海康SDK接入 3.查看设备录像 3.1.时间轴模式 3.2.列表模式 4.RTS ...

最新文章

  1. h3c l2tp ***配置
  2. python迷宫小游戏代码_C++课程设计迷宫小游戏
  3. 《分布式操作系统》知识点(29~34)五
  4. PMCAFF问答龙虎榜,大神云集,等你挑战
  5. VTK:几何对象之Point
  6. byte初始化并赋值_一位数组的定义、赋值和初始化.note
  7. 徐汉字java字符_汉字徐的拼音部首-汉字徐的笔画和解释-汉字徐在线查新华字典...
  8. sts中给项目添加服务器,sts创建java web项目
  9. HDU3791 二叉搜索树【二叉搜索树】
  10. STL 算法接口及用法说明 (二)
  11. ASP.NET 2.0的编译行为
  12. 人工智能AI - 学习/实践
  13. 支付宝手机网站支付,错误代码 insufficient-isv-permissions 错误原因: ISV权限不足
  14. 【3dmax千千问】食住玩初学3dmax插件神器第24课:3dmax自学渲染效果图教程|疯狂模渲大师、室内设计师、效果图绘图员都应该如何认识VRAY或扫描线CORONA渲染器及其VR核心算法的作用?
  15. excel中多条件求和_在Excel中求和的7种方法
  16. 《统计学习方法》(李航)的学习体会(一)
  17. 业绩差距拉大 11家消费金融公司座次洗牌
  18. 物联网毕业设计 - 智能运动计步系统(物联网 嵌入式 单片机 stm32)
  19. 【最新技术早知道】PCIe Gen5 还没用上,Gen6 就来了?PCIe 6.0 系列文章之:《PCIe 6.0,到底 6 在哪?》
  20. java ctr_java – CTR模式使用初始向量(IV)

热门文章

  1. java-Aspose.Words的使用(Office文档转为PDF)
  2. Ubuntu下安装qt57creator-plugin-ros,在QT中进行ROS开发(亲测有效)
  3. 数据结构开发(11):双向循环链表的实现
  4. C++的string类
  5. objective-c 中的关联介绍
  6. ASP.net C# EVal关于前端绑定
  7. 001.XE3添加TPerlRegEx
  8. 【VC++类型转换】string转换为CString
  9. 用虚拟串口进行串口调试
  10. 智能优化算法:水基湍流优化算法-附代码