首先要提醒一句:这个问题不适合胆小的人。这是我最近遇到的一个有趣的挑战。看看你是否可以解决它或以任何方式帮助接近答案,风险自负。
问题是:在里面创建一个标准UIWebView
的iOS应用程序。从任一相机获取相机流。以可以呈现为HTML5画布的格式发送每个帧。有效地实现这一点,以便在iOS7设备中以720p 30fps或更高的速度显示视频流。
到目前为止,我还没有找到任何看起来有意义的解决方案。事实上,我从一个看起来最荒谬的解决方案开始,该解决方案在base64图像字符串中对每个帧进行编码,并通过stringByEvaluatingJavaScriptFromString
将其传递给Web视图。这是执行JPEG编码的方法
- (NSString *)encodeToBase64StringJPEG:(UIImage *)image {
return [UIImageJPEGRepresentation(image, 0.7) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
}
在viewDidLoad
内,我创建并配置捕获会话
_output = [[AVCaptureVideoDataOutput alloc] init];
// create a queue to run the capture on
dispatch_queue_t captureQueue=dispatch_queue_create("captureQueue", NULL);
// setup output delegate
[_output setSampleBufferDelegate:self queue:captureQueue];
// configure the pixel format (could this be the problem? Is this suitable for JPEG?
_output.videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA], (id)kCVPixelBufferPixelFormatTypeKey, nil];
[_session addOutput:_output];
[_session startRunning];
捕获帧并首先转换为UIImage
。
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection {
_image = imageFromSampleBuffer(sampleBuffer);
// here comes the ridiculus part. Attempt to encode the whole image and send it to JS land:
_base64imgCmd = [NSString stringWithFormat:@"draw('data:image/png;base64,%@');", [self encodeToBase64StringJPEG:_image]];
[self.webView stringByEvaluatingJavaScriptFromString:_base64imgCmd];
}
猜猜是什么,它没用。 XCode向我显示了这个错误:
DemoNativeToJS[3983:1803] bool _WebTryThreadLock(bool), 0x15e9d460: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
1 0x355435d3 WebThreadLock
2 0x3013e2f9 <redacted>
3 0x7c3a1 -[igViewController captureOutput:didOutputSampleBuffer:fromConnection:]
4 0x2c5bbe79 <redacted>
这个错误是因为WebView正在运行我们的内存qouta吗?我应该注意到崩溃前应用程序内存使用量出现大幅增长。它会在14MB到20MB之间崩溃,具体取决于JPEG编码的质量级别。
我不想用原生渲染相机流 - 这根本不是一个有趣的问题。我想将视频源传递到JavaScript域并在画布中绘制。
为了您的方便,我有一个minimal demo project (XCode) on github,您可以使用它来获取一个guick headstart:
git clone https://github.com/arasbm/DemoNativeToJS.git
如果您有其他更明智的想法来传递数据而不是使用stringByEvaluatingJavaScriptFromString
,请告诉我。如果您有其他想法或建议,请随时通过评论告诉我,但我希望答案能够通过一些代码证明哪些路径可行。
答案 0 :(得分:2)
您遇到的崩溃是由于UIWebKit尝试从后台线程调用UIKit。防止这种情况发生的最简单方法是强制stringByEvaluatingJavaScriptFromString,它调用UIKit在主线程中运行。您可以通过更改
来完成此操作[self.webView stringByEvaluatingJavaScriptFromString:_base64imgCmd];
到此
[self.webView performSelectorOnMainThread:@selector(stringByEvaluatingJavaScriptFromString:) withObject:_base64imgCmd waitUntilDone:NO];
现在将从主执行线程调用UIKit,这将是安全的。