为什么在快速合并两个视频或更改背景音乐后视频变成黑屏?

2024-05-09

在我的 ios 应用程序中,我想合并两个视频并更改背景音乐。我尝试过,对于普通视频来说效果很好。但是,当我选择任何延时视频,然后尝试合并或更改背景音乐时,视频变成全黑屏。

对于我的应用程序,我使用 swift 4.2 和 xcode-10。我也在 swift 4 和 swift 5 中尝试过,都返回相同的结果。

这是我的代码:

class Export: NSObject {

    let defaultSize = CGSize(width: 1920, height: 1920)
    typealias Completion = (URL?, Error?) -> Void

    func mergeVideos(arrayVideos:[URL], exportURL: URL, completion:@escaping Completion) -> Void {

        var errors: Error!
        var insertTime = kCMTimeZero
        var arrayLayerInstructions:[AVMutableVideoCompositionLayerInstruction] = []
        var outputSize = CGSize(width: 0, height: 0)

        // Determine video output size
        for url in arrayVideos {

            let videoAsset = AVAsset(url: url)
            let videoTrack = videoAsset.tracks(withMediaType: AVMediaType.video)[0]

            var videoSize = videoTrack.naturalSize.applying(videoTrack.preferredTransform)

            videoSize.width = fabs(videoSize.width)
            videoSize.height = fabs(videoSize.height)

            if outputSize.height == 0 || videoSize.height > outputSize.height {
                outputSize.height = videoSize.height
            }

            if outputSize.width == 0 || videoSize.width > outputSize.width {
                outputSize.width = videoSize.width
            }
        }

        // Silence sound (in case of video has no sound track)
        guard let silenceURL = Bundle.main.url(forResource: "silence", withExtension: "mp3") else { completion(nil, errors); return }
        let silenceAsset = AVAsset(url:silenceURL)
        let silenceSoundTrack = silenceAsset.tracks(withMediaType: AVMediaType.audio).first

        // Init composition
        let mixComposition = AVMutableComposition.init()

        for url in arrayVideos {

            let videoAsset = AVAsset(url: url)
            // Get video track
            guard let videoTrack = videoAsset.tracks(withMediaType: AVMediaType.video).first else {

                print("video asset track not found")
                continue
            }

            // Get audio track
            var audioTrack:AVAssetTrack?
            if videoAsset.tracks(withMediaType: AVMediaType.audio).count > 0 {
                audioTrack = videoAsset.tracks(withMediaType: AVMediaType.audio).first
            }
            else {
                audioTrack = silenceSoundTrack
            }

            // Init video & audio composition track
            guard let videoCompositionTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else { completion(nil, errors); return }

            guard let audioCompositionTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) else { completion(nil, errors); return }

            do {
                let startTime = kCMTimeZero
                let duration = videoAsset.duration

                // Add video track to video composition at specific time
                try videoCompositionTrack.insertTimeRange(CMTimeRangeMake(startTime, duration),
                                                           of: videoTrack,
                                                           at: insertTime)

                // Add audio track to audio composition at specific time
                if let audioTrack = audioTrack {
                    try audioCompositionTrack.insertTimeRange(CMTimeRangeMake(startTime, duration),
                                                               of: audioTrack,
                                                               at: insertTime)
                }

                // Add instruction for video track
                let layerInstruction = videoCompositionInstructionForTrack(track: videoCompositionTrack, asset: videoAsset, standardSize: outputSize,  atTime: insertTime)

                // Hide video track before changing to new track
                let endTime = CMTimeAdd(insertTime, duration)
                layerInstruction.setOpacity(0, at: endTime)
                arrayLayerInstructions.append(layerInstruction)

                // Increase the insert time
                insertTime = CMTimeAdd(insertTime, duration)
            }
            catch {
                print("Load track error")
            }
        }

        // Main video composition instruction
        let mainInstruction = AVMutableVideoCompositionInstruction()
        mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, insertTime)
        mainInstruction.layerInstructions = arrayLayerInstructions

        // Main video composition
        let mainComposition = AVMutableVideoComposition() 
        mainComposition.instructions = [mainInstruction]
        mainComposition.frameDuration = CMTimeMake(1, 30)
        mainComposition.renderSize = outputSize

        // Init exporter
        guard let exporter = AVAssetExportSession.init(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) else {

            errors = "exporter initialization failed" as? Error
            completion(nil, errors)
            return
        }
        exporter.outputURL = exportURL
        exporter.outputFileType = AVFileType.mov
        exporter.shouldOptimizeForNetworkUse = true
        exporter.videoComposition = mainComposition

        // Do export
        exporter.exportAsynchronously(completionHandler: {


        })

    }
}

// MARK:- Private methods
extension Export {
    fileprivate func orientationFromTransform(transform: CGAffineTransform) -> (orientation: UIImageOrientation, isPortrait: Bool) {
        var assetOrientation = UIImageOrientation.up
        var isPortrait = false
        if transform.a == 0 && transform.b == 1.0 && transform.c == -1.0 && transform.d == 0 {
            assetOrientation = .right
            isPortrait = true
        } else if transform.a == 0 && transform.b == -1.0 && transform.c == 1.0 && transform.d == 0 {
            assetOrientation = .left
            isPortrait = true
        } else if transform.a == 1.0 && transform.b == 0 && transform.c == 0 && transform.d == 1.0 {
            assetOrientation = .up
        } else if transform.a == -1.0 && transform.b == 0 && transform.c == 0 && transform.d == -1.0 {
            assetOrientation = .down
        }
        return (assetOrientation, isPortrait)
    }

    fileprivate func videoCompositionInstructionForTrack(track: AVCompositionTrack, asset: AVAsset, standardSize:CGSize, atTime: CMTime) -> AVMutableVideoCompositionLayerInstruction {

        let instruction = AVMutableVideoCompositionLayerInstruction(assetTrack: track)
        let assetTrack = asset.tracks(withMediaType: AVMediaType.video)[0]
        let assetSize = assetTrack.naturalSize

        let transform = assetTrack.preferredTransform
        let assetInfo = orientationFromTransform(transform: transform)

        let aspectFillRatio:CGFloat = 1

        if assetInfo.isPortrait {

            let scaleFactor = CGAffineTransform(scaleX: aspectFillRatio, y: aspectFillRatio)
            let posX = standardSize.width/2 - (assetSize.height * aspectFillRatio)/2
            let posY = standardSize.height/2 - (assetSize.width * aspectFillRatio)/2
            let moveFactor = CGAffineTransform(translationX: posX, y: posY)

            instruction.setTransform(assetTrack.preferredTransform.concatenating(scaleFactor).concatenating(moveFactor), at: atTime)

        } else {
            let scaleFactor = CGAffineTransform(scaleX: aspectFillRatio, y: aspectFillRatio)
            let posX = standardSize.width/2 - (assetSize.width * aspectFillRatio)/2
            let posY = standardSize.height/2 - (assetSize.height * aspectFillRatio)/2
            let moveFactor = CGAffineTransform(translationX: posX, y: posY)
            var concat = assetTrack.preferredTransform.concatenating(scaleFactor).concatenating(moveFactor)

            if assetInfo.orientation == .down {
                let fixUpsideDown = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
                concat = fixUpsideDown.concatenating(scaleFactor).concatenating(moveFactor)
            }

            instruction.setTransform(concat, at: atTime)
        }
        return instruction
    }
}

我预计延时视频会像普通视频一样工作并且不会出现黑屏


// 主视频合成指令

将此代码替换为以下代码

    let instruction = AVMutableVideoCompositionInstruction()
    instruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: mutableComposition.duration)

    let videotrack = mutableComposition.tracks(withMediaType: AVMediaType.video)[0] as AVAssetTrack
    let layerinstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videotrack)
    
    let rgb = CGColorSpaceCreateDeviceRGB()
    let myColor : [CGFloat] = [1.0, 1.0, 1.0, 1.0] //white
    let ref = CGColor(colorSpace: rgb, components: myColor)
    instruction.backgroundColor = ref

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

为什么在快速合并两个视频或更改背景音乐后视频变成黑屏? 的相关文章

随机推荐

  • PowerShell 中的触摸功能

    我最近在 PowerShell 配置文件中添加了触摸功能 PS gt notepad profile function touch Set Content Path args 0 Value null 保存并运行测试 touch myfil
  • 向 Python 2.6 添加 SSL 支持

    我尝试使用sslPython 2 6 中的模块 但我被告知它不可用 安装OpenSSL后 我重新编译2 6 但问题仍然存在 有什么建议么 您安装了 OpenSSL 开发库吗 我必须安装openssl devel例如 在 CentOS 上 在
  • 在 android studio 上单击推送通知后重定向到特定活动

    我正在努力开发一个 Android 应用程序 以便在单击所有传入的推送通知时将应用程序重定向到特定的活动页面 我是 Android 开发新手 对我的编程感到抱歉 下面是推送通知部分的 android manifest xml 如果对此主题有
  • Paradox 表 - Oledb 异常:外部表不是预期的格式

    我正在使用 Oledb 从 Paradox 表中读取一些数据 我遇到的问题是 当我将代码复制到控制台应用程序时 代码可以工作 但在 WinForms 中却不行 两者都以 x86 进行调试 我实际上只是复制代码 在 WinForms 应用程序
  • 如何将 wsdl 内部架构设置为 Jaxb2Marshaller 以验证我所做的每篇文章?

    我正在使用 SOAP Web 服务 在调用它之前我必须验证每个 xml 帖子 所以我正在使用 The CXF codegen 插件生成POJO树结构 第三部分 wsdl xxxx soap service wsdl 一个类实现Web服务网关
  • KineticJS - 将舞台缩放到视口

    我正在努力将默认分辨率设置为 1366x756 我会根据视口来放大和缩小它 类似于此处显示的示例 http blogs msdn com b davrous archive 2012 04 06 modernizing your html5
  • 在ansible中合并字典

    我目前正在构建一个使用 ansible 安装 PHP 的角色 并且在合并字典时遇到一些困难 我尝试了多种方法来做到这一点 但我无法让它像我想要的那样工作 A vars file my default values key value my
  • 矩阵向量变换

    我正在编写一个代码来制作软件蒙皮器 骨骼 皮肤动画 并且我正处于 优化 阶段 蒙皮器工作得很好 并且在 Core 上 1 09 毫秒内对 4900 个三角形网格与 22 个骨骼进行蒙皮Duo 2 Ghz 笔记本 我需要知道的是 1 有人可以
  • 通过单击字段启用非活动字段

    是否可以有一组非活动字段 如果单击其中一个字段 则某些字段将变为必填字段并运行某些代码段 举例来说 您显示了三个字段
  • Google 翻译 TTS API 被阻止

    Google 实施了验证码来阻止人们访问 TTS 翻译 API 我在我的移动应用程序中使用它 现在 它没有返回任何东西 如何绕过验证码 将限定符 client tw ob 添加到查询末尾 这个答案不再一致有效 如果你滥用这个IP地址 你的I
  • 重命名($project)数组中的字段 - MongoDB [重复]

    这个问题在这里已经有答案了 我有一个类似以下的文件 id 59ba903dacea50d0d7d47168 sections id 59d9dd7947ce651544c5d4c1 sectionName Section 1 id 59d9
  • ios7 绘图时出现延迟

    我有一个应用程序 在其中我正在视图上绘制一些草图 到目前为止 在我安装之前它运行良好ios7 我的应用程序使用触摸移动方法来识别运动的变化 但是当我画一条线时 触摸方法被调用 但线不会更新 直到我触摸结束ios7 所以画起来有一点点滞后 它
  • 如何在已实现特征的现有类型的枚举范围内实现特征?

    如何在已实现特征的现有类型的枚举范围内实现特征 我有这个 extern crate pnet use pnet packet ipv4 Ipv4Packet use pnet packet ipv6 Ipv6Packet enum Ethe
  • 为什么要检查 Bower 组件?

    鲍尔文档说 注意 如果您没有编写供其他人使用的包 例如 您正在构建 Web 应用程序 则应始终将已安装的包签入源代码管理 有谁能很好地回答为什么吗 如果我正在制作一个网络应用程序 我不希望我的存储库因库 X 版本的更新而混乱 我只想更新 B
  • Keycloak 社交登录 REST API

    我已经为我的 keycloak 实例启用了谷歌社交登录 但我需要将其用作休息服务 是否有可用于执行此操作的端点 Keycloak 中没有 Google 身份验证 API 但您可以使用以下方法解决它代币交换 https www keycloa
  • 在 Java 5 及更高版本中迭代 java.util.Map 的所有键/值对的最简单方法是什么?

    在 Java 5 及更高版本中迭代 java util Map 的所有键 值对的最简单方法是什么 假设K是您的密钥类型 并且V是你的值类型 for Map Entry
  • 在Powershell中,如何设置$?不将该值发送到管道?

    PS gt gci C lt
  • ApplicationEventMulticaster 未初始化 - 在多播事件之前调用“刷新”

    我正在尝试实施ehcache对于我的应用程序 但是当尝试调用服务器时 出现以下错误 java lang IllegalStateException ApplicationEventMulticaster not initialized ca
  • Xcode 7 Playground 执行 EXC_BAD_ACCESS

    在 Xcode 7 Playgrounds 中运行最简单的默认代码 得到以下错误 Playground execution failed Execution was interrupted reason EXC BAD ACCESS cod
  • 为什么在快速合并两个视频或更改背景音乐后视频变成黑屏?

    在我的 ios 应用程序中 我想合并两个视频并更改背景音乐 我尝试过 对于普通视频来说效果很好 但是 当我选择任何延时视频 然后尝试合并或更改背景音乐时 视频变成全黑屏 对于我的应用程序 我使用 swift 4 2 和 xcode 10 我