来自 OpenGL 的 CMSampleBuffer,用于使用 AVAssestWritter 进行视频输出
Posted
技术标签:
【中文标题】来自 OpenGL 的 CMSampleBuffer,用于使用 AVAssestWritter 进行视频输出【英文标题】:CMSampleBuffer from OpenGL for video output with AVAssestWritter 【发布时间】:2011-01-28 02:11:55 【问题描述】:我需要为 OpenGL 帧获取一个 CMSampleBuffer。我正在使用这个:
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);
我得到了 CMSampleBufferCreate 的 EXEC_BAD_ACCESS。
感谢您的帮助,谢谢。
【问题讨论】:
【参考方案1】:解决方案是使用 AVAssetWriterInputPixelBufferAdaptor 类。
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)];
【讨论】:
【参考方案2】:为什么CMSampleBufferCreate()
的第三个参数在您的代码中为真?根据documentation:
参数
分配器
用于为 CMSampleBuffer 分配内存的分配器 目的。将 kCFAllocatorDefault 传递给 使用当前的默认分配器。
数据缓冲区
这可以是 NULL,一个没有后备内存的 CMBlockBuffer, 带有后备内存的 CMBlockBuffer 但还没有数据,或者 CMBlockBuffer 已经包含媒体数据。 仅在最后一种情况下(或者如果 NULL 和 numSamples 为 0) 应为 dataReady 真的。
数据就绪
表示dataBuffer是否已经包含媒体 数据。
作为缓冲区传入的 cm_block_buffer_ref
不包含任何数据(为了安全起见,您应该将其设为 NULL,我不相信编译器默认情况下会这样做),因此您应该在此处使用 false
。
这可能还有其他问题,但这是我第一个跳出来的项目。
【讨论】:
谢谢。如何让 cm_block_buffer_ref 包含 OpenGL 数据? @Matthew - 看着它,我认为您需要创建一个 CVPixelBuffer,然后使用CMSampleBufferCreateForImageBuffer()
而不是 CMSampleBufferCreate()
。事实上,您最好使用 AVAssetWriterInputPixelBufferAdaptor:developer.apple.com/library/ios/#documentation/AVFoundation/…
哦,是的,我添加了自己的答案。我已经设法让它工作(有点慢,但应该是 glReadPixels )。不过谢谢。【参考方案3】:
为什么要使用双 malloc,为什么不通过临时缓冲区就地交换?
类似这样的:
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);
【讨论】:
我什至不再 malloc 原始原始缓冲区,而是回收它。我创建了一个缓冲池类。对于我的短循环,我做的事情略有不同。我将每个图像保存到存储中,然后在稍后按顺序读取它们。以上是关于来自 OpenGL 的 CMSampleBuffer,用于使用 AVAssestWritter 进行视频输出的主要内容,如果未能解决你的问题,请参考以下文章
来自 OpenGL 的 CMSampleBuffer,用于使用 AVAssestWritter 进行视频输出