I'm trying to stream video data over a peer-to-peer connection created with GameKit. I have a method that receives an NSData object and uses it to draw a video stream onto a CALayer:
- (void)recieveVideoFromData:(NSData *)data;
Here are the first few lines of that method which convert the NSData to CMSampleBufferRefs and begins processing:
CMSampleBufferRef imgData = (CMSampleBufferRef)data.bytes;
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(imgData);
CVPixelBufferLockBaseAddress(imageBuffer,0);
Now, when I feed the video stream from the local camera into this method as follows, everything works just fine and the video stream displays on screen:
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
NSData *data = [[NSData alloc] initWithBytes:sampleBuffer length:malloc_size(sampleBuffer)];
[self recieveVideoFromData:data];
}
But, when I send a stream of those NSData packets over a peer-to-peer connection and receive them in the following fashion, I get an EXC_BAD_ACCESS error:
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID {
[self recieveVideoFromData:data];
}
Using the debugger, I learned that the bad access occurs on this line:
CVPixelBufferLockBaseAddress(imageBuffer,0);
I have no idea why the NSData sent over the network should be any different than the NSData sent from another method on the same device. I have checked that the data received over the network is being received at the same interval and is the sa开发者_如何学Gome length (336 bytes) as the data produced on the local device. I also checked the retain count of the data object is 1 before it is used. It seems that the imageBuffer variable is somehow getting lost.
A couple of questions:
Is casting data.bytes to a CMSampleBufferRef the right way to go about unpacking NSData?
How do I assert that the data being received is actually a CMSampleBuffer object? I want to protect my code but I'm not sure how to accomplish a class verification for Core Foundation classes.
Thanks in advance!
Why are you 'unpacking' (that's not unpacking) your CMSampleBuffer
by casting the bytes of NSData
? That's never going to work, because CMSampleBuffer
is not a continuous block in memory.
You have to retrieve all the relevant data from a CMSampleBuffer
yourself before sending, stuff it into and NSData
object, and reasemble it on the other side via
OSStatus CMSampleBufferCreate (
CFAllocatorRef allocator,
CMBlockBufferRef dataBuffer,
Boolean dataReady,
CMSampleBufferMakeDataReadyCallback makeDataReadyCallback,
void *makeDataReadyRefcon,
CMFormatDescriptionRef formatDescription,
CMItemCount numSamples,
CMItemCount numSampleTimingEntries,
const CMSampleTimingInfo *sampleTimingArray,
CMItemCount numSampleSizeEntries,
const size_t *sampleSizeArray,
CMSampleBufferRef *sBufOut
);
The data types in this function might give you a hint what you want to extract from the CMSampleBuffer
when packing your data.
This is probably not the entire answer, but your use of malloc_size
seems like a huge red flag to me. This seems a non-portable extension, not governed by anything like ANSI, ISO or POSIX, and I have some doubts on how it might behave if passed a buffer that didn't come from malloc
. It seems like a sketchy thing to rely on. (I would say if it's come to calling malloc_size
you're already doing something wrong as a C coder, since C is all about knowing how big your buffers are upfront and not relying on non-portable libc functions to do your buffer-size-tracking work for you.)
精彩评论