ios - Duet - 并排合并 2 个视频

标签 ios swift avfoundation swift4.2

注意:-并排合并视频而不损失视频质量

我认为这是一个非常非常重要的问题,经过大量搜索和谷歌搜索后,没有找到与此问题相关的任何有用 Material 。

我正在做一个项目,我需要在一个文件中并排合并视频。

我已经使用 AVFoundation 完成了合并视频 但问题是第一个视频显示为第二个视频的叠加层(与 SMULE 应用程序/卡拉 OK 应用程序或 Tiktok 应用程序一样正确合并).

func mergeVideosFilesWithUrl(savedVideoUrl: URL, newVideoUrl: URL, audioUrl:URL)
    {
        let savePathUrl : NSURL = NSURL(fileURLWithPath: NSHomeDirectory() + "/Documents/camRecordedVideo.mp4")
        do { // delete old video
            try FileManager.default.removeItem(at: savePathUrl as URL)
        } catch { print(error.localizedDescription) }

        var mutableVideoComposition : AVMutableVideoComposition = AVMutableVideoComposition()
        var mixComposition : AVMutableComposition = AVMutableComposition()

        let aNewVideoAsset : AVAsset = AVAsset(url: newVideoUrl)
        let asavedVideoAsset : AVAsset = AVAsset(url: savedVideoUrl)

        let aNewVideoTrack : AVAssetTrack = aNewVideoAsset.tracks(withMediaType: AVMediaType.video)[0]
        let aSavedVideoTrack : AVAssetTrack = asavedVideoAsset.tracks(withMediaType: AVMediaType.video)[0]

        let mutableCompositionNewVideoTrack : AVMutableCompositionTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)!
        do{
            try mutableCompositionNewVideoTrack.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: aNewVideoAsset.duration), of: aNewVideoTrack, at: CMTime.zero)
        }catch {  print("Mutable Error") }

        let mutableCompositionSavedVideoTrack : AVMutableCompositionTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)!
        do{
            try mutableCompositionSavedVideoTrack.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: asavedVideoAsset.duration), of: aSavedVideoTrack , at: CMTime.zero)
        }catch{ print("Mutable Error") }

        let mainInstruction = AVMutableVideoCompositionInstruction()
        mainInstruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: CMTimeMaximum(aNewVideoAsset.duration, asavedVideoAsset.duration) )

        let newVideoLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: mutableCompositionNewVideoTrack)
        let newScale : CGAffineTransform = CGAffineTransform.init(scaleX: 0.7, y: 0.7)
        let newMove : CGAffineTransform = CGAffineTransform.init(translationX: 230, y: 230)
        newVideoLayerInstruction.setTransform(newScale.concatenating(newMove), at: CMTime.zero)

        let savedVideoLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: mutableCompositionSavedVideoTrack)
        let savedScale : CGAffineTransform = CGAffineTransform.init(scaleX: 1.2, y: 1.5)
        let savedMove : CGAffineTransform = CGAffineTransform.init(translationX: 0, y: 0)
        savedVideoLayerInstruction.setTransform(savedScale.concatenating(savedMove), at: CMTime.zero)

        mainInstruction.layerInstructions = [newVideoLayerInstruction, savedVideoLayerInstruction]


        mutableVideoComposition.instructions = [mainInstruction]
        mutableVideoComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)
        mutableVideoComposition.renderSize = CGSize(width: 1240 , height: self.camPreview.frame.height)

        finalPath = savePathUrl.absoluteString
        let assetExport: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)!
        assetExport.videoComposition = mutableVideoComposition
        assetExport.outputFileType = AVFileType.mov

        assetExport.outputURL = savePathUrl as URL
        assetExport.shouldOptimizeForNetworkUse = true

        assetExport.exportAsynchronously { () -> Void in
            switch assetExport.status {

            case AVAssetExportSession.Status.completed:
                print("success")
            case  AVAssetExportSession.Status.failed:
                print("failed \(assetExport.error)")
            case AVAssetExportSession.Status.cancelled:
                print("cancelled \(assetExport.error)")
            default:
                print("complete")
            }
        }

    }

这是我的输出 enter image description here

还有我想要的

enter image description here

因为我不知道制作 SIDE BY SIDE VIDEO/DUET VIDEO 的最佳方法是什么...至于现在,我使用了 AVFoundation。我没有使用任何第 3 方框架或任何 POD。

我想问一下,实现这个的最佳方法是什么?视频应该在服务器端还是应用程序上合并?还有我应该使用哪种方法?

任何帮助将不胜感激。谢谢

最佳答案

为此,我将创建一个包含 2 个轨道的新 AVMutableComposition 对象,并在每个轨道上设置变换以将它们并排放置:

let composition = AVMutableComposition(urlAssetInitializationOptions: <your options>)
let videoTrackA = composition.addMutableTrack(withMediaType:.video, preferredTrackID:kCMPersistentTrackID_Invalid);
let videoTrackB = composition.addMutableTrack(withMediaType:.video, preferredTrackID:kCMPersistentTrackID_Invalid);

videoTrackA.preferredTransform = CGAffineTransform(translationX: <yourX_for_A>, y:0.0)
videoTrackB.preferredTransform = CGAffineTransform(translationX: <yourX_for_B>, y:0.0)

然后。使用以下方法保存:

let exporter = AVAssetExportSession(asset:<yourAsset>, presetName:<yourPresetName>)
exporter.exportAsynchronously(completionHandler: <yourCompletionHandler>)

(未测试 Swift 代码)。

关于ios - Duet - 并排合并 2 个视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55771275/

相关文章:

path - 如何将代码 objective-c 转换为 Swift 以保存图像?

ios - 如何跟踪同一 SKSpriteNode 的各个实例

ios - touchesBegan 未在 UIView 子类中调用

ios - 从 WKWebview 中删除/剥离 HTML 类

swift - Mac Catalyst 上的应用内购买不起作用

swift - BluetoothLE 会扰乱定时器计时吗?

ios - AVAudioSession - 如何在扬声器和耳机输出之间切换

ios - Objective-c,在 AVPlayer 类型的对象上找不到属性 'frame'

ios - UITableview Cell 动画只播放一次

ios - 使用 xcode 和 swift 在 IOS 中向下触摸/向上触摸