注册

GPUImage recalculateViewGeometry卡UI线程的问题

原因:
更新xocde11.4之后发现GPUImage视频画面渲染特别慢,并且控制台输出如下信息:

Main Thread Checker: UI API called on a background thread: -[UIView bounds]
PID: 7360, TID: 1812926, Thread name: (none), Queue name: com.sunsetlakesoftware.GPUImage.openGLESContextQueue, QoS: 0
Backtrace:
4 KXLive 0x0000000100e12e60 __39-[GPUImageView recalculateViewGeometry]_block_invoke + 52
5 KXLive 0x0000000100dec788 runSynchronouslyOnVideoProcessingQueue + 108
6 KXLive 0x0000000100e12e0c -[GPUImageView recalculateViewGeometry] + 108
7 KXLive 0x0000000100e13804 __37-[GPUImageView setInputSize:atIndex:]_block_invoke + 312
8 KXLive 0x0000000100dec788 runSynchronouslyOnVideoProcessingQueue + 108
9 KXLive 0x0000000100e136ac -[GPUImageView setInputSize:atIndex:] + 136
10 KXLive 0x0000000100e0ee38 -[GPUImageVideoCamera updateTargetsForVideoCameraUsingCacheTextureAtWidth:height:time:] + 660
11 KXLive 0x0000000100e0fb48 -[GPUImageVideoCamera processVideoSampleBuffer:] + 2120
12 KXLive 0x0000000100e106c4 __74-[GPUImageVideoCamera captureOutput:didOutputSampleBuffer:fromConnection:]_block_invoke + 180
13 libdispatch.dylib 0x0000000105e5d260 _dispatch_call_block_and_release + 24
14 libdispatch.dylib 0x0000000105e5d220 _dispatch_client_callout + 16
15 libdispatch.dylib 0x0000000105e6be80 _dispatch_queue_serial_drain + 768
16 libdispatch.dylib 0x0000000105e60730 _dispatch_queue_invoke + 328
17 libdispatch.dylib 0x0000000105e6cdd8 _dispatch_root_queue_drain_deferred_wlh + 352
18 libdispatch.dylib 0x0000000105e73ebc _dispatch_workloop_worker_thread + 676
19 libsystem_pthread.dylib 0x0000000181e6fe70 _pthread_wqthread + 860
20 libsystem_pthread.dylib 0x0000000181e6fb08 start_wqthread + 4

意思是在子线程中UIView对象调用了bounds ,导致视频画面迟迟渲染不出来。
查找发现GPUImageView的视频渲染类的

(void)recalculateViewGeometry;

方法中有两处调用了bounds。
解决办法:
在GPUImageView中声明一个属性viewBounds来保存view的bounds值,在- (void)layoutSubviews方法中给viewBounds赋值,用viewBounds代替bounds就可以了,此时可以很快的调起摄像头并且渲染出画面。

- (void)layoutSubviews {
[super layoutSubviews];
self.viewBounds = self.bounds;
// The frame buffer needs to be trashed and re-created when the view size changes.
if (!CGSizeEqualToSize(self.bounds.size, boundsSizeAtFrameBufferEpoch) &&
!CGSizeEqualToSize(self.bounds.size, CGSizeZero)) {
runSynchronouslyOnVideoProcessingQueue(^{
[self destroyDisplayFramebuffer];
[self createDisplayFramebuffer];
[self recalculateViewGeometry];
});
}
}

- (void)recalculateViewGeometry;
{
runSynchronouslyOnVideoProcessingQueue(^{
CGFloat heightScaling, widthScaling;

CGSize currentViewSize = self.viewBounds.size;

// CGFloat imageAspectRatio = inputImageSize.width / inputImageSize.height;
// CGFloat viewAspectRatio = currentViewSize.width / currentViewSize.height;

CGRect insetRect = AVMakeRectWithAspectRatioInsideRect(inputImageSize, self.viewBounds);
在xcode11和iOS13开始,系统对在子线程中做UI操作要求更加严格。千万不要在子线程中使用与UI相关的代码

作者:那月无痕
链接:https://www.jianshu.com/p/15cc2cd3a862




0 个评论

要回复文章请先登录注册