我无法使渲染视频的颜色与源内容的颜色相匹配。我将图像渲染到 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:^{}];