1

我正在开发一个 iOS 应用程序,该应用程序涉及从 Web 服务器获取作为流的一部分的视频片段并在应用程序内连续播放它们。经过一番研究,我决定使用 AVQueuePlayer。每次从服务器获取 MP4 文件并将其存储在 NSData 对象中时,我都会创建一个 AVPlayerItem 并将其附加到队列中。另外,我会收听 AVPlayerItemDidPlayToEndTimeNotification 通知,我会在其中前进到下一个项目。我面临的问题是每次我从一个电影片段前进到另一个时都会出现令人讨厌的小延迟。我尝试在 iMovie 上组合片段,但无法判断一个片段何时结束而另一个片段何时开始。如何摆脱连续片段之间的小停顿/滞后?

这是我的代码:

import UIKit
import MediaPlayer
import AVFoundation

class WatchStream: UIViewController, StreamManagerDelegate {

var subscriber : Subscriber!

//Model object responsible for fetching mp4 fragments
var streamManager = StreamManager()

var queue : AVQueuePlayer!


override func viewDidLoad() {
    super.viewDidLoad()

    //Set up the manager
    streamManager.streamID = subscriber.streamid
    streamManager.delegate = self

    //Register for notification once movie player finished
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "AVPlayerFinishedPlaying:", name:AVPlayerItemDidPlayToEndTimeNotification, object: nil)

    queue = AVQueuePlayer()
    var playerLayer = AVPlayerLayer(player: queue)
    playerLayer.frame = self.view.bounds
    self.view.layer.insertSublayer(playerLayer, below: self.navigationController!.navigationBar.layer)

}

//Delegate method notifying that a new fragment is ready to be watched
func streamManagerLoadedStream(fragment: Int, manager: StreamManager) {
    var url = streamManager.fetchFragmentToPlay()
    if url == nil {return}

    var playerItem = AVPlayerItem(URL: url!)
    queue.insertItem(playerItem, afterItem: nil)
    queue.play()
}

//Method called once name:AVPlayerItemDidPlayToEndTimeNotification fires
func AVPlayerFinishedPlaying(notification : NSNotification) {
    //We need to switch to second one
    queue.advanceToNextItem()

    if queue.status == AVPlayerStatus.ReadyToPlay {
        queue.play()
    }
}

}

同样,我的问题是在推进 AVQueuePlayer 时。它导致了这种滞后,这是不可能的。电影片段很小(每个 1-2 秒)并且应该是连续的,因为作为流。我尝试使用 2 AVQueuePlayers 和 2 AVPlayerLayers 但它没有解决问题。

我还尝试使用 MPMoviePlayerController 并在每次播放完毕时更新其 contentURL。滞后并没有消失。

有什么线索吗?

4

1 回答 1

2

将 AVMutableComposition 与 AVPlayer 一起使用,而不是 AVQueuePlayer。我使用的是 Objective-C,所以我的示例不在 Swift 中,但 Swift 代码将非常相似。

基本逻辑是这样的:

  1. 创建一个 AVMutableComposition

    合成 = [AVMutableComposition 新];

  2. 向其添加单个可变轨道

    AVMutableCompositionTrack *track = [_composition addMutableTrackWithMediaType:AVMediaTypeVideo In a preferredTrackID:kCMPersistentTrackID_Invalid];

  3. 在循环中:为每个视频片段创建一个 AVAssetTrack

    AVURLAsset* 资产 = ...;

    AVAssetTrack *assetTrack = [[asset trackingWithMediaType:AVMediaTypeVideo] objectAtIndex:0];

    CMTimeRange timeRange =assetTrack.timeRange;

  4. 将片段添加到您想要播放的确切时间的曲目中

    [track insertTimeRange:timeRange ofTrack:assetTrack atTime:time error:&error];

    1. 演奏你的作曲

    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:composition]; myPlayer = [[AVPlayer alloc] initWithPlayerItem:playerItem];

    ...

于 2015-03-06T18:43:02.163 回答