在exportAsynchronouslyWithCompletionHandler中创建AVPlayer时看到视频之前的长时间延迟

问题描述 投票:3回答:3

播放从AVAssetExportSession导出的视频时,您会在看到视频之前听到很长时间的声音。音频立即播放,但视频仅在录制循环多次后(即开始和结束)出现。换句话说,在看到任何图像之前,您会多次听到视频中的音频。

我们在iOS 8上使用AutoLayout。

使用以下测试,我们将问题分离到exportAsynchronouslyWithCompletionHandler。在两个代码块中,我们播放现有视频 - 而不是与导出相关的视频 - 因此导出过程已作为变量消除。

代码1在开始时播放视频和音频,而代码2仅在开始时播放音频,并在延迟10-60秒后显示视频(在视频循环几次后)。

两个代码块之间的唯一区别是一个使用exportAsynchronouslyWithCompletionHandler播放视频而另一个不使用。

救命?是否有可能首先导出音频并准备好在视频播放之前播放?与在不同线程上发生的导出有关?

func initPlayer(videoURL: NSURL) {
    // Create player
    player = AVPlayer(URL: videoURL)
    let playerItem = player.currentItem
    let asset = playerItem.asset
    playerLayer = AVPlayerLayer(player: player)
    playerLayer.frame = videoView.frame
    view.layer.addSublayer(playerLayer)
    player.seekToTime(kCMTimeZero)
    player.actionAtItemEnd = .None
    player.play()

    // Get notified when video done for looping purposes
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerItemDidReachEnd:", name: AVPlayerItemDidPlayToEndTimeNotification, object: playerItem)

    // Log status
    println("Initialized video player: \(CMTimeGetSeconds(asset.duration)) seconds & \(asset.tracks.count) tracks for \(videoURL)")
}

func playExistingVideo() {
    let filename = "/ChopsticksVideo.mp4"
    let allPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
    let docsPath = allPaths[0] as! NSString
    let exportPath = docsPath.stringByAppendingFormat(filename)
    let exportURL = NSURL.fileURLWithPath(exportPath as String)!

    initPlayer(exportURL)
}

代码1:

    // Create exporter
    let exporter = AVAssetExportSession(asset: mainComposition, presetName: AVAssetExportPresetHighestQuality)
    exporter.videoComposition = videoComposition
    exporter.outputFileType = AVFileTypeMPEG4
    exporter.outputURL = exportURL
    exporter.shouldOptimizeForNetworkUse = true

    playExistingVideo()

代码2:

    // Create exporter
    let exporter = AVAssetExportSession(asset: mainComposition, presetName: AVAssetExportPresetHighestQuality)
    exporter.videoComposition = videoComposition
    exporter.outputFileType = AVFileTypeMPEG4
    exporter.outputURL = exportURL
    exporter.shouldOptimizeForNetworkUse = true

    // -- Export video
    exporter.exportAsynchronouslyWithCompletionHandler({
        self.playExistingVideo()
    })
ios video autolayout avplayer avassetexportsession
3个回答
4
投票

我要建议问题在这里:

    // Create player
    player = AVPlayer(URL: videoURL)
    let playerItem = player.currentItem
    let asset = playerItem.asset
    playerLayer = AVPlayerLayer(player: player)
    playerLayer.frame = videoView.frame
    view.layer.addSublayer(playerLayer)
    player.seekToTime(kCMTimeZero)
    player.actionAtItemEnd = .None
    player.play()

您可以看到,当您从视频网址创建AVPlayer时,它进入了尚未准备好发挥作用的世界。它通常可以很快开始播放音频,但视频需要更长的时间来准备。这可以解释看到任何事情的延迟。

好吧,而不是等待视频准备好,你只是继续说,立即说play()。这是我的建议。我建议你做的是我explain in my book(这是实际代码的链接):创建播放器和图层,然后设置KVO,以便在播放器准备好显示时通知您,然后添加图层和开始玩。

另外,我还有一个建议。在我看来,你正在运行该代码,在后台线程上设置你的界面(与图层)并说play()。这肯定会造成各种延误。你似乎假设在主线程上调用exportAsynchronouslyWithCompletionHandler:的完成处理程序 - 你将直接前进并调用下一个方法,然后继续设置你的接口。这是一个非常冒险的假设。根据我的经验,你永远不应该假设任何AVFoundation完成处理程序在主线程上。你应该在你的完成处理程序中使用dispatch_async踩到主线程,然后从那里开始。如果你查看我链接到的代码,你会发现我很谨慎。


2
投票

对于那些后来遇到这个问题的人来说,答案就在接受答案的评论中。密钥dispatch_async部分如下:

[exporter exportAsynchronouslyWithCompletionHandler:^(void){
    dispatch_async(dispatch_get_main_queue(), ^{
        switch (exporter.status) {
            case AVAssetExportSessionStatusCompleted:
                NSLog(@"Video Merge Successful");
                break;
            case AVAssetExportSessionStatusFailed:
                NSLog(@"Failed:%@", exporter.error.description);
                break;
            case AVAssetExportSessionStatusCancelled:
                NSLog(@"Canceled:%@", exporter.error);
                break;
            case AVAssetExportSessionStatusExporting:
                NSLog(@"Exporting!");
                break;
            case AVAssetExportSessionStatusWaiting:
                NSLog(@"Waiting");
                break;
            default:
                break;
        }
    });

}];

0
投票

您可以在导出期间播放视频合成。

playerItem = AVPlayerItem(asset: videoComposition)
player = AVPlayer(playerItem: playerItem)

Apple Docs

AWP球员:

convenience init(asset: AVAsset)

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