【问题标题】:Merging Videos but AVAssetExportSession never completes合并视频但 AVAssetExportSession 从未完成
【发布时间】:2015-09-27 14:39:40
【问题描述】:

尝试将一些视频合并在一起并将它们导出为单个文件,从查看教程/示例来看一切似乎都是正确的,但是我的 AVAssetExportSession 似乎永远不会完整,而且我的视频文件永远不会导出,任何帮助非常感谢我遗漏的明显错误。

下面是我合并视频的功能

注意循环中的“视频”是一个成员变量var videos = [AVAsset](),它在调用合并之前被填充(我检查过)。

private func merge()
{
    // Create AVMutableComposition to contain all AVMutableComposition tracks
    var mix_composition = AVMutableComposition()
    var total_time_seconds  = 0.0
    var tracks = [AVCompositionTrack]()

    // Loop over videos and create tracks, keep incrementing total duration
    for video in videos
    {
        // Create the composition track for this video
        let track = mix_composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))

        // Add video duration to total time
        total_time_seconds = total_time_seconds + video.duration.seconds

        // Add track to array of tracks
        tracks.append(track)

        // Add time range to track
        do
        {
            try track.insertTimeRange(CMTimeRangeMake(kCMTimeZero, video.duration), ofTrack: video.tracksWithMediaType(AVMediaTypeVideo)[0], atTime: video.duration)
        }
        catch _
        {
        }
    }

    // Set total time
    let preferred_time_scale: Int32 = 600;
    let total_time = CMTimeMakeWithSeconds(total_time_seconds, preferred_time_scale)

    // Create main instrcution for video composition
    let main_instruction = AVMutableVideoCompositionInstruction()
    main_instruction.timeRange = CMTimeRangeMake(kCMTimeZero, total_time)

    // Create array to hold instructions
    var layer_instructions = [AVVideoCompositionLayerInstruction]()

    // Ensure we have the same number of tracks as videos
    if videos.count == tracks.count
    {
        // Loop number of videos and tracks
        for var index = 0; index < videos.count; ++index
        {
            // Create compositioninstruction for each track
            let instruction = videoCompositionInstructionForTrack(tracks[index], asset: videos[index])

            if(index == 0)
            {
                instruction.setOpacity(0.0, atTime: videos[index].duration)
            }

            // Add instruction to instructions array
            layer_instructions.append(instruction)
        }
    }

    // Set tack instructions to main instruction
    main_instruction.layerInstructions = layer_instructions
    let main_composition = AVMutableVideoComposition()
    main_composition.instructions = [main_instruction]
    main_composition.frameDuration = CMTimeMake(1, 30)
    main_composition.renderSize = CGSize(width: UIScreen.mainScreen().bounds.width, height: UIScreen.mainScreen().bounds.height)

    // Get path for Final video in the current project directory
    let documents_url = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
    let final_url = documents_url.URLByAppendingPathComponent("TEST.mp4")

    // Create AV Export Session
    let exporter = AVAssetExportSession(asset: mix_composition, presetName: AVAssetExportPresetHighestQuality)
    exporter!.outputURL = final_url
    exporter!.outputFileType = AVFileTypeMPEG4
    exporter!.shouldOptimizeForNetworkUse = true
    exporter!.videoComposition = main_composition

    // Perform the Export
    exporter!.exportAsynchronouslyWithCompletionHandler() {
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            self.exportDidFinish(exporter!)
        })
    }
}

下面显示了调用exportAsynchronouslyWithCompletionHandler 时调用的exportDidFinished 函数。我进入了这个函数,但什么也没发生,因为会话状态从未完成。

func exportDidFinish(session: AVAssetExportSession)
{
    if session.status == AVAssetExportSessionStatus.Completed
    {
        let outputURL = session.outputURL
        let library = ALAssetsLibrary()
        if library.videoAtPathIsCompatibleWithSavedPhotosAlbum(outputURL)
        {
            library.writeVideoAtPathToSavedPhotosAlbum(outputURL,
                completionBlock: { (assetURL:NSURL!, error:NSError!) -> Void in
                    if error != nil
                    {
                        let alert = UIAlertView(title: "Error", message: "Video Not Saved", delegate: nil, cancelButtonTitle: "OK")
                        alert.show()

                    }
                    else
                    {
                        let alert = UIAlertView(title: "Success", message: "Video Saved", delegate: nil, cancelButtonTitle: "OK")
                        alert.show()
                    }
            })
        }
    }
}

打印的会话状态显示它是失败的 4,所以我打印了 session.error 并得到了这个,但我不确定它的含义,任何帮助都会很棒

Optional(Error Domain=AVFoundationErrorDomain Code=-11841 "Operation Stopped" UserInfo={NSLocalizedDescription=Operation Stopped, NSLocalizedFailureReason=The video could not be composed.}) 

【问题讨论】:

    标签: ios video swift2 avassetexportsession


    【解决方案1】:

    如果调用了exportDidFinish 但没有任何反应,则您的会话状态不是AVAssetExportSessionStatus.Completed。它可能是AVAssetExportSessionStatus.Failed,或其他一些值。检查这些值,如果失败,请检查 session.error 属性以获取更多信息。

    编辑:如果您希望一个视频一个接一个地播放,请只创建一个AVMutableCompositionTrack。相关变化见下文:

        ...
        var mix_composition = AVMutableComposition()
    
        // Create the composition track for the videos
        let track = mix_composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
    
        //keep track of total time
        var totalTime = kCMTimeZero
    
        for video in videos
        {
            // Add time range to track
            do
            {
                let videoTrack = video.tracksWithMediaType(AVMediaTypeVideo)[0]
                let videoDuration = videoTrack.duration
                let timeRange = CMTimeRangeMake(kCMTimeZero,videoDuration)
    
                try track.insertTimeRange(timeRange, ofTrack: videoTrack, atTime: totalTime)
    
                totalTime = CMTimeAdd(totalTime,videoDuration)
            }
            catch _
            {
            }
        }
    
        // Create main instruction for video composition
        let main_instruction = AVMutableVideoCompositionInstruction()
        main_instruction.timeRange = CMTimeRangeMake(kCMTimeZero, totalTime)
    
        // Create array to hold instructions
        var layer_instructions = [AVVideoCompositionLayerInstruction]()
    
        // Create layer instruction
        let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: track)
    
        // Add it to the array
        layer_instructions.append(layerInstruction)
    
        ...
    

    您还需要将 renderSize 调整为适当的值。您的视频大小可能与您的屏幕大小不同。

    【讨论】:

    • 我如何实际检查我打印状态的值,但它只是说"AVAssetExportSessionStatus"
    • 打印(会话!.status.rawValue)。然后打印(session!.error)
    • 好的,所以状态 4 失败了,我收到了这个错误 'Optional(Error Domain=AVFoundationErrorDomain Code=-11841 "Operation Stopped" UserInfo={NSLocalizedDescription=Operation Stopped, NSLocalizedFailureReason=The video无法组成。}) '
    • 今晚我试试,让你知道这是怎么回事,谢谢你的回答
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多