音频文件播放正常但无法添加到 AVMutableVideoComposition

audio file plays fine but can't add in AVMutableVideoComposition

我正在尝试将使用 MPMediaPickerController 选择的音频文件添加到使用 AVMutableVideoComposition 的视频中,但它给出了错误并且不起作用。

像这样挑选音频:

    func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
    
    if let musicUrl: NSURL = mediaItemCollection.items.first?.assetURL as NSURL? {
        musicURL = musicUrl as URL
        print("Music URL in did select \(musicUrl) !!!")
    }
    
}

并像这样混合音频和视频:

func testMerge(url: URL) {
    
    let firstVideo = AVAsset(url: url)
    var audioAsset = AVAsset(url: musicURL!)
    
    print("Music URL\(musicURL)")

    let firstVideoTrack = firstVideo.tracks(withMediaType: AVMediaType.video).first
    
    let mixComposition = AVMutableComposition()
    
    let audioTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
    let firstTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)) 
    
    do {
        try firstTrack?.insertTimeRange(CMTimeRange(start: .zero, duration: firstVideo.duration), of: firstVideoTrack!, at: .zero)
        
        if musicURL.isFileURL {
            try audioTrack?.insertTimeRange(CMTimeRange(start: .zero, duration: firstVideo.duration), of: audioAsset.tracks(withMediaType: AVMediaType.audio).first, at: .zero)
        }
        
    } catch {
        debugPrint("Can't get track from the Video URL!")
    }
    
    let mainInstruction = AVMutableVideoCompositionInstruction()
    mainInstruction.timeRange = CMTimeRangeMake(start: .zero, duration: firstVideo.duration)
    
    let firstLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: firstTrack!)
        
    let scale = CGAffineTransform(scaleX: 1, y: 1)
    firstLayerInstruction.setTransform(scale, at: .zero)
    
    mainInstruction.layerInstructions = [firstLayerInstruction]
    
let mainCompositionInstruction = AVMutableVideoComposition()
mainCompositionInstruction.instructions = [mainInstruction]
mainCompositionInstruction.frameDuration = CMTimeMake(value: 1, timescale: 30)
mainCompositionInstruction.renderSize = CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)

guard let documentDirectory = FileManager.default.urls (
    for: .documentDirectory,
    in: .userDomainMask).first else { print("ERROR"); return }

let url = documentDirectory.appendingPathComponent("mergeVideo-\(arc4random() % 10000).mp4")

guard let assetExport = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) else {print("ERROR"); return }

assetExport.videoComposition = mainCompositionInstruction
assetExport.outputFileType = .mp4
assetExport.shouldOptimizeForNetworkUse = true
assetExport.outputURL = url
assetExport.exportAsynchronously {
    switch assetExport.status {
            case  AVAssetExportSessionStatus.failed:
                print("failed \(String(describing: assetExport.error))")
            case AVAssetExportSessionStatus.cancelled:
                print("cancelled \(String(describing: assetExport.error))")
            case AVAssetExportSessionStatus.completed:
                print("Completed")
                print(url)
                
            default:
                print("unknown")
            }
    
    DispatchQueue.main.async {
        self.exportDidFinish(assetExport)
    }
}
    
}

如果我用 AVAudioPlayer 播放那个音频然后它正在播放但是如果我添加视频它给出错误 {Error Domain=NSOSStatusErrorDomain Code=-12109 "(null)"}, NSLocalizedFailureReason=The operation此媒体不支持。, NSLocalizedDescription=Operation Stopped}

非常感谢任何帮助或提示,谢谢。

如果我将音频文件添加到项目目录,然后使用包 url 访问它,那么它工作正常,只是不适用于通过 MPMediaPicker 挑选的音频。

这就是我让它工作的方式:

像这样在变量中将其存储为 AVPlayerItem

var playerItem: AVPlayerItem!        

func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
    
    if let musicUrl: NSURL = mediaItemCollection.items.first?.assetURL as NSURL? {
        musicURL = musicUrl as URL
        print("Music URL in did select \(musicUrl) !!!")
    }
    
    playerItem = AVPlayerItem(url: musicURL)
}

然后在 mergeVideo 函数中访问它的轨道是这样的

        do {
        try firstTrack?.insertTimeRange(CMTimeRange(start: .zero, duration: durationTrack.duration), of: firstVideoTrack!, at: .zero)
        try secondTrack?.insertTimeRange(CMTimeRange(start: .zero, duration: durationTrack.duration), of: secondVideoTrack!, at: .zero)
        
        if playerItem != nil {
            let sourceAudio = playerItem.asset.tracks(withMediaType: .audio).first
            
            let audioTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
            try audioTrack?.insertTimeRange(CMTimeRange(start: .zero, duration: durationTrack.duration), of: sourceAudio!, at: .zero)
        }
        
    } catch {
        debugPrint("Can't get track from the Video URL!")
    }