如何对 AVAssetWriter 输出进行颜色管理

2023-12-15

我无法使渲染视频的颜色与源内容的颜色相匹配。我将图像渲染到 CGContext 中,将支持数据转换为 CVPixelBuffer 并将其作为帧附加到 AVAssetWriterInputPixelBufferAdaptor 中。这会导致我绘制到 CGContext 中的图像与生成的视频文件之间存在轻微的颜色差异。

看来有3件事需要解决:

  1. 告诉 AVFoundation 视频所在的色彩空间。
  2. 使 AVAssetWriterInputPixelBufferAdaptor 和我附加到它的 CVPixelBuffers 与该颜色空间匹配。
  3. 对 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:^{}];

这是一个相当令人困惑的主题,苹果文档确实没有多大帮助。我将描述我基于使用 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.

金属BT709解码器

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何对 AVAssetWriter 输出进行颜色管理 的相关文章

随机推荐

  • 扩大堆大小C++

    有没有办法扩大 C 程序的堆大小 在 android 中 您可以通过在清单文件中将其声明为 Large 来轻松做到这一点 当我尝试在堆上分配十亿个数组元素时 我遇到了这个问题 int main int size 1000000000 int
  • android 动画列表中出现 OutOfMemory 错误

    我的绘图中有大约 100 多个图像 帧 每个图像的大小都是 1 5 kbs 分辨率为 480 x 272 现在 当我在动画列表 xml 中添加这些图像 帧 并尝试运行它时 我收到此 OutOfMemory 错误 我已在互联网上搜索 但找不到
  • “child_added”和“value”firebase 之间的区别?

    我发现两者之间有一点区别child added and value在 firebase 中返回数据时 使用value我可以测试一下是否snapshot val 已经返回了一些东西或者没有像这样使用它 获取数据 ref orderByChil
  • 重置并重新启动pygame程序不起作用

    当要求用户重新启动时 我在 pygame 中重置游戏时遇到问题 该程序的构造如下 import board as b class Gui def init self pygame init self gamestate b GameStat
  • 从文件中读取行,迭代每一行和该行中的每个字符

    我需要读取一个文件 获取每一行 迭代每一行并检查该行是否包含 aeiuo 中的任何字符以及是否包含至少 2 个字符 这段代码是 Rust 惯用的吗 如何检查一个文件中是否有多个字符String 到目前为止 我在谷歌和代码窃取方面的尝试 us
  • Kivy 安装出错 - Windows 10(以前可以工作,但在 gstreamer 之后就不行了)

    尝试在 Windows 10 中安装 Kivy 使用以下命令安装基础知识 python m pip install upgrade pip wheel setuptools python m pip install docutils pyg
  • NSOperations 队列和处理应用程序退出

    我即将创作一系列NSOperations 并在队列中运行它们 它们都是连续的并且一次运行一个 这些操作将从网络获取数据并创建和保存核心数据管理对象 应用程序退出的情况如何处理 由于操作在分离线程中运行 如何让主线程等待 直到当前操作 安全
  • iOS 中当年的天数

    我想找到今年今天的天数 例如 如果今天是 2012 年 3 月 15 日 我应该得到 75 31 29 15 或者我们可以简单地说今天到当年 1 月 1 日之间的天数 Use the ordinalityOfUnit的方法NSCalenda
  • php5 mail()函数sendmail错误

    我正在尝试使用 php 的 mail 函数 但不断收到错误 我已经通过安装了sendmailsudo apt get install sendmail 编辑了我的 etc php5 cli php ini文件将以下文本添加到这些行 send
  • 为什么 `define?` 返回字符串或 nil?

    在红宝石中 为什么会defined 返回一个字符串 大多数其他 Ruby 方法以 返回一个布尔值 这是为了支持功能请求而进行的黑客攻击 还是故意滥用 ruby 约定 为什么 例子 defined super gt super defined
  • Facebook登录成功后如何获取用户详细信息

    我尝试了这个 当 isSessionValid getDetails 直接 else facebook authorize 然后 getDetails 在 onActivityResult public class MainActivity
  • ggplot2 中的分面

    我有这个数据集 https dl dropboxusercontent com u 73950 data csv数据集包含 3 个变量 以下是我现在可视化数据的方式 library ggplot2 library reshape2 libr
  • Obj-C 检查照片库中是否已存在图像

    在我的应用程序中 我必须实现保存图像功能 我已经成功地保存了这样的内容 UIImage image UIImage imageNamed actualBackground UIImageWriteToSavedPhotosAlbum ima
  • 替换 JSON 对象中的变量

    我正在编写 JavaScript 代码 我想在其中替换 JSON 对象中的字符串 我的代码如下 var obj name name is name work name is doctor maritial status unmarried
  • CocoaPods 和迦太基

    我有一个关于 Carthage 和 Cocoapods 的项目 它们都有一个共同的依赖项 准确地说是 PureLayout 奇怪 但项目编译良好 没有任何有关类重新声明等的错误 所以问题是 为什么它有效 以及当我调用 PureLayout
  • 当键盘向上移动时,如何使文本字段保持在原位?迅速

    我创建了一个包含 4 个字段和一个按钮的表单 视图层次结构如下所示 主 UIVIew 视图 重命名为 contentView 在 contentView 之上我有 4 个字段和 1 个以编程方式创建的按钮 当 viewDidLoad 被触发
  • 生产环境中 NLog 日志中的行号消失

    我使用 callsite 参数配置了 NLog 布局 使其具有方法名称和行号 并且它在本地运行良好 如下所示 Application Start Global asax cs 33 但它正在改变Application Start没有生产线号
  • 如何使用 XmlWriter 在元素中编写命名空间

    我正在将代码从 vbs 更改为 C 但我在 XMLwriter 方面遇到问题 如何使用 XML write 在 XML file 中获取此类输出 我有这样的代码 using XmlWriter writer XmlWriter Create
  • Phonegap JQM 固定位置页眉/页脚在关闭 iOS 键盘后移动

    我正在尝试在 Phonegap 项目中使用 JQM 在 iOS 应用程序中创建固定页眉和页脚 我有一个使用可折叠 DIV 的页面 并且 DIV 内有一个文本输入 页眉和页脚的一切都很好 直到我展开 DIV 并将某些内容输入到文本字段中 一旦
  • 如何对 AVAssetWriter 输出进行颜色管理

    我无法使渲染视频的颜色与源内容的颜色相匹配 我将图像渲染到 CGContext 中 将支持数据转换为 CVPixelBuffer 并将其作为帧附加到 AVAssetWriterInputPixelBufferAdaptor 中 这会导致我绘