Novedades sobre productos
Mejora de la reproducción de contenido multimedia: Presentamos la carga previa con Media3, parte 1
Lectura de 8 min
En las apps centradas en los medios de hoy en día, brindar una experiencia de reproducción fluida e ininterrumpida es clave para lograr una experiencia del usuario agradable. Los usuarios esperan que sus videos comiencen a reproducirse al instante y que se reproduzcan sin interrupciones.
El desafío principal es la latencia. Tradicionalmente, un reproductor de video solo comienza a funcionar (conectarse, descargar, analizar y almacenar en búfer) después de que el usuario elige un elemento para reproducir. Este enfoque reactivo es lento para el contexto actual de los videos de formato corto. La solución es ser proactivo. Debemos anticipar lo que mirará el usuario a continuación y preparar el contenido con anticipación. Esta es la esencia de la precarga.
Estos son los principales beneficios de la carga previa:
- 🚀 Inicio de reproducción más rápido: Los videos ya están listos para reproducirse, lo que genera transiciones más rápidas entre los elementos y un inicio más inmediato.
- 📉 Reducción del almacenamiento en búfer: Al cargar datos de forma proactiva, es mucho menos probable que la reproducción se detenga, por ejemplo, debido a problemas de red.
- ✨ Experiencia del usuario más fluida: La combinación de inicios más rápidos y menos almacenamiento en búfer crea una interacción más fluida y perfecta para que los usuarios disfruten.
En esta serie de tres partes, presentaremos y analizaremos en detalle las potentes utilidades de Media3 para cargar previamente componentes.
- En la Parte 1, abordaremos los conceptos básicos: comprender las diferentes estrategias de precarga disponibles en Media3, habilitar PreloadConfiguration y configurar DefaultPreloadManager, y habilitar tu app para que precargue elementos. Al final de este blog, deberías poder cargar previamente y reproducir elementos multimedia con la clasificación y la duración que configuraste.
- En la Parte 2, abordaremos temas más avanzados de DefaultPreloadManager: el uso de objetos de escucha para el análisis, la exploración de prácticas recomendadas listas para producción, como el patrón de ventana deslizante y los componentes compartidos personalizados de DefaultPreloadManager y ExoPlayer.
- En la parte 3, analizaremos en profundidad el almacenamiento en caché de disco con DefaultPreloadManager.
¡La precarga al rescate! 🦸♀️
La idea principal detrás de la carga previa es simple: cargar el contenido multimedia antes de que lo necesites. Cuando un usuario desliza el dedo para ir al siguiente video, los primeros segmentos del video ya se descargaron y están disponibles para su reproducción inmediata.
Piénsalo como si fuera un restaurante. Una cocina ocupada no espera un pedido para comenzar a cortar cebollas. 🧅 Hacen el trabajo de preparación con anticipación. La precarga es el trabajo de preparación del reproductor de video.
Cuando se habilita, la precarga puede ayudar a minimizar la latencia de unión cuando un usuario omite el elemento siguiente antes de que el búfer de reproducción llegue a él. Se prepara el primer período de la siguiente ventana y se almacenan en búfer las muestras de video, audio y texto. El período precargado se pone en cola más tarde en el reproductor con muestras almacenadas en búfer disponibles de inmediato y listas para enviarse al códec para la renderización.
En Media3, hay dos APIs principales para la carga previa, cada una adecuada para diferentes casos de uso. El primer paso es elegir la API correcta.
1. Cómo precargar elementos de la playlist con PreloadConfiguration
Este es el enfoque simple, útil para medios lineales y secuenciales, como las playlists en las que el orden de reproducción es predecible (como una serie de episodios). Le das al reproductor la lista completa de elementos multimedia con las APIs de playlist de ExoPlayer y configuras PreloadConfiguration para el reproductor. Luego, este precarga automáticamente los siguientes elementos de la secuencia según la configuración. Esta API intenta optimizar la latencia de unión cuando un usuario omite el elemento siguiente antes de que el búfer de reproducción ya se superponga con el elemento siguiente.
La precarga solo se inicia cuando no se está cargando contenido multimedia para la reproducción en curso, lo que evita que compita por el ancho de banda con la reproducción principal.
Si aún no sabes si necesitas la precarga, esta API es una excelente opción de bajo impacto para probarla.
player.preloadConfiguration =
PreloadConfiguration(/* targetPreloadDurationUs= */ 5_000_000L)
Con la PreloadConfiguration anterior, el reproductor intenta cargar previamente cinco segundos de contenido multimedia para el siguiente elemento de la playlist.
Una vez que habilites la opción, puedes volver a desactivar la precarga de playlists con PreloadConfiguration.DEFAULT:
player.preloadConfiguration = PreloadConfiguration.DEFAULT
2. Cómo precargar listas dinámicas con PreloadManager
La API de PreloadManager es adecuada para las IU dinámicas, como los feeds verticales o los carruseles, en los que el elemento "siguiente" se determina por la interacción del usuario. Este es un nuevo componente independiente y potente dentro de la biblioteca de Media3 ExoPlayer diseñado específicamente para la carga previa proactiva. Administra una colección de posibles MediaSources, priorizándolas según la proximidad a la posición actual del usuario y ofrece un control detallado sobre qué precargar, adecuado para situaciones complejas, como feeds dinámicos de videos de formato corto.
Cómo configurar tu PreloadManager
DefaultPreloadManager es la implementación canónica de PreloadManager.
El compilador de DefaultPreloadManager puede compilar tanto el DefaultPreloadManager como cualquier instancia de ExoPlayer que reproduzca su contenido precargado. Para crear un DefaultPreloadManager, deberás pasar un TargetPreloadStatusControl, que el administrador de carga previa puede consultar para averiguar cuánto cargar para un elemento. Explicaremos y definiremos un ejemplo de TargetPreloadStatusControl en la siguiente sección.
val preloadManagerBuilder = DefaultPreloadManager.Builder(context, targetPreloadStatusControl) val preloadManager = val preloadManagerBuilder.build() // Build ExoPlayer with DefaultPreloadManager.Builder val player = preloadManagerBuilder.buildExoPlayer()
Es necesario usar el mismo compilador para ExoPlayer y DefaultPreloadManager, lo que garantiza que los componentes internos de ambos se compartan correctamente.
Eso es todo. Ahora tienes un administrador listo para recibir instrucciones.
Configura la duración y la clasificación con TargetPreloadStatusControl
¿Qué sucede si quieres precargar, por ejemplo, 10 segundos de video? Puedes proporcionar la posición de tus elementos multimedia en el carrusel, y DefaultPreloadManager prioriza la carga de los elementos según qué tan cerca estén del elemento que el usuario está reproduciendo.
Si quieres controlar la duración del elemento que se precargará, puedes indicarlo con DefaultPreloadManager.PreloadStatus que devuelves.
Por ejemplo:
- El elemento "A" tiene la prioridad más alta, por lo que se cargan 5 segundos de video.
- El elemento "B" tiene prioridad media, pero, cuando llegues a él, carga 3 segundos de video.
- El elemento "C" tiene menos prioridad y solo se hace un seguimiento de las cargas.
- El elemento "D" tiene aún menos prioridad, solo prepáralo.
- Cualquier otro elemento está lejos. No se precarga nada.
Este control detallado puede ayudarte a optimizar el uso de recursos, lo que se recomienda para una reproducción sin problemas.
import androidx.media3.exoplayer.DefaultPreloadManager.PreloadStatus
class MyTargetPreloadStatusControl(
currentPlayingIndex: Int = C.INDEX_UNSET
) : TargetPreloadStatusControl<Int,PreloadStatus> {
// The app is responsible for updating this based on UI state
override fun getTargetPreloadStatus(index: Int): PreloadStatus? {
val distance = index - currentPlayingIndex
// Adjacent items (Next): preload 5 seconds
if (distance == 1) {
// Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED and suggest loading // 5000ms from the default start position
return PreloadStatus.specifiedRangeLoaded(5000L)
}
// Adjacent items (Previous): preload 3 seconds
else if (distance == -1) {
// Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED //and suggest loading 3000ms from the default start position
return PreloadStatus.specifiedRangeLoaded(3000L)
}
// Items two positions away: just select tracks
else if (distance) == 2) {
// Return a PreloadStatus that is labelled by STAGE_TRACKS_SELECTED
return PreloadStatus.TRACKS_SELECTED
}
// Items four positions away: just select prepare
else if (abs(distance) <= 4) {
// Return a PreloadStatus that is labelled by STAGE_SOURCE_PREPARED
return PreloadStatus.SOURCE_PREPARED
}
// All other items are too far away
return null
}
}
Nota: PreloadManager puede mantener precargados los elementos anteriores y siguientes, mientras que PreloadConfiguration solo buscará los elementos siguientes.
Administra elementos de precarga
Una vez que creaste tu administrador, puedes comenzar a indicarle en qué debe trabajar. A medida que el usuario se desplaza por un feed, identificarás los próximos videos y los agregarás al administrador. La interacción con PreloadManager es una conversación basada en el estado entre tu IU y el motor de carga previa.
1. Agregar elementos multimedia
A medida que completes tu feed, debes informar al administrador de los medios que debe hacer un seguimiento. Si estás comenzando, puedes agregar toda la lista que quieras precargar. Posteriormente, puedes seguir agregando un solo elemento a la lista cuando sea necesario. Tienes control total sobre los elementos que se encuentran en la lista de carga previa, lo que significa que también debes administrar lo que se agrega y quita del administrador.
val initialMediaItems = pullMediaItemsFromService(/* count= */ 20)
for (index in 0 until initialMediaItems.size) {
preloadManager.add(
initialMediaItems.get(index),index)
)
}
El administrador comenzará a recuperar datos para este MediaItem en segundo plano.
Después de agregarla, dile al administrador que vuelva a evaluar su nueva lista (sugiriendo que algo cambió, como agregar o quitar un elemento, o que el usuario cambió a reproducir un elemento nuevo).
preloadManager.invalidate()
2. Recupera y reproduce un elemento
Aquí se encuentra la lógica de reproducción principal. Cuando el usuario decide reproducir ese video, no es necesario que crees un nuevo MediaSource. En su lugar, le pides a PreloadManager el que ya preparó. Puedes recuperar el MediaSource del Preload Manager con el MediaItem.
Si el elemento recuperado de PreloadManager es nulo, significa que el elemento multimedia aún no se precargó ni se agregó a PreloadManager, por lo que decides establecer el elemento multimedia directamente.
// When a media item is about to display on the screen
val mediaSource = preloadManager.getMediaSource(mediaItem)
if (mediaSource!= null) {
player.setMediaSource(mediaSource)
} else {
// If mediaSource is null, that mediaItem hasn't been added yet.
// So, send it directly to the player.
player.setMediaItem(mediaItem)
}
player.prepare()
// When the media item is displaying at the center of the screen
player.play()
Cuando preparas el MediaSource recuperado de PreloadManager, realizas una transición sin problemas de la precarga a la reproducción, ya que usas los datos que ya están en la memoria. Esto es lo que hace que el tiempo de inicio sea más rápido.
3. Mantén el índice actual sincronizado con la IU
Dado que nuestro feed o lista puede ser dinámico, es importante notificarle al PreloadManager tu índice de reproducción actual para que siempre pueda priorizar los elementos más cercanos a tu índice actual para la precarga.
preloadManager.setCurrentPlayingIndex(currentIndex) // Need to call invalidate() to update the priorities preloadManager.invalidate()
4. Cómo quitar un elemento
Para que el administrador siga siendo eficiente, debes quitar los elementos que ya no necesite hacer un seguimiento, como los que están lejos de la posición actual del usuario.
// When an item is too far from the current playing index preloadManager.remove(mediaItem)
Si necesitas borrar todos los elementos a la vez, puedes llamar a preloadManager.reset().
5. Soltar al administrador
Cuando ya no necesites el PreloadManager (p.ej., cuando se destruye tu IU), debes liberarlo para liberar sus recursos. Un buen lugar para hacerlo es donde ya liberas los recursos del reproductor. Se recomienda lanzar el administrador antes que el jugador, ya que este puede seguir jugando si no necesitas más carga previa.
// In your Activity's onDestroy() or Composable's onDispose preloadManager.release()
Tiempo de demostración
Compruébalo en vivo 👍
En la siguiente demostración, vemos el impacto de PreloadManager en el lado derecho, que tiene tiempos de carga más rápidos, mientras que el lado izquierdo muestra la experiencia existente. También puedes ver el ejemplo de código de la demostración. (Bonus: También muestra la latencia de inicio de cada video).
¿Qué sigue?
¡Y con esto terminamos la parte 1! Ahora tienes las herramientas para crear un sistema de precarga dinámico. Puedes usar PreloadConfiguration para cargar previamente el siguiente elemento de una playlist en ExoPlayer o configurar un DefaultPreloadManager, agregar y quitar elementos sobre la marcha, configurar el estado de carga previa objetivo y recuperar correctamente el contenido cargado previamente para la reproducción.
En la Parte 2, profundizaremos en el DefaultPreloadManager. Exploraremos cómo detectar eventos de precarga, analizaremos prácticas recomendadas, como el uso de una ventana deslizante para evitar problemas de memoria, y echaremos un vistazo a los componentes compartidos personalizados de ExoPlayer y DefaultPreloadManager.
¿Tienes algún comentario que compartir? Esperamos recibir noticias tuyas.
Mantente atento y haz que tu app sea más rápida. 🚀
Seguir leyendo
-
Novedades sobre productos
Te damos la bienvenida a la segunda entrega de nuestra serie de tres partes sobre la precarga de contenido multimedia con Media3. Esta serie está diseñada para guiarte en el proceso de creación de experiencias multimedia altamente responsivas y de baja latencia en tus apps para Android.
Mayuri Khinvasara Khabya • Lectura de 9 min
-
Novedades sobre productos
Si eres desarrollador de Android y quieres implementar funciones innovadoras basadas en IA en tu app, hace poco lanzamos nuevas y potentes actualizaciones.
Thomas Ezan • Lectura de 3 min
-
Novedades sobre productos
Android 17 alcanzó la versión beta 4, la última versión beta programada de este ciclo de lanzamiento, un hito fundamental para la compatibilidad de las apps y la estabilidad de la plataforma.
Daniel Galpin • Lectura de 4 min
Mantente al día
Recibe la información más reciente sobre el desarrollo de Android en tu bandeja de entrada todas las semanas.