使用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方法之前暂停播放器:
-
初始化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()
-
注册通知
NSNotificationCenter.defaultCenter().addObserver(self, selector: "videoLoop", name: AVPlayerItemDidPlayToEndTimeNotification, object: self.backgroundPlayer!.currentItem)
-
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;
在尝试之前,需要看到这个运行正常吗? 下载并运行这个示例应用程序:
在我使用这个代码的应用程序中,在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。