2013-01-21 13 views
5

Questo è un bel problema, e non un "dimmi come funziona il codice", ma piuttosto una domanda "come gestisco logicamente questa situazione".Come posso gestire l'errore di arrotondamento progressivo TimeSpan di C# .NET durante la registrazione di video frame per frame?

Ho, in breve, video + audio provenienti da una telecamera IP tramite RTSP.

Il video e l'audio vengono decodificati e registrati fotogramma per fotogramma in un singolo contenitore mp4, tramite thread separati (mostrati di seguito).

Il problema è che il video e l'audio diventano progressivamente più sincronizzati nel tempo, a causa della mancanza di precisione con l'ora di fine TimeSpan e le ore di inizio per ciascun fotogramma video.

Deve essere una durata di 1/framerate = 0.0333667000333667 per ciascun fotogramma video, ma viene utilizzato (anche con il metodo FromTicks()), ora di inizio = 0.0 e ora di fine 0.0333667 per il primo fotogramma.

Sono in grado di regolare il valore del frame rate del decoder video da 29.97 (viene estratto dalle impostazioni della telecamera dichiarate framerate), risultando in un video che precede l'audio o in ritardo rispetto all'audio - questo è semplicemente rendendo ciascun video mediaBuffer .StartTime e mediaBuffer.EndTime o troppo presto o troppo tardi, rispetto all'audio.

Nel corso del tempo, il troncamento decimale minuscola finisce per fare il video e l'audio fuori sincrono - più lunga è la registrazione, il più fuori sincrono le due tracce ottengono.

Non capisco davvero perché ciò stia accadendo, perché l'errore di arrotondamento non dovrebbe essere logicamente rilevante.

Anche se avessi solo una precisione di 1 secondo, avrei solo scritto un fotogramma video al secondo, e il posizionamento nella timeline sarebbe approssimativamente dove dovrebbe essere + - 1 secondo, e questo dovrebbe rendere ogni progressivo inquadra lo stesso + - 1 secondo dove dovrebbe essere, non aggiungendo progressivamente più dislocamento. Sto immaginando che questo sembrerebbe per ogni frame:

[< -------- -1 secondo --------> tempo di frame esatto previsto < ------- - + 1s -------->] ------------------------------------ ---------------- tempo frame registrato --------

Mi manca qualcosa qui?

Non sto facendo "nuovo inizio orario fotogramma = ultimo tempo di fine fotogramma, nuovo tempo di fine fotogramma = nuovo orario di inizio fotogramma + 1/framerate" - In realtà sto facendo "nuovo orario di inizio fotogramma = indice fotogramma - 1/framerate, nuovo frame end time = frame index/framerate ".

Cioè, sto calcolando l'inizio e la fine del frame in base al tempo previsto che dovrebbero avere (frame time = frame position/framerate).

Quello che il mio codice sta facendo è questo:

tempo tempo previsto ---------- ---------- tempo previsto orario previsto arco di tempo cornice di tempo

Capisco matematicamente il problema, ma non capisco perché il troncamento decimale stia provando un tale problema o conosca logicamente quale sia la soluzione migliore per risolverlo.

Se implemento qualcosa che dice "ogni x frame, usa" (1/framerate) + un po 'di importo "per recuperare tutto il tempo mancante, sarà possibile che i frame corrispondano dove dovrebbero essere, o solo risultato in video disordinato?

public void AudioDecoderThreadProc() 
    { 
     TimeSpan current = TimeSpan.FromSeconds(0.0); 

     while (IsRunning) 
     { 
      RTPFrame nextFrame = jitter.FindCompleteFrame(); 

      if (nextFrame == null) 
      { 
       System.Threading.Thread.Sleep(20); 
       continue; 
      } 

      while (nextFrame.PacketCount > 0 && IsRunning) 
      { 
       RTPPacket p = nextFrame.GetNextPacket(); 

       if (sub.ti.MediaCapability.Codec == Codec.G711A || sub.ti.MediaCapability.Codec == Codec.G711U) 
       { 
        MediaBuffer<byte> mediaBuffer = new MediaBuffer<byte>(p.DataPointer, 0, (int)p.DataSize); 
        mediaBuffer.StartTime = current; 
        mediaBuffer.EndTime = current.Add(TimeSpan.FromSeconds((p.DataSize)/(double)audioDecoder.SampleRate)); 

        current = mediaBuffer.EndTime; 

        if (SaveToFile == true) 
        { 
         WriteMp4Data(mediaBuffer); 
        } 
       } 
      } 
     } 
    } 

    public void VideoDecoderThreadProc() 
    { 
     byte[] totalFrame = null; 

     TimeSpan current = TimeSpan.FromSeconds(0.0); 
     TimeSpan videoFrame = TimeSpan.FromTicks(3336670); 
     long frameIndex = 1; 

     while (IsRunning) 
     { 
      if (completedFrames.Count > 50) 
      { 
       System.Threading.Thread.Sleep(20); 
       continue; 
      } 

      RTPFrame nextFrame = jitter.FindCompleteFrame(); 

      if (nextFrame == null) 
      { 
       System.Threading.Thread.Sleep(20); 
       continue; 
      } 

      if (nextFrame.HasSequenceGaps == true) 
      { 
       continue; 
      } 

      totalFrame = new byte[nextFrame.TotalPayloadSize * 2]; 
      int offset = 0; 

      while (nextFrame.PacketCount > 0) 
      { 
       byte[] fragFrame = nextFrame.GetAssembledFrame(); 

       if (fragFrame != null) 
       { 
        fragFrame.CopyTo(totalFrame, offset); 
        offset += fragFrame.Length; 
       } 
      } 

      MediaBuffer<byte> mediaBuffer = new MediaBuffer<byte>(
       totalFrame, 
       0, 
       offset, 
       TimeSpan.FromTicks(Convert.ToInt64((frameIndex - 1)/mp4TrackInfo.Video.Framerate * 10000000)), 
       TimeSpan.FromTicks(Convert.ToInt64(frameIndex/mp4TrackInfo.Video.Framerate * 10000000))); 

      if (SaveToFile == true) 
      { 
       WriteMp4Data(mediaBuffer); 
      } 

      lock (completedFrames) 
      { 
       completedFrames.Add(mediaBuffer); 
      } 

      frameIndex++; 
     } 
    } 
+0

La risoluzione di TimeSpan è di 100 nanosecondi. Quindi, se dovesse essere disattivato in modo coerente, non si potrebbe essere spento dopo un'ora di oltre 100 nsec * 29,97 * 3600 = 11 msec. Non puoi vederlo. Dovrai continuare a cercare. Sfidare il frame rate della telecamera reale. E fai attenzione a un bit rate variabile per l'audio, piuttosto comune. –

+0

Beh, è ​​sicuramente il framerate che è sbagliato, ma come può essere risolto? Guesswork? Posso avvicinarlo, molto più lentamente, o molto più veloce di quanto dovrebbe essere. Ma se non ho un modo per calcolare effettivamente quando è il momento giusto per scrivere quel frame. Come fa qualcuno a fare anche correttamente la sincronizzazione A/V? – user1518816

risposta

1

ci sono un paio di cose che si dovrebbe guardare fuori per:

  1. improprio manuale del telaio marcatura temporale. Generalmente è una cattiva idea calcolare a mano le durate dei fotogrammi invece di lasciare che il driver/scheda/qualunque sia il tempo di frame. Stampare una cornice da solo porta quasi sempre alla deriva a causa di bitrate variabili, tempi interni del computer, ecc.

  2. Deriva di precisione. Mi sono imbattuto in deriva quando si tratta di timestamp di frame che sono in unità di millisecondi, ma il timestamp della mia sorgente era in unità di nanosecondi. Questo mi ha richiesto di fare un doppio su un lungo.

    Ad esempio, ottengo un tempo di media da directshow che è in unità di nanosecondi, tuttavia i miei calcoli interni richiedono unità di millisecondi. Ciò significa che ho bisogno di convertire tra ns e ms. Per me, questo è il punto in cui la perdita di precisione è stata. La mia soluzione a questo è stato che è necessario tenere traccia di qualsiasi perdita di precisione.

    Quello che ho fatto in passato è che ho un contatore "timingFraction" in esecuzione. Fondamentalmente ogni volta che faccio una divisione, questo mi dà il timestamp di base per un frame (quindi frame Time/NS_PS_MS). Tuttavia, aggiungo anche la parte frazionata della timestamp pre-castata a un contatore della frazione di temporizzazione (in C++ ho usato la funzione modf). Ora aggiungo il timestamp fuso (che è un numero intero dal momento in cui è stato castato a lungo) con la frazione di tempo rimanente se la frazione di tempo è un intero. Fondamentalmente se hai accumulato un millisecondo in più, assicurati di aggiungerlo al frame. In questo modo puoi compensare qualsiasi deriva di precisione.

  3. Effetti di fisarmonica. Mentre nel tempo tutto può essere aggiunto alla cosa giusta, e pensi che anche con una granulazione di 1 secondo le cose dovrebbero coincidere, non lo faranno. L'audio deve corrispondere perfettamente o le cose sembreranno strane. Questo di solito è caratterizzato dal fatto che senti l'audio giusto proveniente da una persona al momento giusto, ma le labbra non si allineano. Nel corso del tempo tutto va ancora bene, ma nulla si allinea abbastanza. Questo perché non stai rendendo i frame al momento giusto. Alcuni fotogrammi sono un po 'troppo lunghi, alcuni fotogrammi un po' troppo brevi, su tutto tutto si aggiunge al punto giusto, ma nulla è della lunghezza giusta.

Ora, il motivo per cui si sta eseguendo in questo se la vostra precisione è già al livello nanosecondo 100, suona per me come probabilmente è punto 1. Vorrei confermare che si è sicuri si sta calcolando il diritto timestamp fine prima di andare avanti

A volte eseguo anche test in cui riassumo i delta tra i frame e assicurandomi che le cose si aggiungano correttamente. La somma del tempo tra ogni frame per la durata del tuo stream dovrebbe essere uguale al tempo di streaming. Cioè il frame 1 è lungo 33 ms e il frame 2 ha una lunghezza di 34 ms e si registra per 67 ms. Se hai registrato per 70ms hai perso qualcosa da qualche parte. Le derive di solito si manifestano dopo alcune ore e sono più facili da rilevare a orecchio/occhio quando si abbinano audio e video insieme.

Inoltre, per contrastare il commento di Hans, il mondo dell'audio engineering ha molto da dire al riguardo. 10 ms è in abbondanza per sentire la latenza, specialmente se associato al feedback video. Potresti non essere in grado di vedere la latenza di 10 ms ma puoi sicuramente ascoltarlo.Da http://helpx.adobe.com/audition/kb/troubleshoot-recording-playback-monitoring-audition.html

linee guida generali che si applicano ai tempi di latenza

Meno di 10 ms - consente il monitoraggio in tempo reale delle tracce in entrata, compresi gli effetti.

A 10 ms - la latenza può essere rilevata ma può ancora suonare naturale ed è utilizzabile per il monitoraggio.

11-20 ms - il monitoraggio inizia a diventare inutilizzabile, si diffonde l'effettiva sorgente sonora,> e l'uscita monitorata è evidente.

20-30 ms - il suono ritardato inizia a suonare come un ritardo effettivo piuttosto che un componente del segnale originale.

Ho un po 'di sballo qui, ma ci sono un sacco di cose in gioco.

1

Una cosa che spicca è che il calcolo del framerate è sbagliato.

dovrebbe essere una durata di 1/framerate = 0,0333667000333667 per ogni fotogramma video

Questo è quando si utilizza 29.97 come un framerate. 29,97 è semplicemente un valore di visualizzazione. Il framerate effettivo è 30/1.001 = 29.97002997002997 FPS. Un frame dura quindi 1/(30/1.001) = 0.0333666666666667 secondi. Source, vedere '60i'.

Problemi correlati