将视频流从iOS7摄像头发送到web视图中的JavaScript画布

将视频流从iOS7摄像头发送到web视图中的JavaScript画布,javascript,ios,objective-c,canvas,uiwebview,Javascript,Ios,Objective C,Canvas,Uiwebview,首先要提醒一句:这个问题不适合心脏虚弱的人。这是我最近遇到的一个有趣的挑战。看看你是否能解决这个问题或以任何方式帮助接近答案,风险由你自己承担 问题是:创建一个内部带有标准UIWebView的iOS应用程序。从任一摄像机获取摄像机流。以可以呈现到HTML5画布中的格式发送每个帧。有效地实现这一点,以便在iOS7设备中以720p 30fps或更高的速度显示视频流 到目前为止,我还没有找到任何看似可行的解决方案。事实上,我从看起来最可笑的解决方案开始,该解决方案将每个帧编码为base64图像字符串,

首先要提醒一句:这个问题不适合心脏虚弱的人。这是我最近遇到的一个有趣的挑战。看看你是否能解决这个问题或以任何方式帮助接近答案,风险由你自己承担

问题是:创建一个内部带有标准
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>

如果您有其他更明智的想法来传递数据,而不是使用
stringByEvaluatingJavaScriptFromString
,请告诉我。如果您有其他想法或建议,请随时在评论中告诉我,但我希望答案能用一些代码演示什么路径可行。

您遇到的崩溃是由于UIWebKit试图从后台线程调用UIKit造成的。防止这种情况发生的最简单的方法是通过EvaluatingJavaScriptFromString强制stringByEvaluatingJavaScriptFromString,它正在主线程中运行对UIKit的调用。您可以通过更改

[self.webView stringByEvaluatingJavaScriptFromString:_base64imgCmd];
对此

[self.webView performSelectorOnMainThread:@selector(stringByEvaluatingJavaScriptFromString:) withObject:_base64imgCmd waitUntilDone:NO];

现在将从主执行线程调用UIKit,这将是安全的。

我现在在画布上以大约5FPS的速度观看视频,这并不理想,但这是向前迈出的一大步。非常感谢。您好,您找到如何改进fps了吗?@WorieN是的,但这是很久以前的事了,我不知道我做了什么,而且它可能不会适用于当前版本的SDK。祝你好运
[self.webView performSelectorOnMainThread:@selector(stringByEvaluatingJavaScriptFromString:) withObject:_base64imgCmd waitUntilDone:NO];