Skip to content
hzwangsiyu edited this page Mar 30, 2016 · 1 revision

PLPlayerKit 开发指南

内容

1 概述

PLPlayerKit 是一个适用于 iOS 的 HLS 及 RTMP 播放 SDK,可高度定制化和二次开发。特色是支持 RTMP 协议下 H.264 编码 FLV 封装的多媒体流的播放,针对与用户体验密切相关的首开缓冲时间进行了优化,另外还根据移动网络的多变性以及直播场景对播放实时性的需求提供了跳帧机制。

2 阅读对象

本文档为技术文档,需要阅读者

  • 具有基本的 iOS 开发能力
  • 准备接入七牛云直播

3 SDK 最低要求

  • iOS 7
  • iPhone 4s 及以上设备

4 功能及特点

功能 描述
支持 RTMP 协议直播播放 保证秒级实时性
提供 H.264 视频解码 多种 profile level 支持
提供 AAC、MP3 等多种音频解码 适配更多音频编码
支持双声道音频 更好的听觉体验
支持首屏秒开 更好的播放体验
支持弱网情况下跳帧机制 更好地满足直播场景的实时性需求
提供 HeaderDoc 文档 开发中使用 Quick Help 及时阅读文档
支持 ARM7, ARM64 指令集 为最新设备优化
支持模拟器运行 不影响模拟器快速调试

5 前置条件

  • 已注册七牛账号
  • 通过 pili@qiniu.com 申请并已开通直播权限

6 快速开始

6.1 准备工作

6.2 使用 CocoaPods 导入 SDK

PLPlayerKit 只支持 CocoaPods 的方式添加。

  • 在工作目录中创建名称为 Podfile 的文件
  • 在 Podfile 中添加如下一行
pod 'PLPlayerKit'
  • 在终端中运行
$ pod install

$ pod update

到此,你已完成了 PLPlayerKit 的依赖添加

6.3 初始化播放逻辑

6.3.1 创建播放器用的 ViewController

  • 创建 View Controller 如图所示,

  • 选择subclass为 UIViewController,如图所示

6.3.2 添加引用

  • PLPlayerViewController.m 中添加引用
#import <PLPlayerKit/PLPlayerKit.h>

6.3.3 添加声明属性

PLPlayerViewController.h 头文件中声明支持 PLPlayerDelegate,并添加一个 PLPlayer 的属性,添加完后如下

#import <UIKit/UIKit.h>
#import <PLPlayerKit/PLPlayerKit.h>
@interface ViewController : UIViewController <PLPlayerDelegate>
@property (nonatomic, strong) PLPlayer  *player;
@end

6.3.4 添加 App Transport Security Setting

  • 如图所示

6.3.5 创建对象

  • PLPlayerViewController.m 文件中,在 - (void)viewDidLoad 方法内实例化 PLPlayerOption 对象并改变所需设置的属性值用于初始化 PLPlayer 的相关配置参数并且实用实例化 PLPlayer,并且指定 delegate,特别说明的是,在创建 PLPlayer 时,我们要用到播放的 url,我假设你已经知道了直播对应的 rtmp 播放地址。
PLPlayerOption *option = [PLPlayerOption defaultOption];
[option setOptionValue:@15 forKey:PLPlayerOptionKeyTimeoutIntervalForMediaPackets];
NSURL *url = [NSURL URLWithString:@"直播的 rtmp 地址"];
self.player = [PLPlayer playerWithURL:self.URL option:option];
self.player.delegate = self;
  • 在创建完 player 后,我们将播放界面添加到当前视图
[self.view addSubview:self.player.playerView];

6.4 开始播放

取一个简单的场景,就是当 PLPlayerViewController 加载完成即开始播放,那么我们在 - (void)viewDidLoad 方法内添加

[self.player play]

这样在直播推流开始后,运行代码就可以看到直播流了。

7 高级功能

当你要深入理解 SDK 的一些参数及有定制化需求时,可以从高级功能部分中查询阅读,以下小节无前后依赖。

7.1 播放器可选配置项

PLPlayerKit 中通过初始化时传入不同配置的 PLPlayerOption 对象来设置不同的播放器可选配置项信息,对应的有

KEY value 类型 描述
PLPlayerOptionKeyTimeoutIntervalForMediaPackets NSNumber 播放器所用 RTMP 连接的超时断开时间长度,单位为秒

7.2 后台播放配置

PLPlayerKit 提供后台播放支持,开发者可以实现后台与前台播放的无缝切换。

7.2.2 配置 Required background modes

  • 配置如图所示

7.2.2 设置 player 相关属性支持后台播放

self.player.backgroundPlayEnable = YES;

done!

这样, PLPlayer 便支持后台播放了。 需要注意的是在后台播放时仅有音频,视频会在回到前台时继续播放。

7.3 跳帧策略

下面我们来看看跳帧策略

7.3.1 什么是跳帧策略

跳帧策略是指在播放累积延迟逐渐增大时采取的 " 丢弃非实时数据 " 的策略,播放累积延迟是由于缓存不足或其他原因导致的播放暂停而后继续播放会优先播放暂停之前未播放的非实时数据,而实时数据进入缓存队列造成的播放端播放的音视频数据与实时数据之间的时间差,而跳帧策略则是指当播放器发现播放累积延迟超过一定阈值时触发的 " 丢弃非实时数据 " 的策略。

7.3.2 为什么要采取跳帧策略

原因非常简单,就是为了保证播放的实时性需求。

直播作为有别于录播的富媒体传播手段,它的第一要素就是实时,没有了实时,直播的价值就会荡然无存。除了实时性以外,非实时数据堆积造成的内存增加也是不得不考虑的问题,在移动设备有限的内存条件之下,我们应该尽可能保证比较小的内存占用率。跳帧策略能够在保证实时性需求的同时减少播放的内存占用率,因此我们有必要采取跳帧策略。

7.3.3 利弊

丢帧策略固然保证了直播的实时性,但是它的弊端也是显然的,就是会导致信息的丢失,观众在观看过程中如果发生暂停,那么继续播放的时候暂停期间的音视频信息观众将无法观看到。

因此,我们建议开发者从产品层面考虑直播的实时性与观众获取到的直播的完整性的取舍问题。

7.4 播放状态获取

PLPlayerKit 中,通过反馈 PLPlayer 的状态来反馈流的状态。我们定义了几种状态,确保 PLPlayer 对象在有限的几个状态间切换,并可以较好的反应流的状态。

状态名 含义
PLPlayerStatusUnknow 初始化时指定的状态,不会有任何状态会跳转到这一状态
PLPlayerStatusPreparing 播放器正在准备当中
PLPlayerStatusReady 播放器准备完成的状态
PLPlayerStatusCaching 播放器正在缓存的状态
PLPlayerStatusPlaying 播放器正在播放的状态
PLPlayerStatusPaused 播放器暂停的状态
PLPlayerStatusStopped 播放器播放结束或手动停止的状态
PLPlayerStatusError 播放器出现错误的状态

7.4.1 state 状态回调

state 状态对应的 Delegate 回调方法是

- (void)player:(nonnull PLPlayer *)player statusDidChange:(PLPlayerStatus)state;

只有在正常连接,正常断开的情况下跳转的状态才会触发这一回调。所谓正常连接是指通过调用 -play 方法使得流连接的各种状态,而所谓正常断开是指调用 -stop 方法使得流断开的各种状态。所以只有以下四种状态会触发这一回调方法。

  • PLPlayerStatusPreparing
  • PLPlayerStatusReady
  • PLPlayerStatusCaching
  • PLPlayerStatusPlaying
  • PLPlayerStatusPaused
  • PLPlayerStatusStopped

7.4.2 error 状态回调

error 状态对应的 Delegate 回调方法是

- (void)player:(nonnull PLPlayer *)player stoppedWithError:(nullable NSError *)error;

当除了调用 -stop 之外的所有能导致流断开的情况,都被归属于非正常断开的情况,此时就会触发该回调。对于错误的处理,我们不建议触发了一次 error 后就断掉,最好可以在此时尝试调用 -play 方法进行有限次数的重连。

7.6 网络异常处理

直播中,网络异常的情况比我们能意料到的可能会多不少,常见的情况一般有

  • 网络环境切换,比如 3G/4G 与 Wi-Fi 环境切换
  • 网络不可达,网络断开属于这一类
  • 带宽不足,可能触发缓存速度跟不上播放速度

作为开发者我们不能乐观的认为只要是 Wi-Fi 网就是好的,因为即便是 Wi-Fi 也有可能因为运营商下行限制,共享网络带宽等因素导致以上网络异常情况的出现。

为何在直播中要面对这么多的网络异常情况,而在其他上传/下载中很少遇到的,这是因为直播对实时性的要求使得它不得面对这一情况,即无论网络是否抖动,是否能一直良好,直播都要尽可能是可持续,可观看的状态。

对于网络环境的切换,通常需要 App 整体做出调整,不单单是针对直播,所以 PLPlayerKit 并未对这一情况做额外的监听,而是需要开发者自己对这些状态做出处理。

7.6.1 重连

PLPlayerKit 内部不包含重连逻辑。之所以不包含,主要因素是考虑到 App 的业务逻辑场景多样而负责,对于直播重连的次数,时机,间隔都会有不同的需求,而此时应该让开发者自己来决定是否重连,以及尝试重连的次数。

当因为网络异常而触发了播放断开时,会通过 error Delegate 回调触发

- (void)player:(nonnull PLPlayer *)player stoppedWithError:(nullable NSError *)error;

你可以在这个方法内通过重新调用 -play 方法来尝试重连。此处建议不要立即重连,而是采用重连间隔加倍的方式,比如共尝试 3 次重连,第一次等待 0.5s, 第二次等待 1s, 第三次等待 2s,这样的方式主要考虑到弱网时网络带宽的缓解需要时间,而加倍重连可以更容易在网络恢复的时候连接,而非在网络已经拥塞时还不断做无用功的重连。

8 历史记录

  • 2.1.0 (Release Notes && API Diffs)
    • 此次更新为重大版本升级,更改了大量 API 并重构了包括解码渲染在内的多项内容,建议所有用户进行升级,并且根据快速开始使用新版 API 对工程重新进行配置。
    • 更改了播放器的音频解码和渲染方式
    • 更改了播放器的时钟同步机制
    • 重构了内部逻辑,使播放器更稳定
    • 重构了播放器 API ,使播放器的使用更加简单明了,去除了使用起来不方便的部分 API
    • 解决了播放过程中可能出现声音消失的问题
    • 解决了退后台返回后音视频无法正常同步的问题
    • 修改播放器音视频同步机制
    • 解决持续播放过程中出现部分内存没有正确释放的问题
    • 解决了 iOS 版本小于 8.0 时 Demo 出现的crash问题
  • 2.0.4 (Release Notes && API Diffs)
    • 解决 RTMP 播放时可能黑屏的问题
  • 2.0.3 (Release Notes && API Diffs)
    • 解决 RTMP 播放没有声音
    • 解决 RTMP 无法播放导致内存急增最终 App crash
    • 解决 RTMP 无法播放画面只有声音
    • 解决播放 RTMP 时相关的 crash 问题
  • 2.0.2 (Release Notes && API Diffs)
    • 添加 RTMP Cache 机制
    • 添加数据超时属性
    • 修复 RTMP 播放内存 leak
    • 修复 RTMP 播放音频错误问题
    • 修复 RTMP 播放主线程卡死问题
    • 优化架构,减少内存和 cpu 占用
  • 2.0.1 (Release Notes && API Diffs)
    • 修复 contentMode 设置无效的问题
    • 修复 rtmp 无法播放或播放超时时无 error 抛出的问题
    • 修复 rtmp 播放失败时触发的 cpu 飙升问题
    • 修复 stop 可能触发的 crash 问题
    • 更新 demo 确保在 iOS 9.1 下运行正常
  • 2.0.0 (Release Notes && API Diffs)
    • 添加全新的 PLPlayer,弃用 PLVideoPlayerControllerPLAudioPlayerController
    • 播放 RTMP 音视频流时,进入后台后声音继续播放,不会断开,返回前台追帧显示最新视频帧
    • 针对 RTMP 直播彻底优化,首屏秒开,最小化缓存
    • 完全无 ffmpeg 依赖,包体积再次缩小
    • 优化资源占用,比 1.x 版本内存占用减少 50% 以上
  • 1.2.22 (Release Notes && API Diffs)
    • 修复因收到内存警告而引起的崩溃问题
    • 修复停止播放时,可能进入错误 play state 的问题
  • 1.2.21 (Release Notes && API Diffs)
    • 修复 PLVideoParameterFrameViewContentModePLVideoParameterDisableDeinterlacing 设置无效的问题
  • 1.2.20 (Release Notes && API Diffs)
    • 修复 seekTo: 不准确的问题
    • 添加 PLPlayerStateSeeking 类型
  • 1.2.19 (Release Notes && API Diffs)
    • 修复播放无返回状态的问题(针对无直播的流、hls 回放)
    • 修复 hls 回放结束时无 stopped 回调的问题
    • 修复 hls 回放开始的 duration 不为 0 的问题
  • 1.2.18 (Release Notes && API Diffs)
    • 修复在 prepare 状态前释放 player 导致的音频仍然会播放的问题
    • 修复 player 状态返回的类型不正确的问题
    • 优化推出时资源释放
  • 1.2.17 (Release Notes && API Diffs)
    • 修复超时时导致的崩溃的问题
  • 1.2.16 (Release Notes && API Diffs)
    • 添加了音频播放器后台播放的支持
    • 添加了音频播放器后台播放任务开始和结束的回调
    • 添加了音视频播放器超时时长的设定
    • 添加了音视频播放器准备的方法
    • 添加了音视频完全停止播放器的方法
    • 修复播放器不可释放的问题
  • 1.2.15 (Release Notes && API Diffs)
    • 修复 AudioPlayer 无法播放带有视频流的 RTMP 流的问题
  • 1.2.14 (Release Notes && API Diffs)
    • 添加 AudioManager
  • 1.2.13 (Release Notes && API Diffs)
    • 添加纯音频播放控件
    • 更新参数字段及类型,确保通用类型可以在音频及视频播放器使用
    • 更新类型名称,增加易读性,减少歧义
  • 1.2.12 (Release Notes && API Diffs)
    • 更改 repo 地址
  • 1.2.11 (Release Notes && API Diffs)
    • 添加对应用状态的判断,减少因进入后台通知延时未能及时暂停播放导致的 crash
  • 1.2.10 (Release Notes && API Diffs)
    • 添加音频外设更改时的通知
    • 添加音量变更时的通知
    • 添加打进电话等其他事件导致音频中断的通知
  • 1.2.9 (Release Notes && API Diffs)
    • 修复进入后台后崩溃的问题
    • 更新 example 中 player 代码,支持横竖屏旋转操作
  • 1.2.8 (Release Notes && API Diffs)
    • 添加播放进度回调方法
    • 修复 seekTo 后流状态不正确的问题
  • 1.2.7 (Release Notes && API Diffs)
    • 添加播放器状态属性
    • 添加解码器初始化完成后回调
    • 添加播放器状态回调
    • 添加初始化后自动播放参数
  • 1.2.6 (Release Notes && API Diffs)
    • 添加设置播放位置的操作
    • 添加了快进、快退的操作
    • 添加总播放时长的属性
    • 添加获取音量的属性
    • 添加获取当前播放位置的属性
    • 添加静音操作
  • 1.2.5 (Release Notes && API Diffs)
    • 修复与部分其他库头文件冲突的问题
  • 1.2.4 (Release Notes && API Diffs)
    • 添加了 PLMovieParameterFrameViewContentMode 参数
    • 修复与部分其他库头文件冲突的问题
    • 修复 Player contentMode 无法更改的问题
  • 1.2.3 (Release Notes && API Diffs)
    • 修复初始化占用主线程导致卡顿的问题
    • 修复错误回调无效的问题
  • 1.2.2 (Release Notes && API Diffs)
    • 修复 lib 未更新导致的 crash
  • 1.2.1 (Release Notes && API Diffs)
    • 添加 failue 情况下的回调,返回 NSError 对象
    • 移除 PLVideoPlayerViewController,请直接使用 PLVideoPlayerController 进行定制
  • 1.2.0 (Release Notes && API Diffs)
    • 极大缩小 lib 大小
    • 增加可定制的播放控件 PLVideoPlayerController
  • 1.1.2
    • 拆分 Flat lib
    • 添加了 x86_64 支持,便于在 iPhone 6 Plus 模拟器下调试使用
  • 1.1.1
    • 对库引用做了些修改
  • 1.1.0
    • 发布 CocoaPods 版本

9 反馈及意见

当你遇到任何问题时,可以通过在 GitHub 的 repo 提交 issues 来反馈问题,请尽可能的描述清楚遇到的问题,如果有错误信息也一同附带,并且在 Labels 中指明类型为 bug 或者其他。

通过这里查看已有的 issues 和提交 Bug