【问题标题】:Writing 16 bit/pixel data to QuickTime movie via AVFoundation通过 AVFoundation 将 16 位/像素数据写入 QuickTime 电影
【发布时间】:2015-11-08 03:53:31
【问题描述】:

我正在尝试将包含从每像素 16 位 TIFF 文件加载的数据的 CGImage 写入 ProRes 44444 QuickTime 文件,同时保持位深度。

我正在像这样加载数据:

NSImage* image = [[NSImage alloc] initWithContentsOfFile:@"/whatever/test.tif"];
CGImageRef temp = [image CGImageForProposedRect:nil context:nil hints:nil];

我有一个 AVAssetWriterInputPixelBufferAdaptor 设置如下:

NSDictionary *sourcePixelBufferAttributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                                                       [NSNumber numberWithInt:kCVPixelFormatType_64ARGB], kCVPixelBufferPixelFormatTypeKey,
                                                       [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                                                       [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
                                                       nil];

AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput
                                                                                                                 sourcePixelBufferAttributes:sourcePixelBufferAttributesDictionary];

然后我将图像写入 CVPixelBuffer:

CVPixelBufferRef pxbuffer = NULL;
CVReturn status = CVPixelBufferPoolCreatePixelBuffer(NULL, adaptor.pixelBufferPool, &pxbuffer);

CVPixelBufferLockBaseAddress(pxbuffer, 0);
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);

CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();

CGBitmapInfo bitmapInfo = (CGBitmapInfo) kCGImageAlphaPremultipliedLast;
CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 16, 8*size.width, rgbColorSpace, bitmapInfo);

CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);

CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);

CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

然后将其附加到电影中:

[adaptor appendPixelBuffer:pxbuffer withPresentationTime:CMTimeMake(frame, 24)]

这对 8 位/像素图像(适当调整了值)非常有效,但是对于 16 位/像素图像,我在生成的 QuickTime 电影中得到了奇怪的颜色。看起来有些频道可能会被交换,但各种交换它们的尝试都没有产生有用的结果。有没有人有将大于 8 位/像素的图像数据写入 QuickTime 电影的工作示例?

【问题讨论】:

    标签: macos cocoa core-graphics avfoundation


    【解决方案1】:

    所以,我找到了一个解决方案,我想我会发布它,因为公共互联网似乎包含零个这样的例子,我必须尝试很多东西才能找到可行的方法。

    以下是获取 kCVPixelFormatType_4444AYpCbCr16 CVPixelBuffer(编写 ProRes 4444 所需的内容)的方法,从 CGImage 开始。这适用于没有 alpha 的 16 位/通道 RGB 源。通过更改 bitmapInfo 和 bitsPerPixel 值,它可能适用于具有 alpha 通道的图像,但这是未经测试的。

    - (CVPixelBufferRef) convertFrame:(CGImageRef) sourceImage {
        vImage_Buffer sourceBuffer;
        CVPixelBufferRef destBuffer;
    
        vImage_CGImageFormat inFormat = {
            .bitsPerComponent = (unsigned int)CGImageGetBitsPerComponent(sourceImage),
            .bitsPerPixel = (unsigned int)CGImageGetBitsPerPixel(sourceImage),
            .colorSpace = NULL,
            .bitmapInfo = (CGBitmapInfo)kCGImageAlphaNone,
            .version = 0,
            .decode = NULL,
            .renderingIntent = kCGRenderingIntentDefault,
        };
    
        vImage_Error err = vImageBuffer_InitWithCGImage(&sourceBuffer, &inFormat, NULL, sourceImage, kvImageNoFlags);
    
        if (err == kvImageNoError)
        {
            CGColorSpaceRef dstColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceITUR_709);
    
            vImage_CGImageFormat format = {
                .bitsPerComponent = 16,
                .bitsPerPixel = 48,
                .bitmapInfo = (CGBitmapInfo)kCGImageAlphaNone,
                .colorSpace = dstColorSpace,
            };
    
            vImageCVImageFormatRef vformat = vImageCVImageFormat_Create(kCVPixelFormatType_4444AYpCbCr16,
                                                                        kvImage_ARGBToYpCbCrMatrix_ITU_R_709_2,
                                                                        kCVImageBufferChromaLocation_Center,
                                                                        dstColorSpace,
                                                                        0);
    
            CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, CGImageGetWidth(sourceImage), CGImageGetHeight(sourceImage),
                                                  kCVPixelFormatType_4444AYpCbCr16, NULL, &destBuffer);
    
            NSParameterAssert(status == kCVReturnSuccess && destBuffer != NULL);
    
            err = vImageBuffer_CopyToCVPixelBuffer(&sourceBuffer, &format, destBuffer, vformat, 0, kvImagePrintDiagnosticsToConsole);
    
            if(err != 0)
                NSLog(@"Conversion error: %zi", err);
    
            CGColorSpaceRelease(dstColorSpace);
            free(sourceBuffer.data);
        }
    
        return destBuffer;
    }
    

    【讨论】:

    • 感谢您的示例代码。仅供参考,但您那里有内存泄漏,只需在颜色空间释放之前添加此版本:vImageCVImageFormat_Release(vformat)
    • 另请注意,vImageCVImageFormat_Create() 的文档声明源图像的颜色空间应作为 baseColorspace 的值传递,因此在这种情况下,如果您想要默认的 gamma 转换,它应该是 sRGB应用。
    • 仅供参考,您可以在 Intel Mac 上使用 kCVPixelFormatType_64ARGB 编写 ProRes,但由于硬件加速器,需要在 Apple Silicon 上使用 kCVPixelFormatType_64RGBALE 才能在 MacBook M1 Pro/Max 上工作。
    猜你喜欢
    • 1970-01-01
    • 2018-10-03
    • 1970-01-01
    • 2016-11-11
    • 2011-06-07
    • 1970-01-01
    • 2021-06-13
    • 2010-11-06
    • 1970-01-01
    相关资源
    最近更新 更多