iOS11 ReplayKit2 问题总结
一、苹果自6月30日发布iOS11系统之后,其中的Airplay的协议发生变更,导致市场上的苹果直播助手(录屏)大部分变得不可用,因此在iOS11之后需要寻找新的技术方案来录屏
1)采用系统提供的ReplayKit2 包含的System Screen Record的框架
2) 采用libUSB的方案,这个方案利用的苹果的USB协议,github上面已经存在一个库,据说比较难编译,国外的直播平台Mobcrush,体验了一下效果非常好。
二、采用苹果的提供的方案才是正途,不然以后每次升级去破解Airplay的协议太折腾,也不经济。下面总结遇到的一些难题
1)ReplayKit2 本身存在bug,在不断更新的beta版本中,一直存在框架回调视频帧时序错位、声音消失,无法正常启动框架必须重启
2)ReplayKit2 开发Xcode调试很难,每次启动调试,Xcode调试器默认挂起的是主App,如果你需要调试一个一启动就发生的问题,很可能进程直接结束了,调试器什么信息都没有,吐槽Xcode
苹果这么大的市值,到底拿出多少钱用于研发测试,大概以大众为测试,这种态度一定会没落!!!
3)ReplayKit2 直到正式版本中存在的问题,内存不能超过50MB,如果一超过,系统马上干掉你
4)ReplayKit2 与主App之间没有进程通信机制(重大缺陷),直播平台一般主播都有自己的账号,直播权限,弹幕,礼物,苹果只考虑推流么??并且推的流还只能是竖屏,需要hack解决
三、一些经验
1)内存不能超过50MB
在系统回调给你的YUV数据(NV12格式)中,这个回调在多个线程,之前为了避免时序的问题,将回调统一调度到一个串行队列中:
1 2 3 4 5 6 7 8 9 | if ([_txLivePush isPublishing]){ __weak typeof( self ) wSelf = self ; CFRetain(videoSample); dispatch_async(_encodeQueue, ^{ [wSelf NV12ToI420AndRotate:videoSample]; // [_txLivePush sendVideoSampleBuffer:videoSample]; CFRelease(videoSample); }); |
这里带来一个问题,大屏手机在按home键的过程中,upload进程的线程调度受到影响,导致视频数据在队列中积压,内存峰值一旦超过50MB,系统立马把你杀掉
所以在视频的数据流中,一定要注意缓冲区的长度,申请内存一般不要超过3MB,采用同步的方案更可控一些
2)隐私模式
隐私模式就是将系统给的数据替换成一张YUV图片,通常涉及给到的是PNG、JPG
这里需要将JPG->UIImage->pix Data -> YUV I420
下面是一些介绍:
PG->UIImage->pix Data
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | + (unsigned char *)pixelARGBBytesFromImageRef:(CGImageRef)imageRef { NSUInteger iWidth = CGImageGetWidth(imageRef); NSUInteger iHeight = CGImageGetHeight(imageRef); NSUInteger iBytesPerPixel = 4; NSUInteger iBytesPerRow = iBytesPerPixel * iWidth; NSUInteger iBitsPerComponent = 8; unsigned char *imageBytes = malloc(iWidth * iHeight * iBytesPerPixel); CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGContextRef context = CGBitmapContextCreate(imageBytes, iWidth, iHeight, iBitsPerComponent, iBytesPerRow, colorspace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); CGRect rect = CGRectMake(0 , 0 , iWidth , iHeight); CGContextDrawImage(context , rect ,imageRef); CGColorSpaceRelease(colorspace); CGContextRelease(context); CGImageRelease(imageRef); return imageBytes; } |
上面的方法将UIImage转成ARGB的格式,因为libyuv中有一个ARGBToI420的方法。上面的方法中注意选项
1 2 3 4 5 6 7 8 | kCGImageAlphaNone, /* For example, RGB. */ kCGImageAlphaPremultipliedLast, /* For example, premultiplied RGBA */ kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */ kCGImageAlphaLast, /* For example, non-premultiplied RGBA */ kCGImageAlphaFirst, /* For example, non-premultiplied ARGB */ kCGImageAlphaNoneSkipLast, /* For example, RBGX. */ kCGImageAlphaNoneSkipFirst, /* For example, XRGB. */ kCGImageAlphaOnly |
控制颜色通道的顺序,数据的大小端
转好的数据,再转成I420
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | //ToI420 CVReturn rc = CVPixelBufferCreate( NULL , imgSize.width, imgSize.height, kCVPixelFormatType_420YpCbCr8PlanarFullRange, NULL , &_pausePixBuffer); rc = CVPixelBufferLockBaseAddress(_pausePixBuffer, 0); uint8_t *y_copyBaseAddress = (uint8_t*)CVPixelBufferGetBaseAddressOfPlane(_pausePixBuffer, 0); uint8_t *u_copyBaseAddress = (uint8_t*)CVPixelBufferGetBaseAddressOfPlane(_pausePixBuffer, 1); uint8_t *v_copyBaseAddress = (uint8_t*)CVPixelBufferGetBaseAddressOfPlane(_pausePixBuffer, 2); size_t dYLineSize = (size_t)CVPixelBufferGetBytesPerRowOfPlane(_pausePixBuffer, 0); size_t dULineSize = (size_t)CVPixelBufferGetBytesPerRowOfPlane(_pausePixBuffer, 1); size_t dVLineSize = (size_t)CVPixelBufferGetBytesPerRowOfPlane(_pausePixBuffer, 2); tx_ARGBToI420(argbData, imgSize.width*4, y_copyBaseAddress, ( int )dYLineSize, u_copyBaseAddress, ( int )dULineSize, v_copyBaseAddress, ( int )dVLineSize, ( int )imgSize.width, ( int )imgSize.height); free(argbData); |
1 | kCVPixelFormatType_420YpCbCr8PlanarFullRange 代表I420的格式 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库