使用 CIFilter 在 CALayer 层次结构中渲染视频

2023-12-25

在我的 iOS 应用程序的 UI 中,我显示了一个复杂的层次结构CALayers。其中一层是AVPlayerLayer显示视频CIFilter实时应用(使用AVVideoComposition(asset:, applyingCIFiltersWithHandler:)).

现在我想将此图层合成导出到视频文件。里面有两个工具AVFoundation这似乎有帮助:

A: AVVideoCompositionCoreAnimationTool它允许在(可能是动画的)内渲染视频CALayer等级制度

B: AVVideoComposition(asset:, applyingCIFiltersWithHandler:),我也在 UI 中使用它来应用CIFilters 到视频资产。

但是,这两个工具不能同时使用:如果我启动一个AVAssetExportSession结合了这些工具,AVFoundation抛出一个NSInvalidArgumentException:

期望视频合成仅包含AVCoreImageFilterVideoCompositionInstruction

我尝试按如下方式解决此限制:

解决方法1

1) 使用设置导出AVAssetReader and AVAssetWriter

2) 从资产读取器获取样本缓冲区并应用CIFilter,将结果保存在CGImage.

3) 设置CGImage as the content层层次结构中视频层的位置。现在,图层层次结构“看起来像”最终视频的一帧。

4)获取数据CVPixelBuffer对于资产编写器使用的每个帧CVPixelBufferGetBaseAddress并创建一个CGContext与该数据。

5)使用以下命令将我的图层渲染到该上下文CALayer.render(in ctx: CGContext).

此设置有效,但速度非常慢 - 导出 5 秒的视频有时需要一分钟。它看起来像CoreGraphics调用是这里的瓶颈(我猜这是因为通过这种方法,组合发生在 CPU 上?)

解决方法2

另一种方法可能是分两步完成此操作:首先,保存源视频,并将滤镜应用于文件,如下所示B,然后使用该视频文件将视频嵌入到图层合成中,如下所示A。然而,由于它使用两次传递,我想这并没有达到应有的效率。

Summary

将该视频导出到文件的好方法是什么(最好一次性导出)?我该如何使用CIFilters and AVVideoCompositionCoreAnimationTool同时地?是否有一种本地方式来设置“管道”AVFoundation它结合了这些工具?


实现此目的的方法是使用自定义AVVideoCompositing。该对象允许您组合(在本例中应用 CIFilter)每个视频帧。

这是一个应用示例实现CIPhotoEffectNoir整个视频效果:

class VideoFilterCompositor: NSObject, AVVideoCompositing {

    var sourcePixelBufferAttributes: [String : Any]? = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA]
    var requiredPixelBufferAttributesForRenderContext: [String : Any] = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA]
    private var renderContext: AVVideoCompositionRenderContext?

    func renderContextChanged(_ newRenderContext: AVVideoCompositionRenderContext) {
        renderContext = newRenderContext
    }

    func cancelAllPendingVideoCompositionRequests() {
    }

    private let filter = CIFilter(name: "CIPhotoEffectNoir")!
    private let context = CIContext()
    func startRequest(_ asyncVideoCompositionRequest: AVAsynchronousVideoCompositionRequest) {
        guard let track = asyncVideoCompositionRequest.sourceTrackIDs.first?.int32Value, let frame = asyncVideoCompositionRequest.sourceFrame(byTrackID: track) else {
            asyncVideoCompositionRequest.finish(with: NSError(domain: "VideoFilterCompositor", code: 0, userInfo: nil))
            return
        }
        filter.setValue(CIImage(cvPixelBuffer: frame), forKey: kCIInputImageKey)
        if let outputImage = filter.outputImage, let outBuffer = renderContext?.newPixelBuffer() {
            context.render(outputImage, to: outBuffer)
            asyncVideoCompositionRequest.finish(withComposedVideoFrame: outBuffer)
        } else {
            asyncVideoCompositionRequest.finish(with: NSError(domain: "VideoFilterCompositor", code: 0, userInfo: nil))
        }
    }

}

如果您需要在不同时间有不同的过滤器,您可以使用自定义AVVideoCompositionInstructionProtocol你可以从AVAsynchronousVideoCompositionRequest

接下来,您需要将其与您的AVMutableVideoComposition, so:

let videoComposition = AVMutableVideoComposition()
videoComposition.customVideoCompositorClass = VideoFilterCompositor.self
//Add your animator tool as usual
let animator = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: v, in: p)
videoComposition.animationTool = animator
//Finish setting up the composition

这样,您应该能够使用常规方法导出视频AVAssetExportSession,设置其videoComposition

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

使用 CIFilter 在 CALayer 层次结构中渲染视频 的相关文章

  • 如何使用 Swift 获取 YouTube 频道的所有播放列表?

    我的问题不是关于从一般频道检索视频 我只想获取该频道创建的所有 播放列表 并检索每个播放列表的缩略图 标题和视频数量 这是一个 YouTube 频道示例 正如您所看到的 有很多已创建的播放列表 截至目前 我只能获取某个频道最新上传的视频 在
  • FireMonkey iOS RAD Studio XE2 - 在从 URL 加载的表单上显示图像

    是否可以将 TImage 放置在 iOS 的 FMX 表单上 并将图像 jpg 从 URL 加载到此 TImage 中以在 iOS 应用程序中显示 我尝试过但没有成功 任何正确方向的提示或指出都会受到赞赏 将 TButton TImageC
  • iPhone 快照,包括键盘

    我正在寻找拍摄整个 iPhone 屏幕 包括键盘 的正确方法 我找到了一些截取屏幕的代码 CGRect screenCaptureRect UIScreen mainScreen bounds UIView viewWhereYouWant
  • 在 Instruments 中查找内存泄漏行

    我是 iOS 中的仪器新手 我正在尝试使用 Xcode 4 5 2 并按照本教程查找仪器中的内存泄漏 http soulwithmobiletechnology blogspot sg 2011 04 how to check memory
  • iOS7 中“-webkit-overflow-scrolling: touch” 最初的屏幕外元素被破坏

    既然转基因种子已经发布了 我们现在可以谈谈了 看起来 iOS7 中的 webkit overflow scrolling touch 已损坏 最初不在屏幕上的元素的触摸事件不会触发 或者在某些情况下只是不可靠 这是一个例子
  • 应用程序未通过协同设计验证?

    我在提交 iPhone 申请时遇到问题 我看到了一些类似的问题 但没有找到答案 当我存档项目并单击 验证 时 收到错误消息 应用程序未通过协同设计验证 签名无效 或者未使用 Apple 提交证书进行签名 我假设我在协同设计部分做错了什么 我
  • NSPredicate 的 onFormat 字符串

    我想用 id 键对数据进行排序 我如何理解格式字符串的用途NSPredicate格式 我有一个100号的帖子 我的代码 let objectIDs posts map 0 id let predicate NSPredicate forma
  • [UIScreen mainScreen].bounds.size 在 iOS8 中变得依赖于方向吗?

    我在 iOS 7 和 iOS 8 中运行了以下代码 UIInterfaceOrientation orientation UIApplication sharedApplication statusBarOrientation BOOL l
  • 设置 TableView setEditing 时无法选择 UITableViewCell

    我希望能够选择多行 如下所示的默认邮件应用程序 我有一个名为编辑的按钮 可以调用 self myTableView setEditing YES animated YES 编辑按钮成功显示单元格左侧的圆圈 如上所示的邮件应用程序 但是 当我
  • Obj-C / Swift 项目中的致命陷阱异常

    我开始将 Swift 代码集成到我的 Obj C 项目中 一切都进展顺利 但今天 当我更新到 Xcode 6 1 时 事情变得很糟糕 我从之前运行良好的 Swift 代码中收到了许多 陷阱 异常 第一次崩溃位于我的 UIFont 扩展中 这
  • 在ScreenUpdates之后调用drawViewHierarchyInRect时iOS8缩放故障:YES

    我正在将一个项目从 iOS7 转换为 iOS8 该项目使用自定义转换 并且需要在加载完成后捕获模式afterScreenUpdates YES并看到整个屏幕放大一秒钟然后缩小 我还在 iOS 版 Flickr 应用程序的各个部分之间以及在
  • 使用GCD实现并发读独占写模型

    我试图了解使用 Grand Central Dispatch GCD 实现控制资源访问的并发读独占写模型的正确方法 假设有一个 NSMutableDictionary 被大量读取并且偶尔更新 确保读取始终与字典状态一致的正确方法是什么 当然
  • Facebook iOS SDK:登录 Facebook 时无需总是询问应用程序的权限

    我在我的应用程序中使用 Facebook iOS SDK 我有两个类似的问题 有没有办法知道当前是否有用户登录 我现在使用的是在成功登录时存储访问令牌和到期日期 并在应用程序启动时加载它们 我的问题是 如果会话无效 我可以为用户提供登录选项
  • 如何在 Swift 中调用 Objective-C 实例类型方法?

    我有一个 Objective C 类 如下所示 interface CustomObjectHavingData NSObject property nonatomic strong NSData objWithData instancet
  • iOS Safari 通过单击按钮触发扫描信用卡

    您好 我目前正在创建一个测试应用程序 当用户单击文本字段名称或卡号时 扫描信用卡功能对我有用 我的问题是 我希望当用户单击 button1 时发生同样的情况 这应该打开相机来扫描卡并填充现有的文本字段 即名称 卡号和到期日期 额外的好处是
  • 删除 UINavigationBar 下的 1px 边框 - 不起作用

    IBOutlet var navBar UINavigationBar self navBar setBackgroundImage UIImage forBarMetrics UIBarMetrics Default self navBa
  • iOS 11 浏览器图像错误

    在 iOS 11 中滚动页面时出现以下错误 在 Firefox Safari 和 Chrome 中 在 Android 设备中 不会发生该错误 这些是背景图像 我不知道这是否是导致错误的原因 图 2 显示了图像在 Android 中的用途和
  • 观察 UIDatePicker 的变化

    我注意到没有委托来观察 UIDatePicker 中的变化 有没有一种方法可以在不确认任何内容的情况下检测选择器中何时进行更改 例如它旋转并落在新数字上的那一刻 我希望能够检测到这一点 我考虑过关键值观察 但我不认为有一个属性会立即改变 您
  • WKWebView:无需 Javascript 即可缩放PageToFit 行为

    如何获得scalesPageToFit显示在 HTML 内容中的行为WKWebView 不使用 JavaScript 在我们的例子中需要禁用 JS 抱歉没有发布任何代码 但我不知道如何实现这一目标 我所知道的和我找到的所有解决方案都是基于J
  • 如何在 UITableViewCell 上使用自定义初始值设定项?

    我有一个自定义 UITableViewCell 我想在我的表视图中使用它 这是我的单元格代码 class ReflectionCell UITableViewCell IBOutlet weak var header UILabel IBO

随机推荐

  • 如何在R中的xyplot中获得阴影背景?

    using xyplot来自lattice包中 我绘制了多年的时间序列 我会为其中一些年份添加阴影区域 以表明这个时期是 特殊的 例如战争 如果这是微不足道的 请道歉 但我不知道该怎么做 所以如果有人可以帮助我 或者至少为我指出正确的方向
  • 寻找将 Lucene.net 与 ASP.NET 结合使用的示例 [已关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何将三列设为主键

    我正在尝试学习如何将两个文件匹配在一起 但我已经尝试了 5 个小时了 但仍然不知道该怎么做 第一个文件 600 000 行 包含 4 列 Postal Number Houseletter livingspace 第二个文件 7 000 行
  • 如何让 gcloud auth activate-service-account 持续存在

    我正在使用 bq 命令行工具从 Bigquery 表进行查询 当我登录并退出查询进程正在运行的盒子时 有没有办法让服务帐户身份验证持续存在 我所做的步骤 我登录了linux盒子 通过运行以下命令来验证服务帐户 gcloud auth act
  • Java - 当数据超出限制时打印消息?

    我的代码已经可以工作了 虽然不漂亮 但确实是工作 现在我想编写一段代码 如果文本文件中有 19 条或更多数据 则停止加载数据 然后显示例如 显示 输入无效 的消息 我不知道如何做到这一点 所以任何帮助将不胜感激 package stacka
  • htaccess 外部重写/内部重定向

    我想通过 htaccess 文件实现两件事 第一个是 www hostname com index php question gt www hostname com question www hostname com index php m
  • GWT 远程日志记录无法记录 Throwable Stacktrace?

    我想使用 GWT远程记录 http www gwtproject org doc latest DevGuideLogging html 这就是我所做的 在我的 web xml 文件中我做了
  • 用于列出 GCP firebase 函数的 Firebase 命令行

    我有 100 个函数部署到 firebase 我想知道是否可以使用 firebase 命令行工具列出我的计算机上的远程函数 我想查看部署的功能列表 我想解决的是 批量部署功能 避免部署限制 在本地删除 重命名函数然后部署整个函数时出现部署错
  • 截断 UILabel 中的部分文本

    我的要求是 我需要在标签中显示文本 如果文本长度太大而无法容纳在一行中 我需要在末尾截断它 这样只有最后几个字符 通常是黑白 1 1000 的数字 因此文本长度可能会有所不同 是可见的 并且其之前的文本被 截断 所以文本看起来像 abcde
  • kubernetes skydns 转发请求失败

    我正在创建一个 1 个主节点 2 个节点的 kubernetes 集群 我正在尝试基于以下内容创建 skydns apiVersion v1 kind ReplicationController metadata name kube dns
  • ANACONDA navigator 无法启动-from win32com.shell import shellcon, shell

    我已经下载并安装了 ANACONDA Anaconda3 2020 02 Windows x86 但是 我发现我无法启动 ANACONDA 导航器 因此我尝试使用命令行并获得了反馈 from win32com shell import sh
  • 无法获取 dicom 图像以在 python 中显示

    我正在尝试在 opencv python 中显示 DICOM 图像 我正在使用 pydicom 库 然后添加 API 来使用 DOTNET 创建一个完整的 DICOM 查看器 该查看器运行 python 当然 C 使用流程实例调用 pyth
  • AMD 相当于 NvOptimusEnablement

    对于 Intel NVIDIA 双 GPU Optimus 设置 应用程序可以导出NvOptimusEnablement如中所解释的Optimus渲染策略 pdf http developer download nvidia com dev
  • ADP 文件中的数据库连接信息在哪里? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 用户输入了他们每天使用的旧 Access 数据库和表单项目的票证 他们说使用数据库时找不到数据库 自大学以来我就没有使用过 MS Access 来设计
  • 如何轻松打包分析核心转储所需的库(即 packcore)

    HPUX 上可用的 GDB 版本有一个名为 packcore 的命令 该命令创建一个包含核心转储 可执行文件和所有库的 tarball 当尝试在不同的机器上调试核心转储时 我发现这非常有用 在 Linux 机器上的 GDB 标准版本中是否有
  • 使用 Autofac 与 AutoMapper Profile 进行 IoC

    我使用 AutoMapper 一段时间了 我的个人资料设置如下 public class ViewModelAutoMapperConfiguration Profile protected override string ProfileN
  • WiX 卸载 - 在重新启动管理器之前关闭应用程序

    我有一个用 WiX 完成的安装程序 安装完成后 它会启动一个应用程序 在资源管理器进程中注入一些代码 目前 当我卸载时 重新启动管理器会启动并关闭我的应用程序和资源管理器 相反 我想手动关闭我的应用程序 这是通过在命令行上使用 exit 再
  • Scala 推断类型参数 - 推断为“Nothing”的类型边界

    我正在尝试编写一个简单的查询 monad 但无法获取我的generic键入注释正确 我的第一次尝试如下 为了简洁而大大简化 case class Person val name String abstract class Schema T
  • 将实体集合拆分为 n 个部分

    我有一个数据库表 首先 我想按日期时间分组 然后我只想选择有 n 个项目的组 我的班级是这样的 public class VisitDate public int Id get set public int VisitMeDate get
  • 使用 CIFilter 在 CALayer 层次结构中渲染视频

    在我的 iOS 应用程序的 UI 中 我显示了一个复杂的层次结构CALayers 其中一层是AVPlayerLayer显示视频CIFilter实时应用 使用AVVideoComposition asset applyingCIFilters