来自 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 进行视频输出的主要内容,如果未能解决你的问题,请参考以下文章

来自 glClear() 的 OpenGL 帧缓冲区错误

来自物体的 Opengl 闪电

来自 OpenGL 的 CMSampleBuffer,用于使用 AVAssestWritter 进行视频输出

OSX 上的 AVFoundation:来自视频的 OpenGL 纹理,无需访问像素数据

来自实时摄像机的 openGL 纹理的 API 开发

OpenGL中的像素间隙来自哪里?