如何从 CMSampleBufferRef 获取字节,通过网络发送

Posted

技术标签:

【中文标题】如何从 CMSampleBufferRef 获取字节,通过网络发送【英文标题】:How to get Bytes from CMSampleBufferRef , To Send Over Network 【发布时间】:2011-09-05 13:46:34 【问题描述】:

我正在使用 AVFoundation 框架捕获视频。借助 Apple 文档http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/03_MediaCapture.html%23//apple_ref/doc/uid/TP40010188-CH5-SW2

现在我做了以下事情

1.创建videoCaptureDevice 2.创建AVCaptureDeviceInput并设置videoCaptureDevice 3.创建AVCaptureVideoDataOutput并实现Delegate 4.Created AVCaptureSession - 将输入设置为 AVCaptureDeviceInput 并将输出设置为 AVCaptureVideoDataOutput

5.在 AVCaptureVideoDataOutput 委托方法中

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection

我得到了 CMSamplebuffer 并转换成 UIImage 并测试使用打印 UIImageview

[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];

每件事都进展顺利............

我的问题是, 我需要通过 UDP Socket 发送视频帧。即使我尝试了以下一个是坏主意,UIImage 到 NSData 并通过 UDP Pocket 发送。但是视频处理延迟了。主要是因为 UIImage 到 NSDate 的问题

所以请给我解决我的问题

1) 任何方式将 CMSampleBUffer 或 CVImageBuffer 转换为 NSData ?? 2)像Audio Queue Service和Queue for Video一样存储UIImage,做UIImage到NSDate 并发送???

如果我落后于错误的算法,请按写入方向引导我

提前致谢

【问题讨论】:

【参考方案1】:

使用CMSampleBufferGetImageBuffer 从样本缓冲区中获取CVImageBufferRef,然后使用CVPixelBufferGetBaseAddress 从中获取位图数据。这样可以避免不必要地复制图像。

【讨论】:

感谢您的回复。我已经使用了 CVPixelBufferGetBaseAddress 但我可以将其用作字节吗?并且单独使用它,我可以在接收端绘制图像吗??? 是的,这些是字节。其中有 CVPixelBufferGetHeight()*CVPixelBufferGetBytesPerRow()。如果你做对了,你就可以在另一端重建图像。 这对平面格式是否同样有效?还是需要使用 CVPixelBufferGetHeightOfPlane 和 CVPixelBufferGetBytesPerRowOfPlane 代替? 您应该使用平面版本。无需解码 CVPlanarPixelBufferInfo_YCbCrBiPlanar 结构。【参考方案2】:

这是获取缓冲区的代码。此代码假定为平面图像(例如 BGRA)。

NSData* imageToBuffer( CMSampleBufferRef source) 
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(source);
    CVPixelBufferLockBaseAddress(imageBuffer,0);

    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
    size_t width = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);
    void *src_buff = CVPixelBufferGetBaseAddress(imageBuffer);

    NSData *data = [NSData dataWithBytes:src_buff length:bytesPerRow * height];

    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
    return [data autorelease];

更有效的方法是使用 NSMutableData 或缓冲池。

每秒发送一张 480x360 的图像需要 4.1Mbps 的连接(假设有 3 个颜色通道)。

【讨论】:

感谢您的回复。 CVimagebuffer 到 NSdata 没问题。我有一个小疑问,在接收器中我无法取回需要高度、宽度和每行字节数的 CVimagebuffer、bcoz 如何转换回图像缓冲区? 此代码给出的数据长度为 3686400 。但图像只有 3000 我的意思是当我 NSLog(@"%i",[data length]);然后它总是记录 3686400。 使用上面的代码获取NSData,你将如何使用CGImageCreate返回CVImageBuffer?我看不到链接。还是有别的办法?

以上是关于如何从 CMSampleBufferRef 获取字节,通过网络发送的主要内容,如果未能解决你的问题,请参考以下文章

如何将 CMSampleBufferRef 转换为 NSData

来自 CMSampleBufferRef 的图像始终为白色

捕获仍然没有压缩的 UIImage(来自 CMSampleBufferRef)?

从 CMSampleBufferRef 转换的 UIImage,导致 UIImage 无法正确渲染

我们如何从 iPhone 相机中获取 H.264 编码的视频流?

使用重叠执行缓冲/窗口添加 CMSampleBufferRef