Cómo reducir el retraso de inicio de iOS AVPlayer

115

Tenga en cuenta que para la siguiente pregunta: Todos los activos son locales en el dispositivo; no se está realizando ninguna transmisión de red. Los videos contienen pistas de audio.

Estoy trabajando en una aplicación de iOS que requiere reproducir archivos de video con un retraso mínimo para iniciar el videoclip en cuestión. Desafortunadamente, no sabemos qué videoclip específico es el siguiente hasta que realmente necesitamos iniciarlo. Específicamente: cuando se reproduce un videoclip, sabremos cuál es el siguiente conjunto de (aproximadamente) 10 videoclips, pero no sabemos cuál es exactamente, hasta que llegue el momento de reproducir "inmediatamente" el siguiente clip.

Lo que he hecho para ver los retrasos de inicio reales es llamar addBoundaryTimeObserverForTimesal reproductor de video, con un período de tiempo de un milisegundo para ver cuándo comenzó a reproducirse el video, y tomo la diferencia de esa marca de tiempo con el primer lugar en el código que indica qué activo comenzar a jugar.

Por lo que he visto hasta ahora, he descubierto que usar la combinación de AVAssetcargar, y luego crear una a AVPlayerItempartir de eso una vez que está lista, y luego esperar AVPlayerStatusReadyToPlayantes de llamar a play, tiende a tomar entre 1 y 3 segundos para iniciar la acortar.

Desde entonces, cambié a lo que creo que es aproximadamente equivalente: llamar [AVPlayerItem playerItemWithURL:]y esperar para AVPlayerItemStatusReadyToPlayjugar. Aproximadamente el mismo rendimiento.

Una cosa que estoy observando es que la carga del primer elemento de AVPlayer es más lenta que el resto. Parece que una idea es realizar un vuelo previo del AVPlayer con un activo corto / vacío antes de intentar reproducir el primer video. Podría ser una buena práctica general. [ Inicio lento para AVAudioPlayer la primera vez que se reproduce un sonido

Me encantaría reducir los tiempos de inicio del video tanto como sea posible y tener algunas ideas de cosas con las que experimentar, pero me gustaría recibir orientación de cualquier persona que pueda ayudar.

Actualización: la idea 7, a continuación, según se implementa, produce tiempos de conmutación de alrededor de 500 ms. Esto es una mejora, pero sería bueno hacerlo aún más rápido.

Idea 1: use N AVPlayers (no funcionará)

Usando ~ 10 AVPPlayerobjetos e inicie y pause los ~ 10 clips, y una vez que sepamos cuál necesitamos realmente, cambiemos y cancelemos la pausa del correcto AVPlayer, y comience de nuevo para el siguiente ciclo.

No creo que esto funcione, porque he leído que hay aproximadamente un límite de 4 activos AVPlayer'sen iOS. Alguien preguntó sobre esto en StackOverflow aquí y descubrió el límite de 4 AVPlayer: cambio rápido entre videos usando avfoundation

Idea 2: use AVQueuePlayer (no funcionará)

No creo que meter 10 AVPlayerItemsen un AVQueuePlayerprecargarlos todos para comenzar sin problemas. AVQueuePlayeres una cola, y creo que en realidad solo hace que el siguiente video de la cola esté listo para su reproducción inmediata. No sé cuál de ~ 10 videos queremos reproducir, hasta que sea el momento de comenzar con ese. ios-avplayer-video-preloading

Idea 3: cargar, reproducir y retener AVPlayerItemsen segundo plano (todavía no estoy 100% seguro, pero no se ve bien)

Estoy viendo si hay algún beneficio para cargar y reproducir el primer segundo de cada clip de video en segundo plano (suprimir la salida de video y audio), y mantener una referencia a cada uno AVPlayerItem, y cuando sepamos qué elemento debe reproducirse real, cámbielo y cambie el AVPlayer de fondo por el activo. Enjuague y repita.

La teoría sería que los reproducidos recientemente AVPlayer/AVPlayerItempueden contener algunos recursos preparados que harían más rápida la reproducción posterior. Hasta ahora, no he visto beneficios de esto, pero es posible que no tenga la AVPlayerLayerconfiguración correcta para el fondo. Dudo que esto realmente mejore las cosas de lo que he visto.

Idea 4: utilice un formato de archivo diferente, ¿tal vez uno que sea más rápido de cargar?

Actualmente estoy usando el formato H.264 de .m4v (video-MPEG4). H.264 tiene muchas opciones de códec diferentes, por lo que es posible que algunas opciones sean más rápidas de buscar que otras. Descubrí que el uso de configuraciones más avanzadas que hacen que el tamaño del archivo sea más pequeño aumenta el tiempo de búsqueda, pero no he encontrado ninguna opción que vaya al revés.

Idea 5: combinación de formato de video sin pérdida + AVQueuePlayer

Si hay un formato de video que se carga rápidamente, pero tal vez donde el tamaño del archivo es una locura, una idea podría ser preparar previamente los primeros 10 segundos de cada clip de video con una versión que esté hinchada pero que se cargue más rápido, pero al revés eso con un activo que está codificado en H.264. Use un AVQueuePlayer y agregue los primeros 10 segundos en el formato de archivo sin comprimir, y continúe con uno que esté en H.264 que obtenga hasta 10 segundos de tiempo de preparación / precarga. Así que obtendría "lo mejor" de ambos mundos: tiempos de inicio rápidos, pero también se beneficia de un formato más compacto.

Idea 6: use un AVPlayer no estándar / escriba el mío / use el de otra persona

Dadas mis necesidades, tal vez no pueda usar AVPlayer, pero tengo que recurrir a AVAssetReader y decodificar los primeros segundos (posiblemente escribir un archivo sin procesar en el disco), y cuando se trata de reproducción, hacer uso del formato sin procesar para reproducirlo. volver rápido. Me parece un gran proyecto, y si lo hago de una manera ingenua, no está claro / es poco probable que funcione mejor. Cada cuadro de video decodificado y sin comprimir es de 2.25 MB. Hablando ingenuamente, si elegimos ~ 30 fps para el video, terminaría con un requisito de lectura desde el disco de ~ 60 MB / s, lo que probablemente sea imposible / presionarlo. Obviamente, tendríamos que hacer algún nivel de compresión de imagen (quizás formatos de compresión nativos openGL / es a través de PVRTC) ... pero eso es una locura. ¿Quizás hay una biblioteca que pueda usar?

Idea 7: combine todo en un solo recurso de película y busque a tiempo

Una idea que podría ser más fácil que algunas de las anteriores es combinar todo en una sola película y usar seekToTime. Lo que pasa es que estaríamos saltando por todos lados. Acceso esencialmente aleatorio a la película. Creo que esto puede funcionar bien: avplayer-movie-playing-lag-in-ios5

¿Qué enfoque crees que sería mejor? Hasta ahora, no he avanzado mucho en términos de reducir el retraso.

Bernt Habermeier
fuente
Por lo que vale, voy con Idea 7. Todavía es lento, pero no tan impredeciblemente lento como las otras opciones. La siguiente pregunta que tengo es: ¿las opciones de códec, la resolución y la frecuencia de fotogramas clave tienen un impacto en el tiempo de búsqueda?
Bernt Habermeier
Tarde para el juego, pero puede valer la pena cambiar los videos lo más rápido posible (es decir, inmediatamente después de que comience a reproducirse el nuevo) y perfilar la aplicación para ver dónde pasa la mayor parte de su tiempo de CPU.
tc.
1
Casi un año después, ¿qué descubriste con esto?
lnafziger
1
Fui con la opción 7 y llegué a un lugar entre búsquedas de 300 ms y 500 ms. Una cosa que encontré es que cuanto más elegantes son las opciones del códec mp4, más lento es el seekTo. Hay algunas opciones de compresión de video que permiten una mejor compresión y mantienen la calidad del video, pero eliminan el tiempo de decodificación.
Bernt Habermeier
2
Esa es una solicitud que suena razonable, pero realmente para implementar la opción 7, hay demasiadas facetas en la implementación para publicar. Considere: (a) Cree una cadena de herramientas para fusionar activos de video, (b) asegúrese de realizar un seguimiento de las compensaciones de los segmentos de video, (c) las compensaciones de búsqueda cuando ingrese una solicitud para reproducir un clip específico, (d) use addPeriodicTimeObserverForInterval para verificar si se escapó de un videoclip y reaccionó en consecuencia (use este método frente a un addBoundaryTimeObserverForTimes de un solo disparo porque descubrí que este último a veces no se activa ... en general, esto no se presta para pegar código.
Bernt Habermeier

Respuestas:

4

Para iOS 10.xy superior para reducir el retraso de inicio de AVPlayer, configuré: avplayer.automaticallyWaitsToMinimizeStalling = false; y eso pareció arreglarlo para mí. Esto podría tener otras consecuencias, pero aún no las he alcanzado.

Tengo la idea de: https://stackoverflow.com/a/50598525/9620547

grizzb
fuente
Obtuve 6-7 segundos de reducción en el retraso. Pero tengo una pregunta aquí, ¿afectará el rendimiento de la aplicación?
Kalpa
@kalpa Hemos utilizado este código en una aplicación de producción durante más de un año sin efectos negativos perceptibles. En su mayoría, reproducimos archivos de audio de 20 a 60 minutos para oyentes en los EE. UU., Donde la cobertura de datos móviles es generalmente rápida. Sin embargo, su caso de uso podría ser diferente.
Grizzb
Gracias por la info. @grizzb
kalpa
1

Es posible que el activo no esté listo una vez que lo cree, puede realizar cálculos como la duración de la película, asegúrese de contener todos los metadatos de la película en el archivo.

estrella nueva
fuente
1

Primero debe probar la opción # 7, solo para ver si puede hacer que funcione. Sospecho que en realidad no funcionará para sus necesidades, ya que es probable que el tiempo de búsqueda no sea lo suficientemente rápido como para brindarle un cambio perfecto entre clips. Si lo intenta y falla, le aconsejaría que opte por la opción 4/6 y eche un vistazo a mi biblioteca de iOS diseñada específicamente para este propósito, simplemente haga una búsqueda rápida en Google en AVAnimator para obtener más información. Mi biblioteca permite implementar bucles sin interrupciones y cambiar de un clip a otro, es muy rápido porque el video debe decodificarse en un archivo de antemano. En su caso, los 10 videoclips se decodificarían en archivos antes de comenzar, pero luego cambiar entre ellos sería rápido.

MoDJ
fuente
¿Qué pasa con la parte de audio del video? Necesito sincronizar video y audio.
Bernt Habermeier
Sí, el audio ya se maneja con una sincronización muy estrecha entre la pista de audio y el videoclip. Vea los proyectos de xcode de ejemplo. Ya está todo implementado, solo necesitas descargarlo y probarlo.
MoDJ
¿Existe la posibilidad de reproducir videos en red usando AVAnimator?
Richard Topchii
No, funciona con archivos locales, la transmisión de video en red es algo completamente diferente.
MoDJ
0

Sin haber hecho nada como esto en el pasado, basándome en sus pensamientos y experiencias, probaría una combinación de 7 y 1: precargue un AVPlayer con los primeros segundos de los 10 videos de seguimiento. Entonces, es muy probable que la omisión sea más rápida y confiable debido a la menor cantidad de datos. Mientras reproduce la pieza seleccionada, tiene tiempo suficiente para preparar el AVPlayer para el resto del video de seguimiento seleccionado en segundo plano. Cuando finaliza el comienzo, cambia al AVPlayer preparado. Entonces, en total, en un momento dado tiene un máximo de 2 AVPlayers cargados.

Por supuesto, no sé si el cambio se puede hacer con tanta fluidez que no perturbe la reproducción.

(Habría agregado esto como comentario si pudiera).

Mejor, Peter

ilmiacs
fuente
No he encontrado ningún beneficio de cargar 10 activos en serie en un AVPlayer. Además, no entiendo su sugerencia, ya que veo la opción (1) y (7) mutuamente excluyentes. La opción 7 fusiona todos los activos de video en un solo activo, por lo que solo hay un activo para el período de carga. Esto es lo que estoy haciendo hoy, y por lo que vale, estoy obteniendo un retraso de aproximadamente 500 ms en los tiempos reales de inicio / reproducción. Vale la pena señalar que el SeekTo se completa más rápido de lo que se reproduce el primer fotograma real, por lo que para los tiempos de inicio verdaderos, mido cuándo se está reproduciendo el primer fotograma a través de una devolución de llamada temporizada.
Bernt Habermeier
Solo para aclarar mi idea: Mi idea era dividir un activo en dos partes: los primeros segundos y el resto. Ahora ha hecho dos activos de uno. Los 10 comienzos a los que te unirías y usarías saltan y mientras juegas el comienzo cargarías el resto. Esto luego comprende la sugerencia 8 que se agrega a su lista.
ilmiacs
Pero según tengo entendido por su último comentario, mientras tanto impulsó la investigación más, lo cual es bueno, y la solución 7 tampoco funciona. Parece como si AV fundamentalmente se interpusiera en su camino y la única forma de hacerlo probablemente sea usar la tecnología subyacente, es decir, Core Media, para obtener más control sobre sus activos. Peter.
ilmiacs
Oh, ahora entiendo mejor tu idea. Gracias. Sería interesante investigar si obtiene tiempos de búsqueda rápidos para videoclips cortos. No lo he probado todavía, pero valdría la pena considerarlo. Con respecto al uso de los medios principales, no he encontrado ningún buen material de referencia en esa API. ¿Tiene un buen recurso que pueda señalarme?
Bernt Habermeier
No, lo siento. Como dije, no soy un experto ni en AV ni en Core Media. Acabo de leer su pregunta y tenía algunas ideas sobre cómo proceder personalmente y quería compartirlas. Peter
ilmiacs
0

Si entendí correctamente su problema, parece que tiene un video continuo en el que necesita cargar la pista de audio en un momento.

Si ese es el caso, sugiero mirar en BASS . BASS es una biblioteca de audio muy parecida a AVPlayer que le brinda (relativamente) fácil acceso a las API de bajo nivel del marco AudioUnits en iOS. ¿Qué significa para ti? Significa que con un poco de manipulación del búfer (es posible que ni siquiera lo necesite, depende de qué tan pequeño desee el retraso) puede comenzar a reproducir música al instante.

Sin embargo, las limitaciones se extienden al video, como dije, es una biblioteca de audio , por lo que cualquier manipulación de video deberá realizarse con AVPlayer. Sin embargo, al usarlo -seekToTime:toleranfeBefore:toleranceAfter:, debería poder lograr una búsqueda rápida dentro del video siempre que realice un pre-roll con todas las opciones necesarias.

Si está sincronizando en varios dispositivos (lo que su aplicación podría sugerir) simplemente deje un comentario y estaré encantado de editar mi respuesta.

PD: BASS puede parecer desalentador al principio debido a su formato tipo C, pero es realmente muy fácil de usar por lo que es.

Burro
fuente
-2

Aquí hay varias propiedades y métodos proporcionados por la clase AVAsset que pueden ayudar:

- (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
fuente