【问题标题】:IOS Receiving video from NetworkIOS 从网络接收视频
【发布时间】:2012-04-07 16:59:31
【问题描述】:

更新 - 我已经修复了下面代码中的一些错误,图像显示在另一台设备上,但我还有另一个问题。当视频捕获打开时,“主”设备连续发送数据,有时此捕获出现在“从”设备上,并且在很短的时间内,图像“闪烁”为空白并在短时间内重复此操作。有什么想法吗?

我正在开发一个需要将实时摄像头捕获和实时麦克风捕获发送到网络中的另一台设备的应用。

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

最重要的部分是从“主”设备发送和接收视频和音频,并在“从”设备上渲染。

首先,这里有一段代码,应用程序在其中获取相机样本缓冲区并在 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];”只是为了测试主设备上的图像捕获,并且该图像在捕获设备上有效。

接下来是关于如何发送到网络:

- (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 来写和读流,我认为这比不断地打开和关闭流更好。

接下来,我在从设备上收到“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 块不是必需的,但我使用它是因为如果我在第一次迭代时无法读取所有可用字节,我可以在下一次读取。

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

[_client writeImageWithData:data];

...并使用客户端类中的数据创建一个 UIImage 像这样简单...

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

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

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

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

错误:ImageIO:JPEG 不支持的标记类型 0xbf

过了一会儿,我收到了这条消息。

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

谢谢。

【问题讨论】:

  • @ Jan thsi 将通过网络发送图像,但音频呢?如何发送带图像的音频?
  • re: 无法在没有表达式的情况下启动案例。您必须用大括号将语句包装在您的案例中,例如案例 1:{...} 这是一个深奥的 C 语言。

标签: objective-c ios networking avfoundation bonjour


【解决方案1】:

我不确定您发送图像的频率,但即使不是很频繁,我想我也会扫描 JPEG 数据中的 SOI 和 EOI 标记,以确保您拥有所有数据。这是我很快找到的post

【讨论】:

  • 我在视频捕获打开时连续发送数据。
【解决方案2】:

我找到了answer 在渲染前检查 jpeg 格式。

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

【讨论】:

  • 我正在做同样的事情,当我收到图像时,它似乎已损坏。我正在发送像你一样的连续图像。就我而言,我从来没有从 while inputStream.hasBytesAvailable { function.
  • 没关系,我可以流式传输数据,但速度太慢了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多