2010-02-10 10 views
5

Sto scrivendo un filtro push sorgente DirectShow personalizzato che dovrebbe ricevere i dati RTP dal server video e inviarli al renderer. Ho scritto una classe CVideoPushPin che eredita da CSourceStream e CVideoReceiverThread class che è un wrapper per un thread che riceve pacchetti RTP dal server video. Il filo ricevitore fa essenzialmente tre cose:Scrittura personalizzata DirectShow Filtro push RTSP/RTP sorgente - Dati cronografici provenienti da fonti live

  • riceve pacchetti RTP prime e raccoglie alcuni dati che è necessario per il ricevitore Reports
  • assembla telai, li copia nel buffer e memorizza le informazioni su di loro in 256 coda elemento , che è definito come segue:

    struct queue_elem { 
        char *start; // Pointer to a frame in a buffer 
        int length; // Lenght of data 
        REFERENCE_TIME recvTime; // Timestamp when the frame was received (stream time) 
    }; 
    
    struct data { 
        struct queue_elem queue[QUEUE_LENGTH]; 
        int qWrIdx; 
        int qRdIdx; 
    HANDLE mutex; 
    }; 
    
  • ogni frame ricevuto viene timestamped tempo stream corrente

    p->StreamTime(refTime); 
    REFERENCE_TIME rt = refTime.GetUnits(); 
    

Il problema è che non sono sicuro di come sia necessario impostare i timestamp per ogni MediaSample nel metodo FillBuffer. Ho provato diversi modi, ma la riproduzione si interrompe o è troppo lenta. Attualmente il metodo FillBuffer assomiglia a questo:

REFERENCE_TIME thisFrameStartTime, thisFrameEndTime; 
// Make sure if there are at least 4 frames in the buffer 
    if(noOfFrames >= 4) 
    { 
     currentQe = m_myData.queue[m_myData.qRdIdx++]; //Take current frame description  
     if(m_myData.qRdIdx >= QUEUE_LENGTH) 
     { 
      m_myData.qRdIdx = 0; 
     }   
     nextQe = m_myData.queue[m_myData.qRdIdx]; //Take next frame description 
     if(currentQe.length > 0) 
     { 
      memcpy(pData, currentQe.start, currentQe.length);    

      pSample->SetActualDataLength(currentQe.length);     
      CRefTime refTime; 
      m_pFilter->StreamTime(refTime); 
      REFERENCE_TIME rt; 
      rt = refTime.GetUnits(); 
      pSample->GetTime(&thisFrameStartTime, &thisFrameEndTime); 
      thisFrameEndTime = thisFrameStartTime + (nextQe.recvTime - currentQe.recvTime); 
      pSample->SetTime(&thisFrameStartTime, &thisFrameEndTime); 
     } 
    } 
    else 
    { 
     pSample->SetActualDataLength(0); 
    } 

In questo caso ho notato che il numero di elementi negli aumenti di coda molto rapidamente (per qualche motivo il metodo FillBuffer non può tirare fuori i dati abbastanza veloce), e il risultato è aumento del ritardo durante la riproduzione di video. Qualcuno ha un'idea di come dovrei fare il timestamping quando ricevo dati da fonti live?

risposta

6

Il renderer disegna i fotogrammi quando il tempo di flusso del grafico raggiunge il timestamp sull'oggetto campione. Se leggo correttamente il tuo codice, li stai timestamping con il tempo di streaming all'arrivo, quindi saranno sempre in ritardo al rendering. Questo è un po 'confuso dal riproduttore audio: se il riproduttore audio sta fornendo l'orologio del grafico, allora riferirà il tempo corrente del flusso come qualsiasi campione al momento sta suonando, e questo causerà un comportamento temporale indesiderato.

  1. si desidera impostare un tempo in futuro, per consentire la latenza attraverso il grafico e buffering nel filtro. Prova a impostare un'ora forse 300ms nel futuro (ora del flusso ora + 300ms).

  2. Si desidera essere coerenti tra i fotogrammi, quindi non segnarli in base all'orario di arrivo di ciascun fotogramma. Usa il timestamp RTP per ogni frame e imposta la linea di base per il primo a 300ms nel futuro; fotogrammi successivi sono poi (RTP - rtp_at_baseline) + dshow basale (con conversioni di unità appropriate

  3. È necessario timestamp l'audio e gli stream video nello stesso modo, utilizzando la stessa linea di base Tuttavia, se ben ricordo, RTP.. i timestamp hanno una linea di base diversa in ogni flusso, quindi è necessario utilizzare i pacchetti RTCP per convertire i timestamp RTP in tempo assoluto (NTP) e quindi convertire NTP in directshow utilizzando la baseline iniziale (ora di base NTP = dshow ora + 300ms).

G

+0

Geraint, Grazie per il vostro input. ho fatto un po 'di c appende il mio codice, tuttavia il video si blocca subito dopo averlo eseguito. Nel file di registro ho notato che il metodo FillBuffer viene chiamato solo due volte.Quando viene chiamato per la prima volta, lo stream time è 3633950000, frameStartTime è 3635700000 e frameEndTime è 3635703600. Per la seconda volta, lo stream time è 3634370000, frameStartTime è 3635703600 e frameEndTime è 3635707200. Quindi, se ho capito bene, il renderer dovrebbe attendere il tempo di flusso per raggiungere il timestamp sul primo fotogramma e quindi eseguire senza intoppi, ma purtroppo non succede. – mkurek

Problemi correlati