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

115

Hinweis für die folgende Frage: Alle Assets befinden sich lokal auf dem Gerät - es findet kein Netzwerk-Streaming statt. Die Videos enthalten Audiospuren.

Ich arbeite an einer iOS-Anwendung, bei der Videodateien mit minimaler Verzögerung abgespielt werden müssen, um den betreffenden Videoclip zu starten. Leider wissen wir nicht, welcher Videoclip als nächstes kommt, bis wir ihn tatsächlich starten müssen. Insbesondere: Wenn ein Videoclip abgespielt wird, wissen wir, was der nächste Satz von (ungefähr) 10 Videoclips ist, aber wir wissen nicht genau, welcher, bis es Zeit ist, den nächsten Clip "sofort" abzuspielen.

Um die tatsächlichen Startverzögerungen addBoundaryTimeObserverForTimeszu überprüfen, muss ich den Videoplayer mit einer Zeitspanne von einer Millisekunde aufrufen , um zu sehen, wann das Video tatsächlich abgespielt wurde, und ich nehme die Differenz dieses Zeitstempels mit dem ersten Platz in Der Code, der angibt, welches Asset abgespielt werden soll.

Nach dem, was ich bisher gesehen habe, habe ich festgestellt, dass es in der Regel zwischen 1 und 3 Sekunden dauert, die Kombination aus AVAssetLaden und erstmaligem Erstellen eines solchen zu erstellen AVPlayerItem, sobald es fertig ist, und dann zu warten, AVPlayerStatusReadyToPlaybevor ich das Spiel aufrufe Clip.

Ich habe seitdem zu dem gewechselt, was ich für ungefähr gleichwertig halte: anrufen [AVPlayerItem playerItemWithURL:]und darauf warten, AVPlayerItemStatusReadyToPlayzu spielen. Etwa die gleiche Leistung.

Eine Sache, die ich beobachte, ist, dass das Laden des ersten AVPlayer-Elements langsamer ist als der Rest. Eine Idee scheint darin zu bestehen, den AVPlayer mit einem kurzen / leeren Asset vorab zu fliegen, bevor der Versuch, das erste Video abzuspielen, allgemein sinnvoll ist. [ Langsamer Start für AVAudioPlayer beim ersten Abspielen eines Sounds

Ich würde gerne die Startzeiten des Videos so weit wie möglich verkürzen und einige Ideen für Experimente haben, möchte aber eine Anleitung von jedem, der helfen kann.

Update: Idee 7 unten, wie implementiert, ergibt Schaltzeiten von ca. 500 ms. Dies ist eine Verbesserung, aber es wäre schön, dies noch schneller zu erreichen.

Idee 1: Verwenden Sie N AVPlayers (funktioniert nicht)

Verwenden Sie ~ 10 AVPPlayerObjekte und starten und pausieren Sie alle ~ 10 Clips. Wenn Sie wissen, welche wir wirklich benötigen, wechseln Sie zu der richtigen AVPlayerund deaktivieren Sie sie. Beginnen Sie erneut für den nächsten Zyklus.

Ich denke nicht, dass dies funktioniert, da ich gelesen habe, dass AVPlayer'sin iOS ungefähr 4 aktiv sind . Auf StackOverflow hat hier jemand danach gefragt und sich über das 4-AVPlayer-Limit informiert: schnelles Umschalten zwischen Videos mithilfe von Avfoundation

Idee 2: Verwenden Sie AVQueuePlayer (funktioniert nicht)

Ich glaube nicht, dass das Schieben von 10 AVPlayerItemsin eine AVQueuePlayerfür einen nahtlosen Start alle vorladen würde. AVQueuePlayerist 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 wiedergeben möchten, bis es Zeit ist, dieses zu starten. ios-avplayer-video-vorladen

Idee 3: Laden, Spielen und Beibehalten AVPlayerItemsim Hintergrund (noch nicht 100% sicher - sieht aber nicht gut aus)

Ich prüfe, ob es einen Vorteil hat, die erste Sekunde jedes Videoclips im Hintergrund zu laden und abzuspielen (Video- und Audioausgabe unterdrücken) und einen Verweis auf jeden zu behalten AVPlayerItem, und wann wir wissen, für welches Element abgespielt werden muss real, tauschen Sie diesen aus und tauschen Sie den Hintergrund-AVPlayer gegen den aktiven aus. Spülen und wiederholen.

Die Theorie wäre, dass kürzlich gespielte Spiele AVPlayer/AVPlayerItemmöglicherweise noch einige vorbereitete Ressourcen enthalten, die die nachfolgende Wiedergabe beschleunigen würden. Bisher habe ich keine Vorteile daraus gesehen, aber möglicherweise habe ich das AVPlayerLayerSetup für den Hintergrund nicht richtig. Ich bezweifle, dass dies die Dinge von dem, was ich gesehen habe, wirklich verbessern wird.

Idee 4: Verwenden Sie ein anderes Dateiformat - vielleicht eines, das schneller zu laden ist?

Ich verwende derzeit das H.264-Format von .m4v (Video-MPEG4). H.264 verfügt über viele verschiedene Codec-Optionen, sodass einige Optionen möglicherweise schneller zu suchen sind als andere. Ich habe festgestellt, dass die Verwendung erweiterter Einstellungen, die die Dateigröße verringern, die Suchzeit verlängert, aber keine Optionen gefunden, die in die andere Richtung gehen.

Idee 5: Kombination aus verlustfreiem Videoformat und AVQueuePlayer

Wenn es ein Videoformat gibt, das schnell geladen werden kann, dessen Dateigröße jedoch möglicherweise verrückt ist, besteht eine Idee darin, die ersten 10 Sekunden jedes Videoclips mit einer Version vorzubereiten, die aufgebläht, aber schneller zu laden ist, aber zurück das mit einem Asset, das in H.264 codiert ist. Verwenden Sie einen AVQueuePlayer, fügen Sie die ersten 10 Sekunden im unkomprimierten Dateiformat hinzu und folgen Sie dem in H.264, das 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 meinen eigenen / verwenden Sie den eines anderen

Aufgrund meiner Anforderungen kann ich AVPlayer möglicherweise nicht verwenden, muss jedoch auf AVAssetReader zurückgreifen und die ersten Sekunden dekodieren (möglicherweise eine Rohdatei auf die Festplatte schreiben). Verwenden Sie bei der Wiedergabe das Rohformat, um sie abzuspielen schnell zurück. Scheint mir ein riesiges Projekt zu sein, und wenn ich es naiv mache, ist es unklar / unwahrscheinlich, dass es überhaupt besser funktioniert. Jeder dekodierte und unkomprimierte Videorahmen ist 2,25 MB groß. Naiv gesprochen - wenn wir für das Video ~ 30 fps verwenden, würde ich am Ende ~ 60 MB / s für das Lesen von der Festplatte benötigen, was wahrscheinlich unmöglich ist / es pusht. Natürlich müssten wir ein gewisses Maß an Bildkomprimierung durchführen (vielleicht native openGL / es-Komprimierungsformate ü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 Film-Asset und suchen Sie nach Zeit

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

Welcher Ansatz wäre Ihrer Meinung nach der beste? Bisher habe ich bei der Reduzierung der Verzögerung nicht so viele Fortschritte erzielt.

Bernt Habermeier
quelle
Für das, was es wert ist, gehe ich mit Idee 7. Es ist immer noch langsam, aber nicht so unvorhersehbar langsam wie die anderen Optionen. Die nächste Frage, die ich habe, lautet: Haben Codec-Optionen, Auflösung und Keyframe-Frequenz einen Einfluss auf das seekto-Timing?
Bernt Habermeier
Spät im Spiel, aber es kann sich lohnen, Videos so schnell wie möglich zu wechseln (dh unmittelbar nachdem das neue Spiel abgespielt wurde) und die App zu profilieren, um zu sehen, wo sie den größten Teil ihrer CPU-Zeit verbringt.
tc.
1
Was haben Sie fast ein Jahr später jemals damit herausgefunden?
lnafziger
1
Ich entschied mich für Option 7 und kam an einen Ort zwischen 300 ms und 500 ms. Eine Sache, die ich gefunden habe, ist, dass je schicker die MP4-Codec-Optionen sind, desto langsamer ist die Suche nach. Es gibt einige Videokomprimierungsoptionen, die eine bessere Komprimierung ermöglichen und die Videoqualität beibehalten, aber die Dekodierungszeit verkürzen.
Bernt Habermeier
2
Das ist eine vernünftig klingende Anfrage, aber um Option 7 wirklich zu implementieren, gibt es zu viele Facetten in der Implementierung, um sie zu veröffentlichen. Beachten Sie: (a) Erstellen Sie eine Toolkette zum Zusammenführen von Video-Assets, (b) stellen Sie sicher, dass Sie die Videosegment-Offsets verfolgen, (c) suchen Sie nach Offsets, wenn eine Anforderung zum Abspielen eines bestimmten Clips eingeht, (d) verwenden Sie addPeriodicTimeObserverForInterval, um dies zu überprüfen Wenn Sie einen Videoclip gestartet haben und entsprechend reagieren (verwenden Sie diese Methode im Vergleich zu einer Einzelaufnahme von addBoundaryTimeObserverForTimes, da ich festgestellt habe, dass letzteres manchmal nicht ausgelöst wird ... insgesamt eignet sich dies nicht zum Einfügen von Code.
Bernt Habermeier

Antworten:

3

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

Ich hatte die Idee dazu von: https://stackoverflow.com/a/50598525/9620547

grizzb
quelle
1

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

Nova
quelle
1

Sie sollten zuerst Option 7 ausprobieren, um zu sehen, ob Sie das zum Laufen bringen können. Ich vermute, dass es für Ihre Anforderungen nicht funktioniert, da die Suchzeit wahrscheinlich nicht schnell genug ist, um nahtlos zwischen Clips zu wechseln. Wenn Sie dies versuchen und es fehlschlägt, würde ich empfehlen, dass Sie Option 4/6 ausführen und sich meine speziell für diesen Zweck entwickelte iOS-Bibliothek ansehen. Führen Sie einfach eine schnelle Google-Suche in AVAnimator durch, um mehr zu erfahren. Meine Bibliothek ermöglicht es, nahtlose Schleifen zu implementieren und von einem Clip zum anderen zu wechseln. Dies ist sehr schnell, da Videos zuvor in eine Datei dekodiert werden müssen. In Ihrem Fall würden alle 10 Videoclips vor Beginn in Dateien dekodiert, aber der Wechsel zwischen ihnen wäre schnell.

MoDJ
quelle
Was ist mit dem Audioteil des Videos? Ich brauche Video und Audio, um synchronisiert zu werden.
Bernt Habermeier
Ja, Audio wird bereits mit einer sehr engen Synchronisation zwischen der Audiospur und dem Videoclip verarbeitet. Siehe das Beispiel xcode-Projekte. Es ist bereits alles implementiert, Sie müssen es nur herunterladen und ausprobieren.
MoDJ
Gibt es eine Möglichkeit, Netzwerkvideos mit AVAnimator abzuspielen?
Richard Topchii
Nein, es funktioniert mit lokalen Dateien. Das Streamen von Netzwerkvideos ist eine ganz andere Sache.
MoDJ
0

Ohne in der Vergangenheit so etwas getan zu haben, würde ich aufgrund Ihrer Gedanken und Erfahrungen eine Kombination aus 7 und 1 versuchen: Laden Sie einen AVPlayer mit den ersten Sekunden der 10 Folgevideos vor. Dann wird das Überspringen aufgrund weniger Daten sehr wahrscheinlich schneller und zuverlässiger sein. 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 beendet ist, wechseln Sie zum vorbereiteten AVPlayer. Insgesamt sind also zu einem bestimmten Zeitpunkt maximal 2 AVPlayers geladen.

Natürlich weiß ich nicht, ob das Umschalten so reibungslos erfolgen kann, dass es die Wiedergabe nicht stört.

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

Am besten, Peter

Ilmiacs
quelle
Ich habe keinen Vorteil gefunden, 10 Assets in Serie auf einen AVPlayer zu laden. Außerdem verstehe ich Ihren Vorschlag nicht, da sich Option (1) und (7) gegenseitig ausschließen. Option 7 führt alle Video-Assets zu einem einzigen Asset zusammen. Daher muss nur ein einziges Asset geladen werden. Dies ist, was ich heute mache, und für das, was es wert ist, bekomme ich eine Verzögerung von ungefähr 500 ms für die tatsächlichen Start- / Spielzeiten. Es ist erwähnenswert, dass der SeekTo schneller abgeschlossen wird als das eigentliche erste Bild abgespielt wird. Für echte Startzeiten messe ich also, wann das erste Bild tatsächlich über einen zeitgesteuerten Rückruf wiedergegeben wird.
Bernt Habermeier
Nur um meine Idee klar zu machen: Meine Idee war es, einen Vermögenswert in zwei Teile aufzuteilen: die ersten Sekunden und den Rest. Jetzt haben Sie zwei Assets aus einem gemacht. Die 10 Anfänge, denen Sie beitreten und die Sie überspringen würden, und während Sie den Anfang spielen, würden Sie den Rest laden. Dies umfasst dann Vorschlag 8, der Ihrer Liste hinzugefügt wird.
Ilmiacs
Aber wie ich aus Ihrem letzten Kommentar verstehe, haben Sie inzwischen die Forschung weiter vorangetrieben, was gut ist, und Lösung 7 funktioniert auch nicht. Es sieht so aus, als ob AV Ihnen grundsätzlich im Weg bleibt und der einzige Weg für Sie wahrscheinlich darin besteht, die darunter liegende Technologie, dh Core Media, zu verwenden, um mehr Kontrolle über Ihre Assets zu erhalten. Peter.
Ilmiacs
Oh, ich verstehe deine Idee jetzt besser. Vielen Dank. Es wäre interessant zu untersuchen, ob Sie schnelle Suchzeiten für kurze Videoclips erhalten. Ich habe das noch nicht versucht, wäre aber eine Überlegung wert. In Bezug auf die Verwendung von Kernmedien - Ich habe kein gutes Referenzmaterial zu dieser API gefunden. Haben Sie eine gute Ressource, auf die Sie mich hinweisen können?
Bernt Habermeier
Nein Entschuldigung. Wie gesagt, ich bin kein Experte für AV oder Core Media. Lesen Sie einfach Ihre Frage und hatten Sie einige Ideen, wie ich persönlich vorgehen würde, und wollten sie teilen. Peter
Ilmiacs
0

Wenn ich Ihr Problem richtig verstanden habe, haben Sie anscheinend ein fortlaufendes Video, für das Sie die Audiospur kurzfristig laden müssen.

Wenn dies der Fall ist, schlage ich vor, sich mit BASS zu befassen . BASS ist eine Audiobibliothek ähnlich wie AVPlayer, mit der Sie (relativ) einfach auf die Low-Level-APIs des AudioUnits-Frameworks in iOS zugreifen können. Was bedeutet das für dich? Dies bedeutet, dass Sie mit ein wenig Puffermanipulation (Sie benötigen sie möglicherweise nicht einmal, hängt davon ab, wie klein die Verzögerung sein soll) sofort mit der Musikwiedergabe beginnen können.

Die Grenzen erweitern jedoch auf Video, wie gesagt, es ist eine ist Audio- Bibliothek so dass jede Videomanipulation wird noch mit AVPlayer getan werden muß. Mit -seekToTime:toleranfeBefore:toleranceAfter:sollten Sie jedoch in der Lage sein, eine schnelle Suche innerhalb des Videos zu erreichen, solange Sie mit allen erforderlichen Optionen vorab rollen.

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

PS: BASS mag aufgrund seines C-ähnlichen Formats zunächst entmutigend aussehen, aber es ist wirklich sehr einfach zu verwenden, wie es ist.

Esel
quelle
-2

Hier sind einige Eigenschaften und Methoden der AVAsset-Klasse, die hilfreich sein können:

- (void)_pu_setCachedDuration:(id)arg1;
- (id)pu_cachedDuration; 
- (struct
 { 
   long long x1; 
   int x2;
   unsigned int x3; 
   long long x4; 
})pu_duration;
- (void)pu_loadDurationWithCompletionHandler:(id /* block */)arg1;
James Bush
quelle