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 addBoundaryTimeObserverForTimes
zu ü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 AVAsset
Laden und erstmaligem Erstellen eines solchen zu erstellen AVPlayerItem
, sobald es fertig ist, und dann zu warten, AVPlayerStatusReadyToPlay
bevor 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, AVPlayerItemStatusReadyToPlay
zu 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 AVPPlayer
Objekte und starten und pausieren Sie alle ~ 10 Clips. Wenn Sie wissen, welche wir wirklich benötigen, wechseln Sie zu der richtigen AVPlayer
und deaktivieren Sie sie. Beginnen Sie erneut für den nächsten Zyklus.
Ich denke nicht, dass dies funktioniert, da ich gelesen habe, dass AVPlayer's
in 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 AVPlayerItems
in eine AVQueuePlayer
für einen nahtlosen Start alle 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 wiedergeben möchten, bis es Zeit ist, dieses zu starten. ios-avplayer-video-vorladen
Idee 3: Laden, Spielen und Beibehalten AVPlayerItems
im 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/AVPlayerItem
mö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 AVPlayerLayer
Setup 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.
Antworten:
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
quelle
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.
quelle
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.
quelle
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
quelle
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.
quelle
Hier sind einige Eigenschaften und Methoden der AVAsset-Klasse, die hilfreich sein können:
quelle