在 exportAsynchronouslyWithCompletionHandler 中创建 AVPlayer 时,看到视频前的长时间延迟 [英] Long delay before seeing video when AVPlayer created in exportAsynchronouslyWithCompletionHandler

查看:14
本文介绍了在 exportAsynchronouslyWithCompletionHandler 中创建 AVPlayer 时,看到视频前的长时间延迟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

When playing a video exported from a AVAssetExportSession, you hear audio long before seeing video. Audio plays right away, but video only appears after the recording loops several times (i.e., starts and finishes). In other words, you hear audio from the video multiple times before seeing any images.

我们在 iOS 8 上使用 AutoLayout.

We are using AutoLayout on iOS 8.

使用以下测试,我们将问题隔离到 exportAsynchronouslyWithCompletionHandler.在这两个代码块中,我们播放一个现有的视频——与导出无关——因此导出过程已作为一个变量被消除.

Using the following test, we isolated the problem to exportAsynchronouslyWithCompletionHandler. In both code blocks, we play an existing video -- not one related to the export -- so the export process has been eliminated as a variable.

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

Code 1 plays both video & audio at the start whereas Code 2 only plays audio at the start and shows video after a delay of 10-60 seconds (after the video loops several times).

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

The only difference between the two code blocks is one uses exportAsynchronouslyWithCompletionHandler to play the video while the other one does not.

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

Help? Is it possible the audio gets exported first and is ready to play before the video? Something to do with the export happening on a different thread?

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

推荐答案

我会建议问题出在这里:

I'm going to suggest that the problem is here:

    // 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()

您会看到,当您从视频 URL 创建 AVPlayer 时,它会出现尚未准备好播放.它通常可以很快开始播放音频,但准备视频需要更长的时间.这可以解释延迟看到任何东西.

You see, when you create an AVPlayer from a video URL, it comes into the world not yet ready to play. It can usually start playing audio quite quickly, but video takes longer to prepare. This could explain the delay in seeing anything.

好吧,与其等待视频准备好,不如直接说play().这是我的建议.我建议你做的是我 在我的书中解释(这是指向实际代码的链接):创建播放器和图层,然后设置 KVO,以便在播放器准备好显示时通知您,然后 em> 添加图层并开始播放.

Well, instead of waiting for the video to be ready, you are just going ahead and saying play() immediately. Here's my suggestion. What I suggest you do is what I explain in my book (that's a link to the actual code): create the player and the layer, but then set up KVO so that you are notified when the player is ready to display, and then add the layer and start playing.

另外,我还有一个建议.在我看来,您正在运行该代码,设置您的界面(使用层)并说 play()在后台线程上,这似乎是一种危险.这肯定会导致各种延误.您似乎假设 exportAsynchronouslyWithCompletionHandler: 的完成处理程序正在主线程上被调用 - 您正在继续并调用下一个方法,因此继续设置您的界面.这是一个非常冒险的假设.根据我的经验,您永远不应该假设 any AVFoundation 完成处理程序位于主线程上.您应该在完成处理程序中使用 dispatch_async 进入主线程,并仅从那里继续.如果您查看我链接到的代码,您会发现我这样做很小心.

Also, I have one more suggestion. It seems to me that there is a danger that you are running that code, setting up your interface (with the layer) and saying play(), on a background thread. That is certain to cause delays of various kinds. You seem to be assuming that the completion handler from exportAsynchronouslyWithCompletionHandler: is being called on the main thread - and you are going straight ahead and calling the next method and so proceeding to set up your interface. That's a very risky assumption. In my experience you should never assume that any AVFoundation completion handler is on the main thread. You should be stepping out to the main thread with dispatch_async in your completion handler and proceeding only from there. If you look at the code I linked you to, you'll see I'm careful to do that.

这篇关于在 exportAsynchronouslyWithCompletionHandler 中创建 AVPlayer 时,看到视频前的长时间延迟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆