使用AVFoundation AVPlayer播放video?

在AVFoundation中有一个相对简单的循环播放video的方法吗?

我创build了我的AVPlayer和AVPlayerLayer,如下所示:

avPlayer = [[AVPlayer playerWithURL:videoUrl] retain]; avPlayerLayer = [[AVPlayerLayer playerLayerWithPlayer:avPlayer] retain]; avPlayerLayer.frame = contentView.layer.bounds; [contentView.layer addSublayer: avPlayerLayer]; 

然后我播放我的video:

 [avPlayer play]; 

video播放正常,但最后停止。 使用MPMoviePlayerController,您只需将其repeatMode属性设置为正确的值即可。 在AVPlayer上似乎没有类似的属性。 电影结束的时候,似乎还没有一个callback可以告诉我,所以我可以寻求开始,并再次播放。

我没有使用MPMoviePlayerController,因为它有一些严重的限制。 我希望能够一次播放多个videostream。

当玩家结束时你可以得到一个通知。 检查AVPlayerItemDidPlayToEndTimeNotification

设置播放器时:

ObjC

  avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:[avPlayer currentItem]]; 

这将防止玩家在最后暂停。

在通知中:

 - (void)playerItemDidReachEnd:(NSNotification *)notification { AVPlayerItem *p = [notification object]; [p seekToTime:kCMTimeZero]; } 

这将倒回电影。

当释放播放器时,不要忘记取消注册通知。

迅速

 NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidReachEnd(notification:)), name: Notification.Name.AVPlayerItemDidPlayToEndTime, object: avPlayer?.currentItem) @objc func playerItemDidReachEnd(notification: Notification) { if let playerItem: AVPlayerItem = notification.object as? AVPlayerItem { playerItem.seek(to: kCMTimeZero, completionHandler: nil) } } 

如果有帮助,在iOS / tvOS 10中,可以使用一个新的AVPlayerLooper()来创buildvideo无缝循环(Swift):

 player = AVQueuePlayer() playerLayer = AVPlayerLayer(player: player) playerItem = AVPLayerItem(url: videoURL) playerLooper = AVPlayerLooper(player: player, templateItem: playerItem) player.play() 

这是在WWDC 2016在AVFoundation回放进展中呈现的: https : //developer.apple.com/videos/play/wwdc2016/503/

即使使用这些代码,在我向苹果提交错误报告之前,我还是有一个呃逆,得到了这样的回应:

电影文件具有比audio/video轨道长的电影持续时间是问题。 FigPlayer_File禁用无间隙转换,因为音轨编辑比电影的持续时间短(15.682比15.787)。

您需要修复电影文件以使电影持续时间和音轨持续时间相同,或者您可以使用AVPlayerLooper的时间范围参数(设置时间范围从0到音轨的持续时间)

事实certificate,Premiere已经导出文件的audio轨道的长度比video略有不同。 在我的情况下完全删除audio是好的,并解决了这个问题。

Swift中

当玩家结束时,你可以得到一个通知…检查AVPlayerItemDidPlayToEndTimeNotification

设置玩家时:

 avPlayer.actionAtItemEnd = AVPlayerActionAtItemEnd.None NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerItemDidReachEnd:", name: AVPlayerItemDidPlayToEndTimeNotification, object: avPlayer.currentItem) 

这将防止玩家在最后暂停。

在通知中:

 func playerItemDidReachEnd(notification: NSNotification) { if let playerItem: AVPlayerItem = notification.object as? AVPlayerItem { playerItem.seekToTime(kCMTimeZero) } } 

Swift3

 NotificationCenter.default.addObserver(self, selector: #selector(PlaylistViewController.playerItemDidReachEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: avPlayer?.currentItem) 

这将倒回电影。

当释放播放器时,不要忘记取消注册通知。

这是我最终做的,以防止暂停呃逆问题:

 __weak typeof(self) weakSelf = self; // prevent memory cycle NSNotificationCenter *noteCenter = [NSNotificationCenter defaultCenter]; [noteCenter addObserverForName:AVPlayerItemDidPlayToEndTimeNotification object:nil // any object can send queue:nil // the queue of the sending usingBlock:^(NSNotification *note) { // holding a pointer to avPlayer to reuse it [weakSelf.avPlayer seekToTime:kCMTimeZero]; [weakSelf.avPlayer play]; }]; 

并在不再需要的时候将self从观察中移除。

注意:我没有使用avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;

我build议使用AVQueuePlayer无缝循环您的video。 添加通知观察者

 AVPlayerItemDidPlayToEndTimeNotification 

并在其select器中循环播放video

 AVPlayerItem *video = [[AVPlayerItem alloc] initWithURL:videoURL]; [self.player insertItem:video afterItem:nil]; [self.player play]; 

为了避免video回卷时出现间隙,在作品中使用同一资源的多个副本对我来说效果不错。 我在这里find它: http://www.developers-life.com/avplayer-looping-video-without-hiccupdelays.html (现在链接已经死了)。

 AVURLAsset *tAsset = [AVURLAsset assetWithURL:tURL]; CMTimeRange tEditRange = CMTimeRangeMake(CMTimeMake(0, 1), CMTimeMake(tAsset.duration.value, tAsset.duration.timescale)); AVMutableComposition *tComposition = [[[AVMutableComposition alloc] init] autorelease]; for (int i = 0; i < 100; i++) { // Insert some copies. [tComposition insertTimeRange:tEditRange ofAsset:tAsset atTime:tComposition.duration error:nil]; } AVPlayerItem *tAVPlayerItem = [[AVPlayerItem alloc] initWithAsset:tComposition]; AVPlayer *tAVPlayer = [[AVPlayer alloc] initWithPlayerItem:tAVPlayerItem]; 

这对我没有打嗝问题的工作, 点是在调用seekToTime方法之前暂停播放器:

  1. 初始化AVPlayer

     let url = NSBundle.mainBundle().URLForResource("loop", withExtension: "mp4") let playerItem = AVPlayerItem(URL: url!) self.backgroundPlayer = AVPlayer(playerItem: playerItem) let playerLayer = AVPlayerLayer(player: self.backgroundPlayer) playerLayer.frame = CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height) self.layer.addSublayer(playerLayer) self.backgroundPlayer!.actionAtItemEnd = .None self.backgroundPlayer!.play() 
  2. 注册通知

     NSNotificationCenter.defaultCenter().addObserver(self, selector: "videoLoop", name: AVPlayerItemDidPlayToEndTimeNotification, object: self.backgroundPlayer!.currentItem) 
  3. videoLoopfunction

     func videoLoop() { self.backgroundPlayer?.pause() self.backgroundPlayer?.currentItem?.seekToTime(kCMTimeZero) self.backgroundPlayer?.play() } 

将video加载到AVPlayer(当然,通过它的AVPlayerItem):

  [self addDidPlayToEndTimeNotificationForPlayerItem:item]; 

addDidPlayToEndTimeNotificationForPlayerItem方法:

 - (void)addDidPlayToEndTimeNotificationForPlayerItem:(AVPlayerItem *)item { if (_notificationToken) _notificationToken = nil; /* Setting actionAtItemEnd to None prevents the movie from getting paused at item end. A very simplistic, and not gapless, looped playback. */ _player.actionAtItemEnd = AVPlayerActionAtItemEndNone; _notificationToken = [[NSNotificationCenter defaultCenter] addObserverForName:AVPlayerItemDidPlayToEndTimeNotification object:item queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { // Simple item playback rewind. [[_player currentItem] seekToTime:kCMTimeZero]; }]; } 

在你的viewWillDisappear方法中:

 if (_notificationToken) { [[NSNotificationCenter defaultCenter] removeObserver:_notificationToken name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem]; _notificationToken = nil; } 

在您的视图控制器的实现文件中的接口声明:

 id _notificationToken; 

在尝试之前,需要看到这个运行正常吗? 下载并运行这个示例应用程序:

https://developer.apple.com/library/prerelease/ios/samplecode/AVBasicVideoOutput/Listings/AVBasicVideoOutput_APLViewController_m.html#//apple_ref/doc/uid/DTS40013109-AVBasicVideoOutput_APLViewController_m-DontLinkElementID_8

在我使用这个代码的应用程序中,在video结束和开始之间没有任何停顿。 实际上,根据video的不同,我不可能再次告诉video,保存时间码显示。

你可以添加一个AVPlayerItemDidPlayToEndTimeNotification观察者,并从select器开始播放video,代码如下

  //add observer [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:_aniPlayer.currentItem]; -(void)playbackFinished:(NSNotification *)notification{ [_aniPlayer seekToTime:CMTimeMake(0, 1)];//replay from start [_aniPlayer play]; } 

我在AVQueuePlayer的objective-c中的解决scheme – 似乎你必须复制AVPlayerItem和第一个元素完成播放时立即添加另一个副本。 “有点”是有道理的,为我工作没有任何的打嗝

 NSURL *videoLoopUrl; // as [[NSBundle mainBundle] URLForResource:@"assets/yourVideo" withExtension:@"mp4"]]; AVQueuePlayer *_loopVideoPlayer; +(void) nextVideoInstance:(NSNotification*)notif { AVPlayerItem *currItem = [AVPlayerItem playerItemWithURL: videoLoopUrl]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(nextVideoInstance:) name:AVPlayerItemDidPlayToEndTimeNotification object: currItem]; [_loopVideoPlayer insertItem:currItem afterItem:nil]; [_loopVideoPlayer advanceToNextItem]; } +(void) initVideoPlayer { videoCopy1 = [AVPlayerItem playerItemWithURL: videoLoopUrl]; videoCopy2 = [AVPlayerItem playerItemWithURL: videoLoopUrl]; NSArray <AVPlayerItem *> *dummyArray = [NSArray arrayWithObjects: videoCopy1, videoCopy2, nil]; _loopVideoPlayer = [AVQueuePlayer queuePlayerWithItems: dummyArray]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(nextVideoInstance:) name: AVPlayerItemDidPlayToEndTimeNotification object: videoCopy1]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(nextVideoInstance:) name: AVPlayerItemDidPlayToEndTimeNotification object: videoCopy2]; } 

https://gist.github.com/neonm3/06c3b5c911fdd3ca7c7800dccf7202ad

使用AVPlayerViewController下面的代码,它为我工作

  let type : String! = "mp4" let targetURL : String? = NSBundle.mainBundle().pathForResource("Official Apple MacBook Air Video YouTube", ofType: "mp4") let videoURL = NSURL(fileURLWithPath:targetURL!) let player = AVPlayer(URL: videoURL) let playerController = AVPlayerViewController() playerController.player = player self.addChildViewController(playerController) self.playView.addSubview(playerController.view) playerController.view.frame = playView.bounds player.play() 

所有的控制要显示,希望有帮助

 /* "numberOfLoops" is the number of times that the sound will return to the beginning upon reaching the end. A value of zero means to play the sound just once. A value of one will result in playing the sound twice, and so on.. Any negative number will loop indefinitely until stopped. */ @property NSInteger numberOfLoops; 

该属性已经在AVAudioPlayer定义。 希望这可以帮助你。 我正在使用Xcode 6.3。