如何对 AVAssetWriter 输出进行颜色管理
Posted
技术标签:
【中文标题】如何对 AVAssetWriter 输出进行颜色管理【英文标题】:How to color manage AVAssetWriter output 【发布时间】:2018-06-15 18:08:39 【问题描述】:我无法让渲染视频的颜色与源内容的颜色相匹配。我将图像渲染到 CGContext 中,将支持数据转换为 CVPixelBuffer 并将其作为帧附加到 AVAssetWriterInputPixelBufferAdaptor。这会导致我绘制到 CGContext 中的图像与生成的视频文件之间存在细微的颜色差异。
似乎有 3 件事需要解决:
-
告诉 AVFoundation 视频所在的色彩空间。
使 AVAssetWriterInputPixelBufferAdaptor 和我附加到它的 CVPixelBuffers 与该颜色空间匹配。
为 CGContext 使用相同的色彩空间。
文档很糟糕,所以如果我能提供任何关于如何做这些事情的指导,或者我需要做些什么来使颜色在整个过程中得到保留,我将不胜感激。
完整代码:
AVAssetWriter *_assetWriter;
AVAssetWriterInput *_assetInput;
AVAssetWriterInputPixelBufferAdaptor *_assetInputAdaptor;
NSDictionary *outputSettings = @ AVVideoCodecKey :AVVideoCodecH264,
AVVideoWidthKey :@(outputWidth),
AVVideoHeightKey:@(outputHeight);
_assetInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
outputSettings:outputSettings];
NSDictionary *bufferAttributes = @å(NSString*)kCVPixelBufferPixelFormatTypeKey:@(kCVPixelFormatType_32ARGB);
_assetInputAdaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:_assetInput
sourcePixelBufferAttributes:bufferAttributes];
_assetWriter = [AVAssetWriter assetWriterWithURL:aURL fileType:AVFileTypeMPEG4 error:nil];
[_assetWriter addInput:_assetInput];
[_assetWriter startWriting];
[_assetWriter startSessionAtSourceTime:kCMTimeZero];
NSInteger bytesPerRow = outputWidth * 4;
long size = bytesPerRow * outputHeight;
CGColorSpaceRef srgbSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
UInt8 *data = (UInt8 *)calloc(size, 1);
CGContextRef ctx = CGBitmapContextCreateWithData(data, outputWidth, outputHeight, 8, bytesPerRow, srgbSpace, kCGImageAlphaPremultipliedFirst, NULL, NULL);
// draw everything into ctx
CVPixelBufferRef pixelBuffer;
CVPixelBufferCreateWithBytes(kCFAllocatorSystemDefault,
outputWidth, outputHeight,
k32ARGBPixelFormat,
data,
bytesPerRow,
ReleaseCVPixelBufferForCVPixelBufferCreateWithBytes,
NULL,
NULL,
&pixelBuffer);
NSDictionary *pbAttachements = @(id)kCVImageBufferCGColorSpaceKey : (__bridge id)srgbSpace;
CVBufferSetAttachments(pixelBuffer, (__bridge CFDictionaryRef)pbAttachements, kCVAttachmentMode_ShouldPropagate);
[_assetInputAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:CMTimeMake(0, 60)];
CGColorSpaceRelease(srgbSpace);
[_assetInput markAsFinished];
[_assetWriter finishWritingWithCompletionHandler:^];
【问题讨论】:
【参考方案1】:这是一个相当令人困惑的主题,Apple 文档确实没有太大帮助。我将描述基于使用 BT.709 色彩空间的解决方案,我相信有人会基于色度正确性和各种视频标准的怪异性提出异议,但这是一个复杂的话题。首先,不要使用 kCVPixelFormatType_32ARGB 作为像素类型。始终传递 kCVPixelFormatType_32BGRA,因为 BGRA 是 MacOSX 和 iPhone 硬件上的原生像素布局,而且 BGRA 更快。接下来,当您创建 CGBitmapContext 以使用 BT.709 颜色空间 (kCGColorSpaceITUR_709) 进行渲染时。此外,不要渲染到 malloc() 缓冲区,通过在同一内存上创建位图上下文直接渲染到 CoreVideo 像素缓冲区,CoreGraphics 将处理从您的输入图像到 BT.709 及其相关伽玛。然后你需要告诉 AVFoundation 像素缓冲区的颜色空间,通过制作 ICC 配置文件副本并在 CoreVideo 像素缓冲区上设置 kCVImageBufferICCProfileKey 来做到这一点。这可以解决您的问题 1 和 2,您不需要使用这种方法在相同的色彩空间中输入图像。现在,这当然很复杂,而且实际工作的源代码(是的,实际工作的)很难获得。这是一个执行这些确切步骤的小项目的 github 链接,代码是 BSD 许可的,所以请随意使用。特别注意 H264Encoder 类,它将所有这些恐怖包装到一个可重用的模块中。你可以在 encode_h264.m 中找到调用代码,这是一个 MacOSX 命令行工具,用于将 PNG 编码为 M4V。还附上了 3 个与此主题相关的 Apple 文档 1、2、3。
MetalBT709Decoder
【讨论】:
与不同色彩空间中的图像相关的问题。 ***.com/questions/53911662/…以上是关于如何对 AVAssetWriter 输出进行颜色管理的主要内容,如果未能解决你的问题,请参考以下文章
旋转视频而不旋转 AVCaptureConnection 并在 AVAssetWriter 会话中间