通过AVFoundation将{16} /像素数据写入QuickTime影片

时间:2015-11-08 03:53:32

标签: macos cocoa core-graphics avfoundation

我正在尝试将包含从每像素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电影的工作示例?

1 个答案:

答案 0 :(得分:0)

所以,我找到了一个解决方案,而且我认为我发布了它,因为公共互联网似乎只包含了这个例子,在我点击之前我必须尝试很多东西有用的东西。

以下是如何从CGImage开始获取kCVPixelFormatType_4444AYpCbCr16 CVPixelBuffer(您想要编写ProRes 4444的内容)。这适用于没有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;
}