CMSampleBuffer from OpenGL for video output with AVAssestWritter
I need to get a CMSampleBuffer for the OpenGL frame. I'm using this:
int s = 1;
UIScreen * screen = [UIScreen mainScreen];
if ([screen respondsToSelector:@selector(scale)]){
s = (int)[screen scale];
}
const int w = viewController.view.frame.size.width/2;
const int h = viewController.view.frame.size.height/2;
const NSInteger my_data_length = 4*w*h*s*s;
// allocate array and read pixels into it.
GLubyte * buffer = malloc(my_data_length);
glReadPixels(0, 0,开发者_开发百科 w*s, h*s, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
// gl renders "upside down" so swap top to bottom into new array.
GLubyte * buffer2 = malloc(my_data_length);
for(int y = 0; y < h*s; y++){
memcpy(buffer2 + (h*s - 1 - y)*4*w*s, buffer + (4*y*w*s), 4*w*s);
}
free(buffer);
CMBlockBufferRef * cm_block_buffer_ref;
CMBlockBufferAccessDataBytes(cm_block_buffer_ref,0,my_data_length,buffer2,*buffer2);
CMSampleBufferRef * cm_buffer;
CMSampleBufferCreate (kCFAllocatorDefault,cm_block_buffer_ref,true,NULL,NULL,NULL,1,1,NULL,0,NULL,cm_buffer);
I get EXEC_BAD_ACCESS for CMSampleBufferCreate.
Any help is appreciated, thank you.
The solution was to use the AVAssetWriterInputPixelBufferAdaptor class.
int s = 1;
UIScreen * screen = [UIScreen mainScreen];
if ([screen respondsToSelector:@selector(scale)]){
s = (int)[screen scale];
}
const int w = viewController.view.frame.size.width/2;
const int h = viewController.view.frame.size.height/2;
const NSInteger my_data_length = 4*w*h*s*s;
// allocate array and read pixels into it.
GLubyte * buffer = malloc(my_data_length);
glReadPixels(0, 0, w*s, h*s, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
// gl renders "upside down" so swap top to bottom into new array.
GLubyte * buffer2 = malloc(my_data_length);
for(int y = 0; y < h*s; y++){
memcpy(buffer2 + (h*s - 1 - y)*4*w*s, buffer + (4*y*w*s), 4*w*s);
}
free(buffer);
CVPixelBufferRef pixel_buffer = NULL;
CVPixelBufferCreateWithBytes (NULL,w*2,h*2,kCVPixelFormatType_32BGRA,buffer2,4*w*s,NULL,0,NULL,&pixel_buffer);
[av_adaptor appendPixelBuffer: pixel_buffer withPresentationTime:CMTimeMakeWithSeconds([[NSDate date] timeIntervalSinceDate: start_time],30)];
Why is the third parameter to CMSampleBufferCreate()
true in your code? According to the documentation:
Parameters
allocator
The allocator to use to allocate memory for the CMSampleBuffer object. Pass kCFAllocatorDefault to use the current default allocator.
dataBuffer
This can be NULL, a CMBlockBuffer with no backing memory, a CMBlockBuffer with backing memory but no data yet, or a CMBlockBuffer that already contains the media data. Only in that last case (or if NULL and numSamples is 0) should dataReady be true.
dataReady
Indicates whether dataBuffer already contains the media data.
Your cm_block_buffer_ref
that is being passed in as a buffer contains no data (you should NULL it for safety, I don't believe the compiler does that by default), so you should use false
here.
There may be other things wrong with this, but that's the first item that leaps out at me.
Why the double malloc and why not swap in place via a temp buffer?
Something like this:
GLubyte * raw = (GLubyte *) wyMalloc(size);
LOGD("raw address %p", raw);
glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, raw);
const size_t end = h/2;
const size_t W = 4*w;
GLubyte row[4*w];
for (int i=0; i <= end; i++) {
void * top = raw + (h - i - 1)*W;
void * bottom = raw + i*W;
memcpy(row, top, W);
memcpy(top, bottom, W);
memcpy(bottom, row, W);
}
精彩评论