使用AVFoundation AVPlayer循环播放视频?

orj*_*orj 139 objective-c avfoundation ios avplayer swift

在AVFoundation中有一种相对简单的循环视频方式吗?

我已经创建了我的AVPlayer和AVPlayerLayer:

avPlayer = [[AVPlayer playerWithURL:videoUrl] retain];
avPlayerLayer = [[AVPlayerLayer playerLayerWithPlayer:avPlayer] retain];

avPlayerLayer.frame = contentView.layer.bounds;
[contentView.layer addSublayer: avPlayerLayer];
Run Code Online (Sandbox Code Playgroud)

然后我播放我的视频:

[avPlayer play];
Run Code Online (Sandbox Code Playgroud)

视频播放正常但最后停止播放.使用MPMoviePlayerController,您只需将其repeatMode属性设置为正确的值即可.AVPlayer似乎没有类似的属性.似乎没有一个回调可以告诉我什么时候电影结束所以我可以寻找开头并再次播放它.

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

Bas*_*ian 271

玩家结束时可以获得通知.校验AVPlayerItemDidPlayToEndTimeNotification

设置播放器时:

ObjC

  avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone; 

  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(playerItemDidReachEnd:)
                                               name:AVPlayerItemDidPlayToEndTimeNotification
                                             object:[avPlayer currentItem]];
Run Code Online (Sandbox Code Playgroud)

这样可以防止玩家在结束时暂停.

在通知中:

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

这将回放电影.

不要忘记在释放播放器时取消注册通知.

迅速

avPlayer?.actionAtItemEnd = .none

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

@objc func playerItemDidReachEnd(notification: Notification) {
    if let playerItem = notification.object as? AVPlayerItem {
        playerItem.seek(to: kCMTimeZero)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这不应该是必要的...如果你做`avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;`它不会停止,所以不需要再将它设置为播放 (23认同)
  • 此解决方案有效,但并非完全无缝.我有一个非常小的停顿.难道我做错了什么? (12认同)
  • ...如果你想在[p seekToTime:kCMTimeZero](各种各样的"倒带")之后立即播放,只需再次进行[p play]. (6认同)
  • @Praxiteles你需要在视图被破坏时取消注册,或者当你删除视频播放器或你做的任何事情时,你可以使用`[[NSNotificationCenter defaultCenter] removeObserver:self];`例如,当`self`正在收听时通知. (3认同)
  • 在我的情况下它停止了. (2认同)

Nab*_*bha 52

如果它有帮助,在iOS/tvOS 10中,有一个新的AVPlayerLooper()可用于创建无缝的视频循环(Swift):

player = AVQueuePlayer()
playerLayer = AVPlayerLayer(player: player)
playerItem = AVPlayerItem(url: videoURL)
playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)
player.play()    
Run Code Online (Sandbox Code Playgroud)

这是在WWDC 2016的"AVFoundation Playback的进展"中提出的:https: //developer.apple.com/videos/play/wwdc2016/503/

即使使用这段代码,在我向Apple提交错误报告并获得此回复之前,我还是有一个打嗝:

电影持续时间长于音频/视频轨道的电影文件是问题.FigPlayer_File正在禁用无间隙转换,因为音轨编辑比电影持续时间短(15.682 vs 15.787).

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

事实证明,Premiere一直在导出文件的音轨长度与视频略有不同.在我的情况下,完全删除音频是很好的,这解决了问题.

  • 没有其他东西对我有用。我正在使用 AVPlayerLooper 并且有这个错误,修复视频/音频长度之间的差异解决了这个问题。 (3认同)
  • 这也适用于ObjC. (2认同)

Kin*_*ard 26

Swift中:

当玩家结束时你可以获得通知...检查AVPlayerItemDidPlayToEndTimeNotification

设置播放器时:

avPlayer.actionAtItemEnd = AVPlayerActionAtItemEnd.None

NSNotificationCenter.defaultCenter().addObserver(self, 
                                                 selector: "playerItemDidReachEnd:", 
                                                 name: AVPlayerItemDidPlayToEndTimeNotification, 
                                                 object: avPlayer.currentItem)
Run Code Online (Sandbox Code Playgroud)

这样可以防止玩家在结束时暂停.

在通知中:

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

Swift3

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

这将回放电影.

不要忘记在释放播放器时取消注册通知.

  • 我用这种方法看到循环之间的小打嗝.我在Adobe Premier中打开了我的视频并验证了视频中没有重复的帧,所以短暂的打嗝肯定是在回放.有没有人找到一种方法在swift中无缝地制作视频循环? (4认同)

Isl*_* Q. 17

以下是我为防止暂停打嗝问题而采取的措施:

迅速:

NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime,
                                       object: nil,
                                       queue: nil) { [weak self] note in
                                        self?.avPlayer.seek(to: kCMTimeZero)
                                        self?.avPlayer.play()
}
Run Code Online (Sandbox Code Playgroud)

目标C:

__weak typeof(self) weakSelf = self; // prevent memory cycle
NSNotificationCenter *noteCenter = [NSNotificationCenter defaultCenter];
[noteCenter addObserverForName:AVPlayerItemDidPlayToEndTimeNotification
                        object:nil
                         queue:nil
                    usingBlock:^(NSNotification *note) {
                        [weakSelf.avPlayer seekToTime:kCMTimeZero];
                        [weakSelf.avPlayer play];
                    }];
Run Code Online (Sandbox Code Playgroud)

注意:我没有使用,avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone因为它不需要.

  • @KostiaDombrovsky你试过一个实际的设备或不同的视频? (2认同)

NSC*_*der 5

斯威夫特 5:

我对之前的答案做了一些细微的调整,比如在将 playerItem 添加到队列之前将其添加到 playerLayer。

let playerItem = AVPlayerItem(url: url)
let player = AVQueuePlayer(playerItem: playerItem)
let playerLayer = AVPlayerLayer(player: player)

playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)

playerLayer.frame = cell.eventImage.bounds
playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill

// Add the playerLayer to a UIView.layer

player.play()
Run Code Online (Sandbox Code Playgroud)

并让 playerLooper 成为你的 UIViewController 的一个属性,否则视频只能播放一次。