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捕获。
- didOutputSampleBuffer委托没有被调用
- AVURLAsset的caching行为
- 使用AVPlayer和AVMutableComposition进行未alignment的声音播放
- iOS – AVAssestExportSession只能在播放AVPlayer后导出最多8首曲目
- 使用AVFoundation混合图像和video
- 如何通过硬件解码在iOS上解码H.264帧?
- Swift将audio和video文件合并为一个video
- Swift AVCaptureSessionclosures打开button错误:当前不支持多个audio/videoAVCaptureInputs
- IOS将UIProgressView添加到AVFoundation AVCaptureMovieFileOutput