IOS从networking接收video

更新 – 我已经修复了下面的代码中的一些错误,图像显示在其他设备上,但我还有一个问题。 video捕捉打开时,“主”设备连续发送数据,有时这种捕捉会出现在“从属”设备上,并且在很短的时间内,图像会“闪烁”为空白并在短时间内重复播放。 任何想法呢?

我正在开发一款应用程序,需要将实时相机捕获和实时麦克风捕获发送到networking中的其他设备。

我已经完成了使用TCP服务器的设备之间的连接,并用bonjour发布它,这就像一个魅力。

最重要的部分是要发送和接收来自“主”设备的video和audio,并将其呈现在“从”设备上。

首先,这里是一段代码,让应用程序获取相机采样缓冲区,并在UIImage中进行转换:

@implementation AVCaptureManager (AVCaptureVideoDataOutputSampleBufferDelegate) - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { dispatch_sync(dispatch_get_main_queue(), ^{ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; UIImage *image = [self imageFromSampleBuffer:sampleBuffer]; NSData *data = UIImageJPEGRepresentation(image, 0.2); [self.delegate didReceivedImage:image]; [self.delegate didReceivedFrame:data]; [pool drain]; }); } - (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer { CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); CVPixelBufferLockBaseAddress(imageBuffer, 0); size_t width = CVPixelBufferGetWidth(imageBuffer); size_t height = CVPixelBufferGetHeight(imageBuffer); size_t bytesPerRow = width * 4; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer); CGContextRef context = CGBitmapContextCreate( baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little ); CGImageRef quartzImage = CGBitmapContextCreateImage(context); UIImage *image = [UIImage imageWithCGImage:quartzImage]; CGImageRelease(quartzImage); CGColorSpaceRelease(colorSpace); CGContextRelease(context); CVPixelBufferUnlockBaseAddress(imageBuffer, 0); return image; } @end 

消息“[self.delegate didReceivedImage:image];” 只是为了testing主设备上的图像捕获,并且该图像在捕获设备上工作。

接下来是关于如何将其发送到networking:

 - (void) sendData:(NSData *)data { if(_outputStream && [_outputStream hasSpaceAvailable]) { NSInteger bytesWritten = [_outputStream write:[data bytes] maxLength:[data length]]; if(bytesWritten < 0) NSLog(@"[ APP ] Failed to write message"); } } 

看看我使用RunLoop来写和读stream,我认为这比打开和closuresstream不断。

接下来,我收到从属设备上的“NSStreamEventHasBytesAvailable”事件,这里的句柄是:

 case NSStreamEventHasBytesAvailable: /*I can't to start a case without a expression, why not?*/ NSLog(@"[ APP ] stream handleEvent NSStreamEventHasBytesAvailable"); NSUInteger bytesRead; uint8_t buffer[BUFFER_SIZE]; while ([_inputStream hasBytesAvailable]) { bytesRead = [_inputStream read:buffer maxLength:BUFFER_SIZE]; NSLog(@"[ APP ] bytes read: %i", bytesRead); if(bytesRead) [data appendBytes:(const void *)buffer length:sizeof(buffer)]; } [_client writeImageWithData:data]; break; 

BUFFER_SIZE的值是32768.我认为while块是没有必要的,但我使用它,因为如果我在第一次迭代中不能读取所有可用的字节,我可以在下一个读取。

所以,这是重点,stream来正确,但在NSData序列化的图像似乎已损坏,接下来,我只是发送数据到客户端…

 [_client writeImageWithData:data]; 

…并创build一个UIImage与客户端类中的数据这样简单…

 [camPreview setImage:[UIImage imageWithData:data]]; 

在camPreview(是的是一个UIImageView),我有一个图像只是在屏幕上显示占位符,当我从networking中获取imagem并传递给camPreview时,占位符变为空白。

其他的想法是关于输出,当我开始捕获,我接收数据的第一部分,我从系统得到这个消息:

错误:ImageIO:JPEG损坏的JPEG数据:标记0xbf之前的28个无关字节

错误:ImageIO:JPEG不支持的标记types0xbf

过了一段时间,我收到了这个消息。

重点是find图像的原因不显示在“从”设备上。

谢谢。

我不知道你多长时间发送一次图像,但是即使不是很经常,我想我会扫描JPEG数据中的SOI和EOI标记,以确保你有所有的数据。 这里是我很快find的post

我find了一个答案 ,在渲染前检查jpeg格式。

这解决了我的问题,现在我可以显示从“主”IOS设备到“从”IOS设备的video捕获。