Tunelización de contenido multimedia

La tunelización multimedia permite que los datos de video comprimidos formen una tunelización a través de un hardware un decodificador de video directamente a una pantalla, sin que el código de la app o Código del framework de Android El código específico del dispositivo debajo de la pila de Android determina qué fotogramas de video enviar a la pantalla y cuándo enviarlos comparando las marcas de tiempo de presentación de fotogramas con una de las siguientes tipos de reloj interno:

  • Para la reproducción de videos a pedido en Android 5 o versiones posteriores, una AudioTrack reloj sincronizado con marcas de tiempo de presentación de audio aprobada ingreso de la app

  • Para la reproducción de transmisiones en vivo en Android 11 o versiones posteriores, se usa un reloj de referencia de programa. (PCR) o reloj del sistema (STC) controlado por un afinador

Información general

La reproducción de video tradicional en Android notifica. la app cuando se decodifica un fotograma comprimido. Luego, la app versiones el fotograma de video decodificado en la pantalla para que se renderice en el mismo reloj del sistema tiempo que el marco de audio correspondiente, recuperar el historial AudioTimestamps para calcular el tiempo correcto.

Porque la reproducción de video en túnel omite el código de la app y reduce que actúan sobre el video, puede proporcionar una renderización de video más eficaz según la implementación del OEM. También puede brindar imágenes más precisas la cadencia y la sincronización con el reloj elegido (PRC, STC o audio) evitando problemas de sincronización que se generan a causa de un posible sesgo entre la sincronización de Android solicitudes para renderizar video y el tiempo de verdaderos vsyncs de hardware. Sin embargo, la tunelización también puede reducir la compatibilidad con efectos de GPU, como desenfoque o redondeadas en las ventanas de pantalla en pantalla (PIP), ya que los búferes omitir la pila de gráficos de Android.

En el siguiente diagrama, se muestra cómo la tunelización simplifica el proceso de reproducción de video.

comparación entre la tradición y los modos de túnel

Figura 1: Comparación de los procesos de reproducción de video tradicionales y en túnel

Para desarrolladores de apps

Debido a que la mayoría de los desarrolladores de apps se integran con una biblioteca para la reproducción implementación, en la mayoría de los casos, la implementación solo requiere la reconfiguración de esa para la reproducción en túnel. Para la implementación de bajo nivel de un video en túnel reproductor, sigue estas instrucciones.

Para la reproducción de video a pedido en Android 5 o versiones posteriores:

  1. Crea una instancia de SurfaceView.

  2. Crea una instancia de audioSessionId.

  3. Crea instancias AudioTrack y MediaCodec con audioSessionId instancia creada en el paso 2.

  4. Pon en cola datos de audio en AudioTrack con la marca de tiempo de presentación del primer marco de audio en los datos de audio.

Para la reproducción de transmisiones en vivo en Android 11 o versiones posteriores, haz lo siguiente:

  1. Crea una instancia de SurfaceView.

  2. Obtén una instancia de avSyncHwId de Tuner.

  3. Crea instancias AudioTrack y MediaCodec con la instancia avSyncHwId creada en el paso 2.

El flujo de llamada a la API se muestra en los siguientes fragmentos de código:

aab.setContentType(AudioAttributes.CONTENT_TYPE_MOVIE);

// configure for audio clock sync
aab.setFlag(AudioAttributes.FLAG_HW_AV_SYNC);
// or, for tuner clock sync (Android 11 or higher)
new tunerConfig = TunerConfiguration(0, avSyncId);
aab.setTunerConfiguration(tunerConfig);
if (codecName == null) {
  return FAILURE;
}

// configure for audio clock sync
mf.setInteger(MediaFormat.KEY_AUDIO_SESSION_ID, audioSessionId);
// or, for tuner clock sync (Android 11 or higher)
mf.setInteger(MediaFormat.KEY_HARDWARE_AV_SYNC_ID, avSyncId);

Comportamiento de la reproducción de videos a pedido

Porque la reproducción de video on demand en túnel está vinculada implícitamente a AudioTrack reproducción, el comportamiento de la reproducción de video en túnel puede depender del de la reproducción de audio.

  • En la mayoría de los dispositivos, de forma predeterminada, los fotogramas de video no se renderizan hasta que se escucha el audio. comenzará la reproducción. Sin embargo, es posible que la app necesite renderizar un fotograma antes Iniciar la reproducción de audio, por ejemplo, para mostrarle al usuario el video actual la posición mientras buscas.

    • Para indicar que el primer fotograma de video en fila se debe renderizar en cuanto se decodifica, establece el PARAMETER_KEY_TUNNEL_PEEK parámetro en 1. Cuando se reordenan los fotogramas de video comprimidos en la fila (por ejemplo, cuando Fotogramas B las imágenes), esto significa que el primer fotograma de video que se muestra siempre debe ser un iframe

    • Si no quieres que el primer fotograma de video en cola se renderice hasta el audio comienza la reproducción, establece este parámetro en 0.

    • Si no se establece este parámetro, el OEM determina el comportamiento del dispositivo.

  • Cuando no se proporcionan datos de audio a AudioTrack y los búferes están vacíos (subdesbordamiento de audio), la reproducción de video se detiene hasta que se escriben más datos de audio porque el reloj de audio ya no avanza.

  • Durante la reproducción, pueden aparecer discontinuidades que la app no puede corregir marcas de tiempo de presentaciones de audio. Cuando esto sucede, el OEM corrige brechas existentes al detener el fotograma actual y brechas positivas al disminuir fotogramas de video o la inserción de audios silenciosos (según el OEM implementación). La posición del marco AudioTimestamp no aumenta para se insertaron marcos de audio silenciosos.

Para fabricantes de dispositivos

Configuración

Los OEMs deben crear un decodificador de video independiente para admitir la reproducción de video en túnel. Este decodificador debería anunciar que es capaz de reproducir contenido en túnel en la Archivo media_codecs.xml:

<Feature name="tunneled-playback" required="true"/>

Cuando se configura una instancia MediaCodec tunelizada con un ID de sesión de audio, consulta AudioFlinger para este ID de HW_AV_SYNC:

if (entry.getKey().equals(MediaFormat.KEY_AUDIO_SESSION_ID)) {
    int sessionId = 0;
    try {
        sessionId = (Integer)entry.getValue();
    }
    catch (Exception e) {
        throw new IllegalArgumentException("Wrong Session ID Parameter!");
    }
    keys[i] = "audio-hw-sync";
    values[i] = AudioSystem.getAudioHwSyncForSession(sessionId);
}

Durante esta consulta, AudioFlinger recupera el ID de HW_AV_SYNC del dispositivo de audio principal y lo asocia internamente con el audio ID de sesión:

audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
char *reply = dev->get_parameters(dev, AUDIO_PARAMETER_HW_AV_SYNC);
AudioParameter param = AudioParameter(String8(reply));
int hwAVSyncId;
param.getInt(String8(AUDIO_PARAMETER_HW_AV_SYNC), hwAVSyncId);

Si ya se creó una instancia de AudioTrack, el ID de HW_AV_SYNC es pasan a la transmisión de salida con el mismo ID de sesión de audio. Si no ha sido aún se creó, el ID de HW_AV_SYNC se pasa al flujo de salida durante Creación de AudioTrack. Esto se hace mediante el sistema de reproducción conversación:

mOutput->stream->common.set_parameters(&mOutput->stream->common, AUDIO_PARAMETER_STREAM_HW_AV_SYNC, hwAVSyncId);

El ID de HW_AV_SYNC, ya sea que corresponda a una transmisión de salida de audio o a una Tuner se pasa al componente OMX o Codec2 para que la El código OEM puede asociar el códec con la transmisión de salida de audio correspondiente o la transmisión del sintonizador.

Durante la configuración de componentes, el componente OMX o Codec2 debe devolver un controlador de banda lateral que se puede usar para asociar el códec con un compositor de hardware (HWC). Cuando la app asocia una superficie con MediaCodec, esta banda lateral se transmite a HWC a través de SurfaceFlinger, que configura la capa como una banda lateral.

err = native_window_set_sideband_stream(nativeWindow.get(), sidebandHandle);
if (err != OK) {
  ALOGE("native_window_set_sideband_stream(%p) failed! (err %d).", sidebandHandle, err);
  return err;
}

HWC es responsable de recibir los nuevos búferes de imagen del resultado del códec en el el momento adecuado, ya sea sincronizado con la transmisión de salida de audio asociada o el reloj de referencia del programa del sintonizador, componer los búferes con la longitud el contenido de otras capas y la visualización de la imagen resultante. Esto sucede independientemente del ciclo normal de preparar y establecer. Las llamadas de preparación y configuración suceden solo cuando cambian otras capas, o cuando las propiedades de la capa de banda lateral (como la posición o el tamaño).

OMX

Un componente de decodificador tunelizado debe admitir lo siguiente:

  • Configurando los OMX.google.android.index.configureVideoTunnelMode extendidos que usa la estructura ConfigureVideoTunnelModeParams para pasar en el ID de HW_AV_SYNC asociado con el dispositivo de salida de audio

  • Configurar el parámetro OMX_IndexConfigAndroidTunnelPeek que le indica al para procesar o no el primer fotograma decodificado, independientemente del si comenzó la reproducción de audio.

  • Cómo enviar el evento OMX_EventOnFirstTunnelFrameReady cuando se realiza el primer túnel se decodificó el fotograma y está listo para procesarse.

La implementación del AOSP configura el modo túnel en ACodec a través de OMXNodeInstance como se muestra en el siguiente fragmento de código:

OMX_INDEXTYPE index;
OMX_STRING name = const_cast<OMX_STRING>(
        "OMX.google.android.index.configureVideoTunnelMode");

OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);

ConfigureVideoTunnelModeParams tunnelParams;
InitOMXParams(&tunnelParams);
tunnelParams.nPortIndex = portIndex;
tunnelParams.bTunneled = tunneled;
tunnelParams.nAudioHwSync = audioHwSync;
err = OMX_SetParameter(mHandle, index, &tunnelParams);
err = OMX_GetParameter(mHandle, index, &tunnelParams);
sidebandHandle = (native_handle_t*)tunnelParams.pSidebandWindow;

Si el componente admite esta configuración, debería asignar una banda lateral. controlador a este códec y pasarlo de vuelta a través del miembro pSidebandWindow para que el HWC pueda identificar el códec asociado. Si el componente no admite esta configuración, debe establecer bTunneled en OMX_FALSE.

Códec 2

En Android 11 o versiones posteriores, Codec2 admite la reproducción en túnel. El decodificador debe admitir lo siguiente:

  • Configurar C2PortTunneledModeTuning, que configura el modo túnel y pasa el objeto HW_AV_SYNC recuperado del dispositivo de salida de audio la configuración del sintonizador.

  • Consulta C2_PARAMKEY_OUTPUT_TUNNEL_HANDLE para asignar y recuperar el para HWC.

  • Controla C2_PARAMKEY_TUNNEL_HOLD_RENDER cuando se adjunta a un C2Work, que Indica al códec que se decodifique e indique la finalización del trabajo, pero no que la renderice. el búfer de salida hasta que 1) se le indique al códec que lo renderice o 2) comience la reproducción de audio.

  • Controla C2_PARAMKEY_TUNNEL_START_RENDER, que le indica al códec lo siguiente: procesar inmediatamente el marco que se marcó con C2_PARAMKEY_TUNNEL_HOLD_RENDER, incluso si no comenzó la reproducción de audio.

  • Deja debug.stagefright.ccodec_delayed_params sin configurar (recomendado). Si debes configurarlo en false.

La implementación del AOSP configura el modo túnel en CCodec a través de C2PortTunnelModeTuning, como se muestra en el siguiente fragmento de código:

if (msg->findInt32("audio-hw-sync", &tunneledPlayback->m.syncId[0])) {
    tunneledPlayback->m.syncType =
            C2PortTunneledModeTuning::Struct::sync_type_t::AUDIO_HW_SYNC;
} else if (msg->findInt32("hw-av-sync-id", &tunneledPlayback->m.syncId[0])) {
    tunneledPlayback->m.syncType =
            C2PortTunneledModeTuning::Struct::sync_type_t::HW_AV_SYNC;
} else {
    tunneledPlayback->m.syncType =
            C2PortTunneledModeTuning::Struct::sync_type_t::REALTIME;
    tunneledPlayback->setFlexCount(0);
}
c2_status_t c2err = comp->config({ tunneledPlayback.get() }, C2_MAY_BLOCK,
        failures);
std::vector<std::unique_ptr<C2Param>> params;
c2err = comp->query({}, {C2PortTunnelHandleTuning::output::PARAM_TYPE},
        C2_DONT_BLOCK, &params);
if (c2err == C2_OK && params.size() == 1u) {
    C2PortTunnelHandleTuning::output *videoTunnelSideband =
            C2PortTunnelHandleTuning::output::From(params[0].get());
    return OK;
}

Si el componente admite esta configuración, debería asignar una banda lateral. controlador a este códec y pasarlo de vuelta a través de C2PortTunnelHandlingTuning para que el HWC pueda identificar el códec asociado.

HAL de audio

Para la reproducción de video a pedido, la HAL de audio recibe la presentación de audio Marcas de tiempo intercaladas con los datos de audio en formato big-endian dentro de un encabezado encontrado Al comienzo de cada bloque de datos de audio, la app escribe lo siguiente:

struct TunnelModeSyncHeader {
  // The 32-bit data to identify the sync header (0x55550002)
  int32 syncWord;
  // The size of the audio data following the sync header before the next sync
  // header might be found.
  int32 sizeInBytes;
  // The presentation timestamp of the first audio sample following the sync
  // header.
  int64 presentationTimestamp;
  // The number of bytes to skip after the beginning of the sync header to find the
  // first audio sample (20 bytes for compressed audio, or larger for PCM, aligned
  // to the channel count and sample size).
  int32 offset;
}

Para que HWC renderice fotogramas de video sincronizados con los fotogramas de audio correspondientes, La HAL de audio debe analizar el encabezado de sincronización y usar la marca de tiempo de presentación para volver a sincronizar el reloj de reproducción con la renderización de audio. Para volver a sincronizar cuando se está reproduciendo audio comprimido, es posible que la HAL de audio deba analizar los metadatos dentro de los datos de audio comprimidos para determinar la duración de la reproducción.

Pausar asistencia

Android 5 y las versiones anteriores no admiten la pausa. Puedes pausar las redes solo reproducción por falta de A/V, pero si el búfer interno para el video es grande (por ejemplo, hay un segundo de datos en el componente OMX), hace una pausa no parezcan receptivos.

En Android 5.1 y versiones posteriores, AudioFlinger admite pausar y reanudar contenido de forma directa salidas de audio (túneles). Si la HAL implementa las funciones de pausa y reanudación, realiza un seguimiento de la pausa. y la reanudación se reenvía a la HAL.

La secuencia de llamadas de pausa, vaciado y reanudación se respeta mediante la ejecución de las llamadas de HAL en el subproceso de reproducción (igual que la descarga).

Sugerencias de implementación

HAL de audio

En Android 11, el ID de sincronización HW de PCR o STC se puede usar para la sincronización de A/V, por lo que se admite la transmisión de solo video.

En el caso de Android 10 o versiones anteriores, los dispositivos compatibles con la reproducción de video en túnel deben tener al menos un perfil de transmisión de salida de audio con FLAG_HW_AV_SYNC y Las marcas AUDIO_OUTPUT_FLAG_DIRECT en su archivo audio_policy.conf. Estas marcas se usan para configurar el reloj del sistema desde el reloj de audio.

OMX

Los fabricantes de dispositivos deben tener un componente OMX independiente para el video en túnel reproducción (los fabricantes pueden tener componentes OMX adicionales para otros tipos de la reproducción de audio y video, como la reproducción segura). El componente en túnel debe:

  • Especifica 0 búferes (nBufferCountMin, nBufferCountActual) en su salida puerto de red.

  • Implementa la extensión OMX.google.android.index.prepareForAdaptivePlayback setParameter.

  • Especifica sus capacidades en el archivo media_codecs.xml y declara la reproducción en túnel. También debería aclarar cualquier limitación del fotograma el tamaño, la alineación o la tasa de bits. A continuación, se muestra un ejemplo:

    <MediaCodec name="OMX.OEM_NAME.VIDEO.DECODER.AVC.tunneled"
    type="video/avc" >
        <Feature name="adaptive-playback" />
        <Feature name="tunneled-playback" required=”true” />
        <Limit name="size" min="32x32" max="3840x2160" />
        <Limit name="alignment" value="2x2" />
        <Limit name="bitrate" range="1-20000000" />
            ...
    </MediaCodec>
    

Si se usa el mismo componente OMX para admitir la decodificación tunelizada y no tunelizada, la función de reproducción en túnel no debe ser necesaria. Tanto las redes mediante túneles de codificadores no túneles tienen las mismas limitaciones de capacidad. Un ejemplo es como se muestra a continuación:

<MediaCodec name="OMX._OEM\_NAME_.VIDEO.DECODER.AVC" type="video/avc" >
    <Feature name="adaptive-playback" />
    <Feature name="tunneled-playback" />
    <Limit name="size" min="32x32" max="3840x2160" />
    <Limit name="alignment" value="2x2" />
    <Limit name="bitrate" range="1-20000000" />
        ...
</MediaCodec>

Hardware Composer (HWC)

Cuando hay una capa tunelizada (una capa con HWC_SIDEBAND compositionType) activada una pantalla, el sidebandStream de la capa es el controlador de banda lateral asignado por el Componente de video OMX.

El HWC sincroniza los fotogramas de video decodificados (del componente OMX tunelizado) con la pista de audio asociada (con el ID de audio-hw-sync). Cuando se agrega un nuevo fotograma se vuelve actual, el HWC lo compone con el contenido actual de todas las capas recibido durante la última llamada de preparación o establecimiento y muestra la imagen resultante. Las llamadas de preparación o establecimiento solo ocurren cuando cambian otras capas, o cuando propiedades de la capa de banda lateral (como la posición o el tamaño).

La siguiente figura representa el HWC que funciona con el hardware (o kernel o controlador) para combinar fotogramas (7b) con la última composición (7a) para que se muestre en el momento correcto, según el audio (7c).

HWC que combina fotogramas de video basados en audio

Figura 2: Sincronizador de hardware HWC (o kernel o controlador)