web-dev-qa-db-de.com

So verringern Sie die Startverzögerung für iOS AVPlayer

Beachten Sie für die folgende Frage: Alle Assets sind lokal auf dem Gerät - es wird kein Netzwerkstreaming ausgeführt. Die Videos enthalten Audiospuren.

Ich arbeite an einer iOS-Anwendung, die das Abspielen von Videodateien mit minimaler Verzögerung erfordert, um den fraglichen Videoclip zu starten. Leider wissen wir nicht, welches Video als Nächstes angezeigt wird, bevor wir es starten müssen. Im Einzelnen: Wenn ein Videoclip abgespielt wird, werden wir wissen, was der nächste Satz von (ungefähr) 10 Videoclips ist. Wir wissen jedoch nicht genau, welcher Videoclip genau ist, bis der nächste Clip "sofort" abgespielt wird.

Um die tatsächlichen Startverzögerungen zu untersuchen, habe ich auf dem Videoplayer addBoundaryTimeObserverForTimes aufgerufen, wobei eine Zeitspanne von einer Millisekunde zu sehen ist, wann das Video tatsächlich abgespielt wurde, und ich nehme die Differenz dieses Zeitstempels mit der ersten Stelle im Code, die angibt, welches Asset gestartet wird.

Nach allem, was ich bisher gesehen habe, habe ich herausgefunden, dass ich die Kombination aus AVAsset loading und dann ein AVPlayerItem erstellt habe, sobald es fertig ist, und dann auf AVPlayerStatusReadyToPlay wartet Ich rufe das Spiel auf, dauert meistens 1 bis 3 Sekunden, um den Clip zu starten.

Ich habe seitdem zu dem gewechselt, was in etwa gleichwertig ist: [AVPlayerItem playerItemWithURL:] aufrufen und darauf warten, dass AVPlayerItemStatusReadyToPlay abgespielt wird. In etwa die gleiche Leistung.

Ich beobachte gerade, dass der erste AVPlayer-Artikel langsamer geladen wird als der Rest. Eine Idee ist, den AVPlayer mit einem kurzen/leeren Asset vorab zu starten, bevor das erste Video abgespielt werden kann. [ Langsamer Start für AVAudioPlayer beim ersten Abspielen eines Sounds

Ich würde es lieben, die Video-Startzeiten so niedrig wie möglich zu halten, und habe einige Vorstellungen von Dingen, mit denen Sie experimentieren könnten, aber ich würde gerne eine Anleitung von jedem haben, der helfen könnte.

Update: Die Idee 7 unten führt in der Implementierung zu Schaltzeiten von etwa 500 ms. Dies ist eine Verbesserung, aber es wäre schön, dies noch schneller zu machen.

Idee 1: Verwenden Sie N AVPlayers (funktioniert nicht)

Wenn Sie ~ 10 AVPPlayer -Objekte verwenden und alle ~ 10 Clips starten und pausieren, und sobald wir wissen, welche wir wirklich brauchen, wechseln Sie zu AVPlayer und unterbrechen die Wiedergabe, und beginnen Sie von vorne für den nächsten Zyklus.

Ich glaube nicht, dass dies funktioniert, da ich gelesen habe, dass es in iOS ungefähr ein Limit von 4 aktiven AVPlayer's gibt. Es gab jemanden, der bei StackOverflow hier nachgefragt hat, und fand heraus, wie hoch die Begrenzung auf 4 AVPlayer ist: schnelles Umschalten zwischen Videos - using-avfoundation

Idee 2: Verwenden Sie AVQueuePlayer (funktioniert nicht)

Ich glaube nicht, dass das Verschieben von 10 AVPlayerItems in einen AVQueuePlayer sie alle für einen nahtlosen Start vorladen würde. AVQueuePlayer ist eine Warteschlange, und ich denke, es macht wirklich nur das nächste Video in der Warteschlange für die sofortige Wiedergabe bereit. Ich weiß nicht, welches von ~ 10 Videos wir abspielen möchten, bis es an der Zeit ist, dieses Video zu starten. ios-avplayer-video-vorladen

Idee 3: Laden, spielen und AVPlayerItems im Hintergrund behalten (noch nicht zu 100% sicher - aber nicht gut aussehen)

Ich schaue mir an, ob es von Vorteil ist, die erste Sekunde jedes Videoclips im Hintergrund zu laden und abzuspielen (Video- und Audioausgabe unterdrücken), und einen Verweis auf jedes AVPlayerItem zu behalten, und wenn wir wissen, welches Element es ist muss für echt gespielt werden, tauschen Sie das ein und tauschen Sie den Hintergrund-AVPlayer mit dem aktiven aus. Spülen und wiederholen.

Die Theorie wäre, dass kürzlich gespielte AVPlayer/AVPlayerItems noch einige vorbereitete Ressourcen enthalten könnten, die die nachfolgende Wiedergabe beschleunigen würden. Bisher habe ich keine Vorteile davon gesehen, aber ich habe möglicherweise nicht die AVPlayerLayer -Einstellung für den Hintergrund richtig vorgenommen. Ich bezweifle, dass dies die Dinge wirklich verbessern wird.

Idee 4: Verwenden Sie ein anderes Dateiformat - vielleicht eines, das schneller geladen werden kann? 

Ich verwende derzeit das .m4v-Format (Video-MPEG4) im H.264-Format. H.264 hat viele verschiedene Codec-Optionen, daher ist es möglich, dass einige Optionen schneller zu finden sind als andere. Ich habe festgestellt, dass die Verwendung von erweiterten Einstellungen, die die Dateigröße verringern, die Suchzeit erhöht, aber keine Optionen gefunden haben, die in die andere Richtung gehen.

Idee 5: Kombination aus verlustfreiem Videoformat + AVQueuePlayer

Wenn es ein Videoformat gibt, das schnell geladen werden kann, aber bei einer Dateigröße vielleicht verrückt ist, könnte es eine Idee sein, die ersten 10 Sekunden jedes Videoclips mit einer aufgeblähten Version vorzubereiten, die jedoch schneller geladen wird, jedoch zurück das mit einem Asset, das in H.264 codiert ist. Verwenden Sie einen AVQueuePlayer und fügen Sie die ersten 10 Sekunden im unkomprimierten Dateiformat hinzu. Anschließend können Sie einen in H.264 nachverfolgen, der bis zu 10 Sekunden Vorbereitungs-/Vorladezeit benötigt. Ich würde also das Beste aus beiden Welten bekommen: schnelle Startzeiten, aber auch ein kompakteres Format.Idee 6: Verwenden Sie einen nicht standardmäßigen AVPlayer/schreiben Sie einen eigenen/verwenden Sie jemandes anderen.

Unter Berücksichtigung meiner Bedürfnisse kann ich AVPlayer möglicherweise nicht verwenden, muss aber auf AVAssetReader zurückgreifen und die ersten Sekunden dekodieren (möglicherweise Raw-Datei auf Festplatte schreiben). Wenn es sich um die Wiedergabe handelt, verwenden Sie das Rohformat, um es abzuspielen schnell zurück. Scheint mir ein riesiges Projekt zu sein, und wenn ich naiv vorgeht, ist es unklar/unwahrscheinlich, dass es sogar noch besser geht. Jedes dekodierte und unkomprimierte Videobild ist 2,25 MB groß. Naiv gesagt - wenn wir mit ~ 30 fps für das Video gehen, würde ich mit ~ 60 MB/s Read-from-Disk-Anforderung enden. Natürlich müssten wir eine gewisse Bildkomprimierung durchführen (vielleicht native OpenGL/es-Kompressionsformate über PVRTC) ... aber das ist irgendwie verrückt. Vielleicht gibt es da draußen eine Bibliothek, die ich benutzen kann?

Idee 7: Kombinieren Sie alles zu einem einzigen Movie-Asset und seekToTime

Eine Idee, die möglicherweise einfacher als einige der oben genannten ist, besteht darin, alles in einem einzigen Film zu kombinieren und seekToTime zu verwenden. Die Sache ist, dass wir überall herumspringen würden. Im Wesentlichen wahlfreier Zugriff auf den Film. Ich denke, das kann tatsächlich klappen: avplayer-movie-playing-lag-in-ios5

Welcher Ansatz ist Ihrer Meinung nach am besten? Bisher habe ich bei der Reduzierung der Verzögerung noch nicht so viel gemacht.

Which approach do you think would be best? So far, I've not made that much progress in terms of reducing the lag.

105

Sie sollten zuerst Option 7 ausprobieren, nur um zu sehen, ob Sie das zum Laufen bringen können. Ich vermute, dass dies für Ihre Anforderungen nicht funktionieren wird, da die Suchzeit wahrscheinlich nicht schnell genug ist, um ein nahtloses Umschalten zwischen den Clips zu ermöglichen. Wenn Sie dies versuchen und es fehlschlägt, würde ich Ihnen raten, die Option 4/6 zu verwenden und meine speziell für diesen Zweck entwickelte iOS-Bibliothek zu betrachten. Führen Sie einfach eine schnelle Google-Suche in AVAnimator durch, um mehr zu erfahren. Meine Bibliothek ermöglicht das Implementieren nahtloser Loops und das Umschalten von einem Clip auf einen anderen. Sie ist sehr schnell, da das Video zuvor in eine Datei decodiert werden muss. In Ihrem Fall werden alle 10 Videoclips in Dateien dekodiert, bevor Sie beginnen. Das Umschalten zwischen ihnen ist jedoch schnell.

1
MoDJ

Das Asset ist möglicherweise nicht fertig, sobald Sie es erstellt haben. Es kann Berechnungen wie die Dauer des Films durchführen. Stellen Sie sicher, dass alle Metadaten des Films in der Datei enthalten sind. 

1
nova

Ohne so etwas in der Vergangenheit getan zu haben, würde ich, basierend auf Ihren Gedanken und Erfahrungen, eine Kombination aus 7 und 1 versuchen: Laden Sie einen AVPlayer mit den ersten Sekunden der 10 Folgevideos. Das Überspringen wird dann wahrscheinlich aufgrund von weniger Daten schneller und zuverlässiger. Während Sie das ausgewählte Stück abspielen, haben Sie genügend Zeit, um den AVPlayer für den Rest des ausgewählten Folgevideos im Hintergrund vorzubereiten. Wenn der Anfang abgeschlossen ist, wechseln Sie zum vorbereiteten AVPlayer. Insgesamt haben Sie also zu jeder Zeit maximal 2 AVPlayers geladen. 

Ich weiß natürlich nicht, ob das Umschalten so reibungslos vonstatten geht, dass es die Wiedergabe nicht stört.

(Hätte dies als Kommentar hinzugefügt, wenn ich könnte.)

Am besten, Peter 

0
ilmiacs

Für iOS 10.x und höher, um die Startverzögerung für den AVPlayer zu verringern, habe ich Folgendes festgelegt: avplayer.automaticallyWaitsToMinimizeStalling = false; und das schien es für mich zu beheben. Dies könnte andere Konsequenzen haben, die ich aber noch nicht getroffen habe.

Die Idee dazu hatte ich von: https://stackoverflow.com/a/50598525/9620547

0
grizzb

Wenn ich Ihr Problem richtig verstanden habe, scheint es, als hätten Sie ein fortlaufendes Video, in das Sie die Audiospur kurzfristig laden müssen.

Wenn dies der Fall ist, schlage ich vor, in BASS zu suchen. BASS ist eine Audiobibliothek ähnlich wie AVPlayer, mit der Sie (relativ) einfachen Zugriff auf die Low-Level-APIs des AudioUnits-Frameworks in iOS erhalten. Was bedeutet das für dich? Dies bedeutet, dass Sie mit einer kleinen Puffer-Manipulation (die Sie möglicherweise nicht einmal brauchen, abhängig davon, wie klein Sie die Verzögerung wünschen), sofort Musik abspielen können.

Die Einschränkungen erstrecken sich jedoch auch auf Video. Wie gesagt, es handelt sich um eine audio -Bibliothek, sodass jegliche Videomanipulation mit AVPlayer durchgeführt werden muss. Wenn Sie jedoch -seekToTime:toleranfeBefore:toleranceAfter: verwenden, sollten Sie in der Lage sein, innerhalb des Videos eine schnelle Suche durchzuführen, solange Sie mit allen erforderlichen Optionen vorlaufen. 

Wenn Sie über mehrere Geräte hinweg synchronisieren (was möglicherweise von Ihrer Anwendung vorgeschlagen wird), hinterlassen Sie einfach einen Kommentar, und ich würde gerne meine Antwort bearbeiten.

PS: BASS mag auf den ersten Blick aufgrund seines C-artigen Formats entmutigend wirken, aber es ist wirklich einfach zu verwenden, was es ist.

0
Ge0rges