AVAssetExportSession在运行时不起作用

时间:2018-07-10 04:55:21

标签: ios swift xcode avfoundation

我想合并视频和音频文件。我的程序在调试/跳过模式下可以正常运行,但在运行时无法运行。我想这可能与“ exportAsynchronously”功能有关,在加载之前我访问了一些值。这是我的代码。

合并视频和音频的功能:

func mergeVideoAndAudio(videoUrl: URL,
                        audioUrl: URL,
                        shouldFlipHorizontally: Bool = false,
                        completion: @escaping (_ error: Error?, _ url: URL?) -> Void) {

    let mixComposition = AVMutableComposition()
    var mutableCompositionVideoTrack = [AVMutableCompositionTrack]()
    var mutableCompositionAudioTrack = [AVMutableCompositionTrack]()
    var mutableCompositionAudioOfVideoTrack = [AVMutableCompositionTrack]()

    //start merge

    let aVideoAsset = AVAsset(url: videoUrl)
    let aAudioAsset = AVAsset(url: audioUrl)

    let compositionAddVideo = mixComposition.addMutableTrack(withMediaType: AVMediaType.video,
                                                             preferredTrackID: kCMPersistentTrackID_Invalid)

    let compositionAddAudio = mixComposition.addMutableTrack(withMediaType: AVMediaType.audio,
                                                             preferredTrackID: kCMPersistentTrackID_Invalid)

    let compositionAddAudioOfVideo = mixComposition.addMutableTrack(withMediaType: AVMediaType.audio,
                                                                    preferredTrackID: kCMPersistentTrackID_Invalid)

    let aVideoAssetTrack: AVAssetTrack = aVideoAsset.tracks(withMediaType: AVMediaType.video)[0]
    let aAudioOfVideoAssetTrack: AVAssetTrack? = aVideoAsset.tracks(withMediaType: AVMediaType.audio).first
    let aAudioAssetTrack: AVAssetTrack = aAudioAsset.tracks(withMediaType: AVMediaType.audio)[0]

    // Default must have tranformation
    compositionAddVideo?.preferredTransform = aVideoAssetTrack.preferredTransform

    if shouldFlipHorizontally {
        // Flip video horizontally
        var frontalTransform: CGAffineTransform = CGAffineTransform(scaleX: -1.0, y: 1.0)
        frontalTransform = frontalTransform.translatedBy(x: -aVideoAssetTrack.naturalSize.width, y: 0.0)
        frontalTransform = frontalTransform.translatedBy(x: 0.0, y: -aVideoAssetTrack.naturalSize.width)
        compositionAddVideo?.preferredTransform = frontalTransform
    }

    mutableCompositionVideoTrack.append(compositionAddVideo!)
    mutableCompositionAudioTrack.append(compositionAddAudio!)
    mutableCompositionAudioOfVideoTrack.append(compositionAddAudioOfVideo!)

    do {
        try mutableCompositionVideoTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero,
                                                                            aVideoAssetTrack.timeRange.duration),
                                                            of: aVideoAssetTrack,
                                                            at: kCMTimeZero)

        //In my case my audio file is longer then video file so i took videoAsset duration
        //instead of audioAsset duration
        try mutableCompositionAudioTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero,
                                                                            aVideoAssetTrack.timeRange.duration),
                                                            of: aAudioAssetTrack,
                                                            at: kCMTimeZero)

        // adding audio (of the video if exists) asset to the final composition
        if let aAudioOfVideoAssetTrack = aAudioOfVideoAssetTrack {
            try mutableCompositionAudioOfVideoTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero,
                                                                                       aVideoAssetTrack.timeRange.duration),
                                                                       of: aAudioOfVideoAssetTrack,
                                                                       at: kCMTimeZero)
        }
    } catch {
        print(error.localizedDescription)
    }

    // Exporting
    let savePathUrl: URL = URL(fileURLWithPath: NSHomeDirectory() + "/Documents/newVideo.mp4")
    do { // delete old video
        try FileManager.default.removeItem(at: savePathUrl)
    } catch { print(error.localizedDescription) }

    let assetExport: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)!
    assetExport.outputFileType = AVFileType.mp4
    assetExport.outputURL = savePathUrl
    assetExport.shouldOptimizeForNetworkUse = true

    assetExport.exportAsynchronously { () -> Void in
        switch assetExport.status {
        case AVAssetExportSessionStatus.completed:
            print("success")
            completion(nil, savePathUrl)
        case AVAssetExportSessionStatus.failed:
            print("failed \(assetExport.error?.localizedDescription ?? "error nil")")
            completion(assetExport.error, nil)
        case AVAssetExportSessionStatus.cancelled:
            print("cancelled \(assetExport.error?.localizedDescription ?? "error nil")")
            completion(assetExport.error, nil)
        default:
            print("complete")
            completion(assetExport.error, nil)
        }
    }

}

我在哪里调用函数:

@objc func touchCameraButton(){
soundFileURL!, completion: {(err, url) in print("fuck")})

    if isVideoRecordingOn{

        if isFirstTouch{
            startCapture()
            recordAudio()
            isFirstTouch = false
        }else{
            startCapture()
            recordAudio()
            self.mergeVideoAndAudio(videoUrl: videoFileURL, audioUrl: soundFileURL!, shouldFlipHorizontally: true, completion: {(err, url) in DispatchQueue.main.async {
                self.videoWithAudioURL = url
                if (err != nil){
                    print(err?.localizedDescription ?? "Error in merging video and audio")
                }
                self.isFirstTouch = true
                }
            })
    }
    }
}

1 个答案:

答案 0 :(得分:0)

会话在后台线程上执行,因此您必须在主线程的完成句柄中执行所有操作。

您只能执行以下操作

    assetExport.exportAsynchronously { () -> Void in
       DispatchQueue.main.async {
        switch assetExport.status {
        case AVAssetExportSessionStatus.completed:
            print("success")
            completion(nil, savePathUrl)
        case AVAssetExportSessionStatus.failed:
            print("failed \(assetExport.error?.localizedDescription ?? "error nil")")
            completion(assetExport.error, nil)
        case AVAssetExportSessionStatus.cancelled:
            print("cancelled \(assetExport.error?.localizedDescription ?? "error nil")")
            completion(assetExport.error, nil)
        default:
            print("complete")
            completion(assetExport.error, nil)
        }
    }    
}