iOS 端屏幕录制开发指南
一、 概述
实现直播过程中共享屏幕分为两个步骤:屏幕数据采集和流媒体数据推送。前对于 iOS 来说,屏幕采集需要系统的权限,受制于 iOS 系统的限制,第三方 app 并没有直接录制屏幕的权限,必须通过系统的功能来实现。
本文将描述 iOS 系统的屏幕共享的应用、实现、限制、实现细节等方面调研结果。(注:由于 iOS 10 和之前的系统只支持 App 内录制屏幕,所以只做简单的介绍,不做详细说明)
二、 应用
屏幕共享早起出现在视频会议当中,后来在一些游戏直播中也出现了大规模应用,Apple 早期不支持屏幕共享,但随着直播的盛行,Apple 也是根据用户的需求,给予了屏幕共享的支持,推出了 ReplayKit 库来迎合这种场景。
市面上的屏幕共享的场景大致分类如下:
一、:远程操作屏幕 :辅助他人对手机进行操作。如年轻人帮组老年人进行远程设置,客服帮组客户解决软件故障或者使用帮组,有效的解决语言表述低效的问题。
二、:游戏直播:知名游戏主播可以把手机上玩游戏的画面直播给其他人,可以进行游戏教学,游戏解说,让其他人更好的学习游戏技巧。
三、:视频会议,开会房把手机内容给他人观看进行解说,如手机中的邮件内容、图片、文档等,方便参会方快速共享信息,提高沟通效率。
三、 各系统实现屏幕共享
iOS 系统上实现屏幕共享的技术,主要在于系统各个版本的差异,下面将针对各个系统版本实现方式和限制性等方面进行比较。首先,由于需要使用手机的相机和麦克等硬件,无法在模拟器上调试使用。首先我们了解下目前各个版本的覆盖率情况。
系统覆盖率
根据苹果官网的数据显示,截止到 2021 年 6 月,iOS 系统各个系统版本占有率大致如下图所示,可见,目前 iOS13 及以下系统的用户覆盖率不足 2%,而 iOS14 系统的覆盖率约为 90%,iOS13 系统的覆盖率约为 8 %。顾为了兼顾老版本,目前市面上应用一般会兼容到 iOS 9。
iOS 8
iOS8 以及以前的版本,系统没有提供相应的功能,通过破解系统的功能调用私有的 API 来实现。由于 iOS8 太过古老而且运行 iOS8 系统的设备也基本上支撑不起来直播的功能,我们这里不做详细讨论,有兴趣的可以研究一下。
iOS 9 系统
Apple 在 iOS 9 推出了 ReplayKit 框架,提供了录屏功能,但是限制是只能录制本 App 内的屏幕。录制完成后会生成一个视频文件,只能通过 RPPreviewViewController 来预览,编译生成的文件,录制过程中无法获取数据,只能将最终录制完毕的整个 mp4 文件提供给开发者,所以实际上并非真正的屏幕的直播共享,无法保证实时性。
iOS 10 系统
iOS 10 Apple 推出了 Broadcast Upload Extention 和 Broadcast Setup UI Extention,来解决录屏的问题。
首先介绍一下 App Extension,官方文档(Extension的官方文档)。Extension 是对 App 的扩展,在一定程度上打破了沙盒的限制,提供了应用间通信的可能。Extension 是一个独立运行的进程,有自己的生命周期。下图所示:
虽然 iOS 10 系统解决了之前系统的一系列弊病,但是仍然没能解决只能录制当前 app 的屏幕内容的问题,这样会限制一些应用的使用场景。
iOS 11 系统
iOS 11 的发布正式直播兴盛的年代,为了迎合市场需求,Apple 提供了跨 app 录屏的功能,可以实现录取整个屏幕的功能。 虽然 ReplayKit2 已经可以满足开发者的多数需求,但是对于用户来说,这个版本在实现屏幕直播时,需要用户提前在手机设置中配置出屏幕录制的访问控制权限,使屏幕录制按钮显示在系统的上拉管理菜单中,并且在录制时,上拉底部菜单调出快捷管理菜单,并且长按屏幕录制圆形按钮才能开始录制和直播。复杂的操作流程,让用户使用的门槛增高。所以在 iOS 11 上屏幕共享功能也显得很单薄。
iOS12 系统
iOS 12 在 iOS11 的基础上进行了优化,并提供了 RPSystemBroadcastPickerView,解决了录制屏幕,用户无需在控制中心手动启动。
总结
结合上面 iOS 各个系统版本对屏幕录制的限制的分析,从版本稳定性和发布可靠性角度来说,我们应该从 iOS12 系统开始提供屏幕录制功能,而之前的系统版本不做兼容。如果只录制 app 页面进行直播,那么系统可兼容到 iOS 9。
四. 屏幕共享注意事项
由于 iOS 手机屏幕分辨率较高,考虑到内存占用和传输效率,需要对采集图像和处理过程进行优化,一般限制分辨率在 720P 以内。
Extension 子进程有 50M 内存限制,当在该线程内存超过 50M 会导致程序崩溃,就是由于这个限制,业界相似的处理方案都会限制其视频质量不超过 720P,高端机型的视频针数保持在 30 之内,低端机型视频帧率保持在 10 之内。
子进程崩溃会导致页面一直弹提示框,用户只能重启手机来解决该问题。
子进程和 host app 通信,需要看传输的内容选择不同的形式:
1、通过配置 app group 的方式共享文件或者 UserDefault。
2、进程间通知:CFNotificationCenter,一般开启关闭等可以通过通知实现。
3、通过 Socket 传输,像屏幕分享这样的场景比较适合这么做。
五. anyRTC 屏幕共享实现
anyRTC 视频屏幕共享可有两种实现方式:
一种是在 Extension 子进程中通过 Socket 传输发送屏幕共享视频数据到 host app 中,host app 中以自采集 Push 的方式向 SDK 塞流,该方式只能传输一路视频流,要么屏幕共享要么摄像头的视频流。
一种是在 Extension 子进程中初始化 SDK, 拉流设置为不订阅其他人的音频和视频,只做发送端。该方式实现了一个客户端可以发送自己的摄像头的视频流,也可以发送屏幕共享的流,只是以两个 uid 进入同一个频道的形式。
本地 Socket 传输到 host app
思路参考:博客
大致的思路是:本地起一个 socket,通过 tcp 的形式传输到 host app,复杂的操作在 host app 中进行,有效解决 Extension 50M 的限制问题。
子进程中直接使用 SDK
思路:在 Extension 中直接使用 SDK ,只做发流,不接收流。同时也要注意 Extension 50M 的问题(1:应用限制横竖屏直播,要么横盘、要么竖屏,应用横竖屏切换容易导致内存突增。2:低性能机器限制视频的帧率(1~10 帧))
1.初始化
设置频道属性为直播模式,并设置为主播角色,启用视频模块
2.设置屏幕共享的分辨率
由于子进程中有 50M 限制,为了系统的稳定性建议分辨率不要设置超过 720P
根据屏幕的宽高,跟分辨率做换算,计算出最佳的分辨率输出
视频的帧率,如果在低端机型下,建议设置 5 帧,高端机器不要超过 30 帧
屏幕共享的清晰度,可以适当调整 bitrate,建议不要超过 1800
3.设置使用外部音视频源
设置使用外部视频源采集,打开后内部采集自动关停
设置使用外部音频源采集,打开后内部音频采集自动关停
4.禁止接收音视频
作为屏幕共享端只需要发流,不需要接收流。
5.加入频道
获取 host app 中的用户 Id,在进行一层组装,标记为某个人的辅流
获取 host app 中正在使用的频道 Id,开始屏幕共享的时候以该用户的辅流的形式进入频道
6.发流
RPSampleBufferTypeVideo:获取视频数据,并使用外置塞流接口把视频数据发送出去
RPSampleBufferTypeAudioApp:获取应用内的声音源,并使用外置塞流接口把音频数据发送出去
RPSampleBufferTypeAudioMic:获取麦克风声音源,并使用外置塞流接口把音频数据发送出去
视频塞流,需要对视频数据进行组装,视频类型、时间戳、旋转角度等信息
经过上述步骤,便可实现屏幕共享功能。为了方便开发者更能快速上手,可以参考 demo 快速上手。
版权声明: 本文为 InfoQ 作者【anyRTC开发者】的原创文章。
原文链接:【http://xie.infoq.cn/article/57ab5af442776cce414527085】。文章转载请联系作者。
评论