Diffusions en temps réel

Codes temporels en temps réel

Les graphiques des calculatrices MediaPipe sont souvent utilisés pour traiter des flux d'images vidéo ou audio pour des applications interactives. Le framework MediaPipe ne nécessite que l'affectation de paquets successifs à des horodatages monotones croissants. Par convention, les calculateurs et les graphiques en temps réel utilisent la durée d'enregistrement ou de présentation de chaque image comme code temporel, chaque horodatage indiquant les microsecondes écoulées depuis Jan/1/1970:00:00:00. Cela permet de traiter les paquets provenant de différentes sources dans une séquence cohérente au niveau mondial.

Planification en temps réel

Normalement, chaque calculatrice s'exécute dès que tous ses paquets d'entrée pour un horodatage donné sont disponibles. Normalement, cela se produit lorsque le calculateur a fini de traiter l'image précédente, et que chacun des calculateurs qui produisent ses entrées a fini de traiter l'image actuelle. Le programmeur MediaPipe appelle chaque calculateur dès que ces conditions sont remplies. Pour plus d'informations, consultez la section Synchronisation.

Limites d'horodatage

Lorsqu'un calculateur ne génère aucun paquet de sortie pour un horodatage donné, il peut à la place générer une "limite d'horodatage" indiquant qu'aucun paquet ne sera produit pour cet horodatage. Cette indication est nécessaire pour permettre l'exécution des calculateurs en aval à cet horodatage, même si aucun paquet n'est arrivé pour certains flux pour ce code temporel. Cela est particulièrement important pour les graphiques en temps réel dans les applications interactives, où il est essentiel que chaque calculatrice commence le traitement dès que possible.

Examinez un graphique comme celui-ci:

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

Supposons qu'au code temporel T, le nœud A n'envoie pas de paquet dans son flux de sortie alpha. Le nœud B reçoit un paquet dans foo au code temporel T et attend un paquet dans alpha au code temporel T. Si A n'envoie pas à B de mise à jour liée à l'horodatage pour alpha, B continue d'attendre l'arrivée d'un paquet dans alpha. Pendant ce temps, la file d'attente de paquets foo accumule des paquets à T, T+1, etc.

Pour générer un paquet dans un flux, un calculateur utilise les fonctions API CalculatorContext::Outputs et OutputStream::Add. Pour générer à la place un horodatage lié à un flux, un calculateur peut utiliser les fonctions d'API CalculatorContext::Outputs et CalculatorContext::SetNextTimestampBound. La limite spécifiée est le code temporel le plus bas autorisé pour le paquet suivant dans le flux de sortie spécifié. Lorsqu'aucun paquet n'est généré, un calculateur effectue généralement une opération comme:

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

La fonction Timestamp::NextAllowedInStream renvoie l'horodatage successif. Exemple :Timestamp(1).NextAllowedInStream() == Timestamp(2)

Propagation des limites d'horodatage

Les calculateurs qui seront utilisés dans les graphiques en temps réel doivent définir des limites d'horodatage de sortie basées sur les limites d'horodatage d'entrée afin de permettre une planification rapide des calculateurs en aval. Les calculateurs génèrent souvent des paquets avec les mêmes horodatages que leurs paquets d'entrée. Dans ce cas, il suffit de générer un paquet à chaque appel de Calculator::Process pour définir des limites d'horodatage de sortie.

Toutefois, les calculateurs ne sont pas tenus de suivre ce modèle courant pour les horodatages de sortie. Ils ne sont requis que de choisir des horodatages de sortie augmentant de manière monotone. Par conséquent, certains calculateurs doivent calculer explicitement les limites d'horodatage. MediaPipe fournit plusieurs outils permettant de calculer la limite d'horodatage appropriée pour chaque calculateur.

1. Vous pouvez utiliser SetNextTimestampBound() pour spécifier la limite d'horodatage, t + 1, pour un flux de sortie.

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

Vous pouvez également générer un paquet vide avec le code temporel t pour spécifier l'élément t + 1 lié à l'horodatage.

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

La limite d'horodatage d'un flux d'entrée est indiquée par le paquet ou le paquet vide dans le flux d'entrée.

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

2. TimestampOffset() peut être spécifié pour copier automatiquement l'horodatage lié aux flux d'entrée vers les flux de sortie.

cc->SetTimestampOffset(0);

Ce paramètre permet de propager automatiquement les limites d'horodatage, même lorsque seules les limites d'horodatage arrivent et que Calculator::Process n'est pas appelé.

3. ProcessTimestampBounds() peut être spécifié afin d'appeler Calculator::Process pour chaque nouvel "horodatage défini", "settledtimestamp" correspondant au nouvel horodatage le plus élevé en dessous des limites d'horodatage actuelles. Sans ProcessTimestampBounds(), Calculator::Process n'est appelé qu'avec un ou plusieurs paquets entrants.

cc->SetProcessTimestampBounds(true);

Ce paramètre permet à un calculateur d'effectuer ses propres calculs et propagation des limites d'horodatage, même lorsque seuls les horodatages d'entrée sont mis à jour. Il permet de répliquer l'effet de TimestampOffset(), mais également de calculer une limite d'horodatage qui tient compte de facteurs supplémentaires.

Par exemple, pour répliquer SetTimestampOffset(0), un simulateur peut effectuer les opérations suivantes:

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

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

Planification de la calculatrice::Ouvrir et Calculatrice::Fermer

Calculator::Open est appelé lorsque tous les paquets latéraux d'entrée requis ont été produits. Les paquets latéraux d'entrée peuvent être fournis par l'application englobante ou par des "calculateurs de paquets latéraux" à l'intérieur du graphe. Les paquets latéraux peuvent être spécifiés depuis l'extérieur du graphique à l'aide des paramètres CalculatorGraph::Initialize et CalculatorGraph::StartRun de l'API. Les paquets secondaires peuvent être spécifiés par des calculateurs dans le graphe à l'aide de CalculatorGraphConfig::OutputSidePackets et OutputSidePacket::Set.

Calculatrice::Close est appelé lorsque tous les flux d'entrée sont devenus Done parce qu'ils sont fermés ou lorsqu'ils ont atteint la valeur Timestamp::Done liée à l'horodatage.

Remarque:Si le graphe termine toute exécution en attente de la calculatrice et passe à Done, avant que certains flux ne passent à Done, MediaPipe appelle les appels restants à Calculator::Close, afin que chaque calculateur puisse produire ses résultats finaux.

L'utilisation de TimestampOffset a des conséquences pour Calculator::Close. Par nature, une calculatrice spécifiant SetTimestampOffset(0) signale que tous ses flux de sortie ont atteint la valeur Timestamp::Done lorsque tous ses flux d'entrée ont atteint la valeur Timestamp::Done. Par conséquent, aucune autre sortie n'est possible. Cela empêche un tel calculateur d'émettre des paquets pendant Calculator::Close. Si un simulateur doit produire un paquet récapitulatif pendant Calculator::Close, Calculator::Process doit spécifier des limites d'horodatage de sorte qu'au moins un horodatage (tel que Timestamp::Max) reste disponible pendant Calculator::Close. Cela signifie qu'un tel calculateur ne peut normalement pas s'appuyer sur SetTimestampOffset(0) et doit spécifier explicitement les limites d'horodatage à l'aide de SetNextTimestampBounds().