如何从CMSampleBufferRef中获取字节以便通过网络发送

29

我正在使用AVFoundation框架捕获视频,参考了苹果开发文档 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并实现了代理;
4.创建了AVCaptureSession——将输入设为AVCaptureDeviceInput,将输出设为AVCaptureVideoDataOutput

5.在AVCaptureVideoDataOutput的代理方法中:

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

我得到了CMSampleBuffer,并将其转换为UIImage,然后测试使用UIImageView打印UIImage。

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

一切都进行得很顺利,直到这一步......

我的问题是,我需要通过UDP套接字发送视频帧。尽管我尝试了不好的方法,即UIImage转换为NSData并通过UDP Pocket发送,但视频处理中出现了很大的延迟。主要问题在于UIImage转NSDate。

所以请给我解决方案:

1)有没有办法将CMSampleBuffer或CVImageBuffer转换为NSData?
2)是否有类似音频队列服务和视频队列来存储UIImage,并进行UIImage到NSDate的转换和发送?

如果我走错了算法,请指正我走向正确的方向。

提前感谢您

2个回答

38

以下是获取缓冲区的代码。该代码假设图像是平坦的(例如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的图像,假设有3个颜色通道,则需要4.1Mbps的连接速度。


谢谢您的回复。将CVimagebuffer转换为NSdata是可以的。我有一个小疑问,在接收器中,我无法获取CVimagebuffer,因为它需要单独的高度、宽度和每行字节数。 - Asta ni enohpi
1
如何将其转换回图像缓冲区? - Paul Solt
2
这段代码给出的数据长度为3686400,但图像只有3000。 - sajwan
3
当我使用 NSLog(@"%i",[data length]); 时,它总是记录 3686400。 - sajwan
1
使用上面的代码获取NSData数据后,如何使用CGImageCreate将其转换为CVImageBuffer?我无法找到连接点。还是有其他方法吗? - noRema
显示剩余5条评论

2

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


谢谢您的回复。我已经使用了CVPixelBufferGetBaseAddress,但是我可以将其用作字节吗?仅使用它,我能在接收端绘制图像吗? - Asta ni enohpi
是的,那些是字节。它们的数量为CVPixelBufferGetHeight()*CVPixelBufferGetBytesPerRow()。如果你做得对,你就能在另一端重建图像。 - Rhythmic Fistman
对于平面格式,这个是否也适用?还是需要使用CVPixelBufferGetHeightOfPlane和CVPixelBufferGetBytesPerRowOfPlane? - user2074102
你应该使用平面版本。这样可以避免解码CVPlanarPixelBufferInfo_YCbCrBiPlanar结构体。 - Rhythmic Fistman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接