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

发布于 2025-01-09 01:39:39 字数 3699 浏览 1 评论 0原文

我正在尝试将使用 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=此媒体不支持该操作。, NSLocalizedDescription=操作已停止}

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

i'm trying to add audio file selected with MPMediaPickerController to video with AVMutableVideoComposition, but it gives error and doesn't work.

picking audio like this :

    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) !!!")
    }
    
}

and mixing audio and video like this :

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)
    }
}
    
}

if i play that audio with AVAudioPlayer then it is playing but if i add in video it gives error {Error Domain=NSOSStatusErrorDomain Code=-12109 "(null)"}, NSLocalizedFailureReason=The operation is not supported for this media., NSLocalizedDescription=Operation Stopped}

any help or tip would be really appreciated, thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

趁年轻赶紧闹 2025-01-16 01:39:39

如果我将音频文件添加到项目目录,然后使用捆绑包 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!")
    }

If i add audio file to project directory and then access it with bundle url then it works fine it just doesn't work with audio picked through MPMediaPicker.

This is how i was able to make it work :

stored it as AVPlayerItem in variable like this

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)
}

then in mergeVideo function accessed it's track like this

        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!")
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文