Transmisiones en tiempo real

Marcas de tiempo en tiempo real

Los gráficos de la calculadora de MediaPipe se usan a menudo para procesar transmisiones de video o audio. o marcos para aplicaciones interactivas. El framework de MediaPipe solo requiere que a paquetes sucesivos y marcas de tiempo que aumentan monótonamente. De convención, las calculadoras y los gráficos en tiempo real usan el tiempo de registro o el la hora de presentación de cada fotograma como su marca de tiempo, donde cada marca de tiempo indica los microsegundos desde Jan/1/1970:00:00:00. Esto permite que los paquetes de varios fuentes de datos se procesen en una secuencia coherente a nivel global.

Programación en tiempo real

Por lo general, cada calculadora se ejecuta en cuanto todos sus paquetes de entrada para un y marca de tiempo estén disponibles. Por lo general, esto sucede cuando la calculadora terminó de procesar el fotograma anterior, y cada una de las calculadoras produjo cuando sus entradas terminan de procesar el fotograma actual. El programador de MediaPipe Invoca cada calculadora en cuanto se cumplen estas condiciones. Consulta Sincronización para obtener más detalles.

Límites de marcas de tiempo

Cuando una calculadora no produce ningún paquete de salida para una marca de tiempo determinada, puede mostrar un “límite de marca de tiempo” lo que indica que no se enviará ningún paquete producido para esa marca de tiempo. Esta indicación es necesaria para permitir se ejecuten en esa marca de tiempo, aunque no haya llegado ningún paquete para ciertas transmisiones para esa marca de tiempo. Esto es especialmente importante para las operaciones en tiempo real gráficos en aplicaciones interactivas, donde es crucial que cada calculadora comiencen a procesarse lo antes posible.

Considera un gráfico como el siguiente:

node {
   calculator: "A"
   input_stream: "alpha_in"
   output_stream: "alpha"
}
node {
   calculator: "B"
   input_stream: "alpha"
   input_stream: "foo"
   output_stream: "beta"
}

Supongamos que, en la marca de tiempo T, el nodo A no envía un paquete en su transmisión de salida. alpha El nodo B recibe un paquete en foo en la marca de tiempo T y espera un paquete en alpha en la marca de tiempo T. Si A no envía a B un límite de marca de tiempo actualización de alpha. B seguirá esperando la llegada de un paquete en alpha. Mientras tanto, la cola de paquetes de foo acumulará paquetes en T, T+1 y y así sucesivamente.

Para la salida de un paquete en una transmisión, una calculadora usa las funciones de API CalculatorContext::Outputs y OutputStream::Add. Como alternativa, para obtener una marca de tiempo vinculada a una transmisión, una calculadora puede usar las funciones de API CalculatorContext::Outputs y CalculatorContext::SetNextTimestampBound. El el límite especificado es la marca de tiempo más baja permitida para el siguiente paquete de la flujo de salida especificado. Cuando no se muestra ningún paquete, por lo general, la calculadora hacer algo como:

cc->Outputs().Tag("output_frame").SetNextTimestampBound(
  cc->InputTimestamp().NextAllowedInStream());

La función Timestamp::NextAllowedInStream muestra la marca de tiempo sucesiva. Por ejemplo, Timestamp(1).NextAllowedInStream() == Timestamp(2)

Propaga límites de marca de tiempo

Las calculadoras que se usarán en gráficos en tiempo real deben definir el resultado. basados en los límites de marca de tiempo de entrada para permitir programar calculadoras de forma oportuna. Un patrón común es que las calculadoras los paquetes de salida con las mismas marcas de tiempo que sus paquetes de entrada. En este caso, enviar un paquete por cada llamada a Calculator::Process es suficiente para definir los límites de marca de tiempo de salida.

Sin embargo, no es necesario que las calculadoras sigan este patrón común para los resultados. marcas de tiempo, solo deben elegir valores de salida monótonamente y marcas de tiempo. Como resultado, ciertas calculadoras deben calcular los límites de marca de tiempo. de forma explícita. MediaPipe proporciona varias herramientas para calcular las marcas de tiempo para cada calculadora.

1. SetNextTimestampBound() se puede usar para especificar el límite de marca de tiempo, t + 1, para una transmisión de salida.

cc->Outputs.Tag("OUT").SetNextTimestampBound(t.NextAllowedInStream());

Como alternativa, se puede producir un paquete vacío con la marca de tiempo t para especificar el vinculado a la marca de tiempo t + 1.

cc->Outputs.Tag("OUT").Add(Packet(), t);

El límite de marca de tiempo de una transmisión de entrada se indica mediante el paquete o la fuente paquete en la transmisión de entrada.

Timestamp bound = cc->Inputs().Tag("IN").Value().Timestamp();

2. TimestampOffset() puede especificarse para copiar automáticamente el marca de tiempo vinculada de transmisiones de entrada a transmisiones de salida.

cc->SetTimestampOffset(0);

Este parámetro de configuración tiene la ventaja de propagar automáticamente los límites de la marca de tiempo incluso cuando solo llegan los límites de la marca de tiempo y no se invoca a Calculadora::Process.

3. ProcessTimestampBounds() puede especificarse para invocar Calculator::Process para cada nueva “marca de tiempo liquidada”, en la que el valor marca de tiempo es la nueva marca de tiempo más alta debajo de los límites de la marca de tiempo actual. Sin ProcessTimestampBounds(), Calculator::Process solo se invoca con uno o más paquetes entrantes.

cc->SetProcessTimestampBounds(true);

Este parámetro de configuración permite que una calculadora realice su propio cálculo de límites de marca de tiempo. y propagación, incluso cuando solo se actualizan las marcas de tiempo de entrada. Se puede usar para replicar el efecto de TimestampOffset(), pero también se puede usar para calcular un límite de marca de tiempo que tenga en cuenta factores adicionales.

Por ejemplo, para replicar SetTimestampOffset(0), una calculadora podría haz lo siguiente:

absl::Status Open(CalculatorContext* cc) {
  cc->SetProcessTimestampBounds(true);
}

absl::Status Process(CalculatorContext* cc) {
  cc->Outputs.Tag("OUT").SetNextTimestampBound(
      cc->InputTimestamp().NextAllowedInStream());
}

Programación de Calculadora::Abrir y Calculadora::Cerrar

Se invoca Calculator::Open cuando todos los paquetes de entrada adicionales necesarios producidos. Los paquetes de entrada adicionales se pueden proporcionar mediante la aplicación contenedora o "calculadoras de paquetes adicionales" dentro del gráfico. Los paquetes adicionales se pueden especificar desde fuera del gráfico con el CalculatorGraph::Initialize de la API y CalculatorGraph::StartRun Los paquetes laterales pueden especificarse con calculadoras dentro el gráfico con CalculatorGraphConfig::OutputSidePackets y OutputSidePacket::Set

Calculator::Close se invoca cuando todas las transmisiones de entrada se vuelven Done se está cerrando o alcanzando el límite de marca de tiempo Timestamp::Done.

Nota: Si el gráfico finaliza toda la ejecución pendiente de la calculadora y se convierte en Done, antes de que algunas transmisiones pasen a ser Done, MediaPipe invocará la llamadas restantes a Calculator::Close, de modo que cada calculadora pueda producir su los resultados finales.

El uso de TimestampOffset tiene algunas implicaciones para Calculator::Close. R que especifique SetTimestampOffset(0) indicará de por qué todos las transmisiones de salida alcanzaron el Timestamp::Done cuando todas las transmisiones de entrada llegaron a Timestamp::Done, por lo que no es posible obtener más resultados. Esto evita que esa calculadora emita paquetes durante Calculator::Close Si una calculadora debe producir un paquete de resumen durante Calculator::Close y Calculator::Process deben especificar límites de marca de tiempo, como que al menos una marca de tiempo (como Timestamp::Max) permanezca disponible durante Calculator::Close Esto significa que una calculadora normalmente no puede basarse en SetTimestampOffset(0) y, en su lugar, debe especificar explícitamente los límites de marca de tiempo usando SetNextTimestampBounds().