void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);然後在創建上下文以pxdata 所指向的記憶體作為上下文數據存貯的容器, 最後 渲染 上下文[self.webView.layer renderInContext:context];這樣就將 we ...
近兩年一直從事視頻行業的開發, 加班也比較嚴重, 好久沒有寫文章了, 最近稍微有些時間, 前來寫點文章, 記錄一些開發中遇到的問題, 和解決方法!
做視頻會議項目, 當然是離不開音視頻啦, 也常常和WebRTC打交道, 包括編譯WebRTC, 修改源碼, 還有C++和OC的混編開發, JS交互, 也嘗試過RN的開發來避開一些問題等等, 東西很多, 路也很不好走, 通宵加班也是家常便飯, 不過現在項目基本穩定,已經上線, 用戶反饋也都很不錯! 回頭看看走過的路, 雖然坎坎坷坷, 但是也是收穫滿滿呀!
進入正題, 項目中有共用的功能, 屏幕共用使用的ReplayKit, 但是應用外的屏幕共用時是使用的Broadcast Extension, 而該擴展是另外的獨立進程, 涉及到宿主App和擴展App的信令之間的交互, 好在有比較有好的第三方使用, 省了不少事, 最終完成了屏幕共用! 如果有朋友涉及到這方面的知識的話, 可以一起交流溝通哈!
除屏幕共用外, 我們要有網頁共用, 網頁共用, 開始一臉懵逼! 後來的解決方案是, 共用人端使用WKWebView, 觀看端看的是視頻流! OK, 那麼問題來了, 如何把一個UIView 的渲染數據採集成為Buffer呢, 頭大, 最初考路過使用應用內的錄屏, 這樣是可以解決, 但是, 錄屏的話吧整個屏幕上的內容全都採集出來, 不是很友好, 用戶只想共用這個網頁, 其他的不想讓觀看者看到! 確實挺麻煩的, 查了很多資料, 也沒有特別合適的!
經過多方面研究和資料的查閱, 最終的解決方案是, 創建CVPixelBufferRef pxbuffer, 然後獲取像素基本地址
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
然後在創建上下文以pxdata 所指向的記憶體作為上下文數據存貯的容器, 最後 渲染 上下文[self.webView.layer renderInContext:context];
這樣就將 webView 視圖上的渲染數據轉成了一幀 CVPixelBufferRef 數據, 然後根據幀率設置定時器, 去不停的獲取webView的渲染數據轉換成需要像素緩衝數據!
具體的代碼如下
- (CVPixelBufferRef)CVPixelBufferRef { CGSize size = self.frame.size; NSDictionary *options = @{(NSString*)kCVPixelBufferCGImageCompatibilityKey : @YES, (NSString*)kCVPixelBufferCGBitmapContextCompatibilityKey : @YES, (NSString*)kCVPixelBufferIOSurfacePropertiesKey: [NSDictionary dictionary]}; CVPixelBufferRef pxbuffer = NULL; CGFloat frameWidth = size.width; CGFloat frameHeight = size.height; CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, frameWidth, frameHeight, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options, &pxbuffer); NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL); CVPixelBufferLockBaseAddress(pxbuffer, 0); void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer); NSParameterAssert(pxdata != NULL); CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 8, CVPixelBufferGetBytesPerRow(pxbuffer), rgbColorSpace, kCGImageAlphaPremultipliedFirst); NSParameterAssert(context); CGContextConcatCTM(context, CGAffineTransformMakeRotation(0)); CGAffineTransform flipVertical = CGAffineTransformMake( 1, 0, 0, -1, 0, frameHeight); CGContextConcatCTM(context, flipVertical); // CGAffineTransform flipHorizontal = CGAffineTransformMake( -1.0, 0.0, 0.0, 1.0, frameWidth, 0.0 ); // CGContextConcatCTM(context, flipHorizontal); [self.webView.layer renderInContext:context]; CGColorSpaceRelease(rgbColorSpace); CGContextRelease(context); CVPixelBufferUnlockBaseAddress(pxbuffer, 0); return pxbuffer; }
這或許不是最好的方法, 但目前確實解決了燃眉之急, 分享出來, 為有同樣需求的小伙伴提供一條方案, 或者小伙伴有更好的方法, 分享出來, 大家可以學習交流一下
或者上我的簡書