Stream in tempo reale

Timestamp in tempo reale

I grafici del calcolatore MediaPipe vengono spesso utilizzati per elaborare flussi di video o audio per applicazioni interattive. Il framework MediaPipe richiede solo che e pacchetti successivi possono essere assegnati con timestamp con incrementi monotonici. Di tradizionale, le calcolatrici e i grafici in tempo reale usano il tempo di registrazione o di presentazione di ogni frame come timestamp, con ogni timestamp che indica microsecondi da Jan/1/1970:00:00:00. Ciò consente ai pacchetti di da elaborare in una sequenza coerente a livello globale.

Programmazione in tempo reale

Normalmente, ogni Calcolatrice viene eseguita non appena tutti i suoi pacchetti di input il timestamp diventa disponibile. Solitamente, questo accade quando la calcolatrice ha terminato l'elaborazione del frame precedente e ciascuno dei calcolatori che produce i suoi input hanno terminato l'elaborazione del frame corrente. Scheduler di MediaPipe richiama ogni calcolatore non appena queste condizioni sono soddisfatte. Consulta Sincronizzazione per ulteriori dettagli.

Limiti di timestamp

Quando una calcolatrice non produce pacchetti di output per un determinato timestamp, può invece generare un "timestamp bound" che indica che nessun pacchetto sarà generate per quel timestamp. Questa indicazione è necessaria per consentire il downstream di calcolo da eseguire in quel timestamp, anche se non è arrivato nessun pacchetto determinati flussi di dati per quel timestamp. Ciò è particolarmente importante per i report in applicazioni interattive, per cui è fondamentale che ogni calcolatrice iniziare l'elaborazione il prima possibile.

Considera un grafico come il seguente:

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

Supponiamo: al timestamp T, il nodo A non invia un pacchetto nel flusso di output alpha. Il nodo B riceve un pacchetto in foo al timestamp T ed è in attesa di un pacchetto in alpha al timestamp T. Se A non invia a B un timestamp vincolato aggiornamento per alpha, B continuerà ad attendere l'arrivo di un pacchetto in alpha. Nel frattempo, la coda di pacchetti di foo accumulerà pacchetti alle ore T, T+1 e così via.

Per restituire un pacchetto in un flusso, un calcolatore usa le funzioni API CalculatorContext::Outputs e OutputStream::Add. Per eseguire invece un output con timestamp associato a un flusso, un calcolatore può usare le funzioni API CalculatorContext::Outputs e CalculatorContext::SetNextTimestampBound. La specificato è il timestamp più basso consentito per il pacchetto successivo flusso di output specificato. Quando non viene restituito alcun pacchetto, solitamente una calcolatrice fai ad esempio:

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

La funzione Timestamp::NextAllowedInStream restituisce il timestamp successivo. Ad esempio, Timestamp(1).NextAllowedInStream() == Timestamp(2).

Propagazione dei limiti del timestamp

I calcolatori che verranno utilizzati nei grafici in tempo reale devono definire limiti di timestamp basati sui limiti del timestamp di input per consentire il downstream calcolatrici da pianificare tempestivamente. Uno schema comune è che le calcolatrici di output con gli stessi timestamp dei pacchetti di input. In questo caso, è sufficiente inviare un pacchetto per ogni chiamata a Calculator::Process per definire i limiti del timestamp di output.

Tuttavia, i calcolatori non sono tenuti a seguire questo schema comune per l'output i timestamp, devono solo scegliere l'aumento monotonico dell'output i timestamp. Di conseguenza, alcuni calcolatori devono calcolare i limiti dei timestamp in modo esplicito. MediaPipe offre diversi strumenti per calcolare il timestamp appropriato per ogni calcolatore.

1. È possibile utilizzare SetNextTimestampBound() per specificare il limite di timestamp, t + 1, per un flusso di output.

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

In alternativa, può essere generato un pacchetto vuoto con timestamp t per specificare con timestamp t + 1.

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

Il timestamp associato a un flusso di input è indicato dal pacchetto o dal pacchetto sul flusso di input.

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

2. TimestampOffset() può essere specificato in modo da copiare automaticamente il valore timestamp associato dai flussi di input ai flussi di output.

cc->SetTimestampOffset(0);

Questa impostazione ha il vantaggio di propagare automaticamente i limiti dei timestamp. anche quando arrivano solo i limiti di timestamp e Calcolatrice::Process non viene richiamata.

3. ProcessTimestampBounds() può essere specificato per richiamare Calculator::Process per ogni nuovo "timestamp saldato", dove il valore timestamp" è il nuovo timestamp più alto sotto i limiti del timestamp corrente. Senza ProcessTimestampBounds(), Calculator::Process viene richiamato solo con uno o più pacchetti in arrivo.

cc->SetProcessTimestampBounds(true);

Questa impostazione consente a una calcolatrice di eseguire il calcolo dei propri limiti di timestamp e la propagazione, anche se vengono aggiornati solo i timestamp di input. Può essere utilizzato per replicare l'effetto di TimestampOffset(), ma può essere utilizzato anche per calcolare un limite di timestamp che prende in considerazione fattori aggiuntivi.

Ad esempio, per replicare SetTimestampOffset(0), una calcolatrice potrebbe segui questi passaggi:

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

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

Programmazione della Calcolatrice::Apri e Calcolatrice::Chiudi

Calculator::Open viene richiamato quando tutti i pacchetti collaterali di input sono stati prodotto. I pacchetti collaterali di input possono essere forniti dall'applicazione che lo contiene o "calcolatori a pacchetto laterale" all'interno del grafico. I pacchetti laterali possono essere specificati da al di fuori del grafico utilizzando i valori CalculatorGraph::Initialize e CalculatorGraph::StartRun. I pacchetti laterali possono essere specificati dai calcolatori all'interno di il grafico utilizzando CalculatorGraphConfig::OutputSidePackets e OutputSidePacket::Set.

Calcolatrice::Chiudi viene richiamato quando tutti i flussi di input sono diventati Done la chiusura o il raggiungimento del limite di timestamp Timestamp::Done.

Nota: se il grafico termina tutte le esecuzioni in attesa della calcolatrice e diventa Done, prima che alcuni flussi diventino Done, MediaPipe richiama la chiamate rimanenti a Calculator::Close, in modo che ogni calcolatore possa produrre output finali.

L'uso di TimestampOffset ha alcune implicazioni per Calculator::Close. R calcolatrice che specifica SetTimestampOffset(0), in base alla progettazione segnalerà che tutti i suoi flussi di output hanno raggiunto Timestamp::Done quando tutti i suoi flussi di input hanno raggiunto Timestamp::Done e pertanto non sono possibili ulteriori output. In questo modo un calcolatore di questo tipo non può emettere pacchetti durante Calculator::Close. Se un calcolatore deve produrre un pacchetto di riepilogo durante Calculator::Close, Calculator::Process deve specificare limiti di timestamp come che almeno un timestamp (ad esempio Timestamp::Max) rimanga disponibile durante Calculator::Close. Ciò significa che un calcolatore di questo tipo non può fare affidamento SetTimestampOffset(0) e deve invece specificare in modo esplicito i limiti del timestamp utilizzando SetNextTimestampBounds().