Zapętlanie wideo za pomocą AVFoundation AVPlayer?
Czy istnieje stosunkowo łatwy sposób na zapętlenie wideo w AVFoundation?
Mój AVPlayer i AVPlayerLayer stworzyłem tak:
avPlayer = [[AVPlayer playerWithURL:videoUrl] retain];
avPlayerLayer = [[AVPlayerLayer playerLayerWithPlayer:avPlayer] retain];
avPlayerLayer.frame = contentView.layer.bounds;
[contentView.layer addSublayer: avPlayerLayer];
A potem puszczam filmik z:
[avPlayer play];
Wideo gra dobrze, ale zatrzymuje się na końcu. W MPMoviePlayerController wystarczy ustawić jego właściwość repeatMode
na odpowiednią wartość. Wygląda na to, że w Avplayerze nie ma podobnej właściwości. Nie wydaje się też, aby było połączenie zwrotne, które powie mi, kiedy film się skończy więc mogę szukać początku i odtworzyć go ponownie.
Nie używam MPMoviePlayerController, ponieważ ma poważne ograniczenia. Chcę móc odtwarzać wiele strumieni wideo naraz.
15 answers
Możesz otrzymać powiadomienie, gdy gracz zakończy grę. Sprawdź AVPlayerItemDidPlayToEndTimeNotification
Podczas konfigurowania odtwarzacza:
ObjC
avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[avPlayer currentItem]];
To uniemożliwi graczowi pauzę na końcu.
W zgłoszeniu:
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
[p seekToTime:kCMTimeZero];
}
To przewija film.
Nie zapomnij wyrejestrować powiadomienia podczas zwalniania gracza.
Swift
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)
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-02 08:04:55
Jeśli to pomoże, w iOS / tvOS 10 jest nowa funkcja AVPlayerLooper (), której możesz użyć do tworzenia płynnej pętli wideo (Swift):
player = AVQueuePlayer()
playerLayer = AVPlayerLayer(player: player)
playerItem = AVPLayerItem(url: videoURL)
playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)
player.play()
To zostało zaprezentowane na WWDC 2016 w "Advances in AVFoundation Playback": https://developer.apple.com/videos/play/wwdc2016/503/
Nawet używając tego kodu, miałem czkawkę, dopóki nie złożyłem zgłoszenia błędu w Apple i dostałem taką odpowiedź:
Plik filmowy o czasie trwania filmu dłuższym niż ścieżki audio / wideo jest problem. FigPlayer_File wyłącza przejście bez GAPA, ponieważ edycja ścieżki audio jest krótsza niż czas trwania filmu (15.682 vs 15.787).
Musisz albo naprawić pliki filmowe, aby mieć czas trwania filmu i czas trwania ścieżki mieć taką samą długość lub można użyć zakresu czasowego parametr AVPlayerLooper (ustawia zakres czasu od 0 do czasu trwania ścieżka audio)
Okazuje się, że Premiere eksportował pliki ze ścieżką audio o nieco innej długości niż wideo. W moim przypadku całkowite usunięcie dźwięku było w porządku i to naprawiło problem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-30 22:20:47
W :
Możesz otrzymać powiadomienie, gdy gracz zakończy grę... sprawdź AVPlayerItemDidPlayToEndTimeNotification
Podczas konfigurowania odtwarzacza:
avPlayer.actionAtItemEnd = AVPlayerActionAtItemEnd.None
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "playerItemDidReachEnd:",
name: AVPlayerItemDidPlayToEndTimeNotification,
object: avPlayer.currentItem)
To uniemożliwi graczowi pauzę na końcu.
W zgłoszeniu:
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)
To przewija film.
Nie zapomnij wyrejestrować powiadomienia podczas zwalniania gracza.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-29 17:23:41
Oto, co zrobiłem, aby zapobiec problemowi pauzy-czkawki:
Swift:
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime,
object: nil,
queue: nil) { [weak self] note in
self?.avPlayer.seek(to: kCMTimeZero)
self?.avPlayer.play()
}
Cel 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];
}];
Uwaga: {[7] } nie używałem avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone
, ponieważ nie jest to potrzebne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-01 05:29:56
Zalecam używanie AVQueuePlayer do płynnego zapętlania filmów. Add the notification observer
AVPlayerItemDidPlayToEndTimeNotification
I w jego selektorze zapętl swój film
AVPlayerItem *video = [[AVPlayerItem alloc] initWithURL:videoURL];
[self.player insertItem:video afterItem:nil];
[self.player play];
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-03 17:35:17
Aby uniknąć luki podczas przewijania wideo, użycie wielu kopii tego samego zasobu w kompozycji działało dobrze dla mnie. Znalazłem go tutaj: www.developers-life.com/avplayer-looping-video-without-hiccupdelays.html (link nie działa).
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];
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-09 18:54:18
Dla Swift 3 & 4
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.avPlayer?.currentItem, queue: .main) { _ in
self.avPlayer?.seek(to: kCMTimeZero)
self.avPlayer?.play()
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-21 12:43:55
To działało dla mnie bez problemów, punkt polega na wstrzymaniu odtwarzacza przed wywołaniem metody seekToTime:
-
Init 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()
-
Zgłoszenie rejestracyjne
NSNotificationCenter.defaultCenter().addObserver(self, selector: "videoLoop", name: AVPlayerItemDidPlayToEndTimeNotification, object: self.backgroundPlayer!.currentItem)
-
Funkcja VideoLoop
func videoLoop() { self.backgroundPlayer?.pause() self.backgroundPlayer?.currentItem?.seekToTime(kCMTimeZero) self.backgroundPlayer?.play() }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-11 00:43:32
Po wczytaniu filmu do Avplayera (oczywiście przez jego AVPlayerItem):
[self addDidPlayToEndTimeNotificationForPlayerItem:item];
Metoda 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];
}];
}
In your viewwilldisappear method:
if (_notificationToken) {
[[NSNotificationCenter defaultCenter] removeObserver:_notificationToken name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
_notificationToken = nil;
}
W deklaracji interfejsu kontrolera widoku w pliku implementacji:
id _notificationToken;
Chcesz zobaczyć, jak to działa, zanim spróbujesz? Pobierz i uruchom tę próbkę app:
W mojej aplikacji, która używa tego samego kodu, nie ma żadnej przerwy między końcem filmu a początkiem. W rzeczywistości, w zależności od filmu, nie ma sposobu, aby powiedzieć, że film jest na początku ponownie, zapisz kod czasowy wyświetlacz.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-26 01:16:25
Możesz dodać Avplayeritemdidplaytoendtimenotifying observer i odtworzyć wideo od początku w selektorze, Kod jak poniżej
//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];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-29 03:19:24
Moje rozwiązanie w objective-c wth AVQueuePlayer-wydaje się, że trzeba powielić AVPlayerItem i po zakończeniu odtwarzania pierwszego elementu natychmiast dodać kolejną kopię. "Kind of" Ma Sens i działa dla mnie bez czkawki
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-22 13:06:42
Poniżej działa dla mnie w WKWebView w swift 4.1 Główna część WKWebView w WKwebviewConfiguration
wkwebView.navigationDelegate = self
wkwebView.allowsBackForwardNavigationGestures = true
self.wkwebView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height))
let config = WKWebViewConfiguration()
config.allowsInlineMediaPlayback = true
wkwebView = WKWebView(frame: wkwebView.frame, configuration: config)
self.view.addSubview(wkwebView)
self.wkwebView.load(NSURLRequest(url: URL(string: self.getUrl())!) as URLRequest)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-19 13:46:40
To co zrobiłem, to zrobić pętlę odtwarzania, jak mój kod poniżej:
[player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0)
queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
float current = CMTimeGetSeconds(time);
float total = CMTimeGetSeconds([playerItem duration]);
if (current >= total) {
[[self.player currentItem] seekToTime:kCMTimeZero];
[self.player play];
}
}];
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-14 13:14:45
Użyj AVPlayerViewController poniżej kodu, działa dla mnie
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()
Wszystkie kontrolki do pokazania, mam nadzieję, że będą pomocne
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-03 10:00:11
/* "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;
Ta właściwość jest już zdefiniowana wewnątrz AVAudioPlayer
. Mam nadzieję, że to ci pomoże.
Używam Xcode 6.3.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-23 10:31:09