两层显示相同的视频

问题描述 投票:0回答:1

我正在为视频创建两个图层,并尝试在每个单独的图层上显示我自己的 URL 和视频。我做错了什么?我在视频层和覆盖层上仅显示最终结果中的第一个视频。 问题:在最终输出视频中,我在视频层和覆盖层上仅看到来自第一个 URL (videoURL) 的视频。覆盖层未按预期显示来自overlayVideoURL 的视频。
我尝试过的: 我检查了 CALayer 框架并确认它们设置正确。 已验证 AVVideoCompositionCoreAnimationTool 是否正确使用。 确认 AVMutableComposition 已插入两条轨道。 问题: 我设置视频图层的方式是否有错误? 如何保证每一层正确显示各自的视频? 其他详细信息: 视频已正确加载并插入到 AVMutableComposition 中。 最终的合成仅在两层上显示来自 videoURL 的视频。

 func makeVideo(videoURL: URL, overlayVideoURL: URL, forName name: String, onComplete: @escaping (URL?) -> Void) {
            let asset = AVURLAsset(url: videoURL)
            let overlayAsset = AVURLAsset(url: overlayVideoURL)
            let composition = AVMutableComposition()
            guard
                let compositionTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid),
                let assetTrack = asset.tracks(withMediaType: .video).first,
                let overlayCompositionTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid),
                let overlayAssetTrack = overlayAsset.tracks(withMediaType: .video).first
            else {
                print("Something is wrong with the assets.")
                onComplete(nil)
                return
            }
            do {
                let timeRange = CMTimeRange(start: .zero, duration: asset.duration)
                try compositionTrack.insertTimeRange(timeRange, of: assetTrack, at: .zero)
                try overlayCompositionTrack.insertTimeRange(timeRange, of: overlayAssetTrack, at: .zero)
            } catch {
                print(error)
                onComplete(nil)
                return
            } 
            let videoInfo = orientation(from: assetTrack.preferredTransform)
            let videoSize = videoInfo.isPortrait ? CGSize(width: assetTrack.naturalSize.height, height: assetTrack.naturalSize.width) : assetTrack.naturalSize
            let videoComposition = AVMutableVideoComposition()
            videoComposition.renderSize = videoSize
            videoComposition.frameDuration = CMTime(value: 1, timescale: 30) 
            let instruction = AVMutableVideoCompositionInstruction()
            instruction.timeRange = CMTimeRange(start: .zero, duration: composition.duration)
            let layerInstruction = compositionLayerInstruction(for: compositionTrack, assetTrack: assetTrack)
            let overlayLayerInstruction = compositionLayerInstruction(for: overlayCompositionTrack, assetTrack: overlayAssetTrack)
            instruction.layerInstructions = [layerInstruction, overlayLayerInstruction]
            videoComposition.instructions = [instruction]
            let videoLayer = CALayer()
            videoLayer.frame = CGRect(origin: .zero, size: videoSize)
            let overlayVideoLayer = CALayer()
            overlayVideoLayer.frame = CGRect(x: videoSize.width / 4, y: videoSize.height / 4, width: videoSize.width / 2, height: videoSize.height / 2)
            let outputLayer = CALayer()
            outputLayer.frame = CGRect(origin: .zero, size: videoSize)
            outputLayer.addSublayer(videoLayer)
            outputLayer.addSublayer(overlayVideoLayer)
            videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayers: [videoLayer, overlayVideoLayer], in: outputLayer)
            guard let export = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) else {
                print("Cannot create export session.")
                onComplete(nil)
                return
            }
            let videoName = UUID().uuidString
            let exportURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(videoName).appendingPathExtension("mov")
            export.videoComposition = videoComposition
            export.outputFileType = .mov
            export.outputURL = exportURL
            export.exportAsynchronously {
                DispatchQueue.main.async {
                    switch export.status {
                    case .completed:
                        onComplete(exportURL)
                    default:
                        print("Something went wrong during export.")
                        print(export.error ?? "unknown error")
                        onComplete(nil)
                    }
                }
            }
        }
ios swift xcode swiftui avfoundation
1个回答
0
投票

尝试使用

AVMutableVideoCompositionLayerInstruction
而不是
AVMutableVideoComposition
。计划是这样的:

// Here how to build it:
let mainInstruction = AVMutableVideoCompositionInstruction()
// Set time of your result video duration
mainInstruction.timeRange = timeRange
// For each video you'll need a separate AVMutableVideoCompositionInstruction
let videoInstruction = AVMutableVideoCompositionInstruction()
let overlayInstruction = AVMutableVideoCompositionInstruction()
// Now how to build and setup those instructions
// Here's your asset
let asset = AVAsset(url: url)
if let audioTrack = asset.tracks(withMediaType: .audio).first,
   let compositionAudioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) {
    // Add audio track
}
let track = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)!
try! track.insertTimeRange(CMTimeRange(start: .zero, duration: asset.duration), of: asset.tracks(withMediaType: .video).first!, at: .zero)
let instruction /*videoInstruction/overlayInstruction*/ = AVMutableVideoCompositionLayerInstruction(assetTrack: track)
/* frameTransform shoule be calculated to move video track to the proper location on the layer */
instruction.setTransform(transform.concatenating(frameTransform), at: .zero)
// It will combine instructions for several layers
mainInstruction.layerInstructions = [videoInstruction, overlayInstruction]
// Video composition should have only one instruction
videoComposition.instructions = [mainInstruction]
// Then apply add videoComposition to a single layer, this single layer will render both videos in the locations determined by trannsform
videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer)

抱歉代码混乱,它所基于的示例更加混乱,所以我尝试从中提取重要的内容

© www.soinside.com 2019 - 2024. All rights reserved.