2010-02-10 89 views
5

我正在編寫自定義DirectShow源推送過濾器,它應該從視頻服務器接收RTP數據並將它們推送到呈現器。我編寫了一個CVideoPushPin類,該類繼承自CSourceStream和CVideoReceiverThread類,它是從視頻服務器接收RTP包的線程的包裝。接收器線程基本上做三兩件事:編寫自定義DirectShow RTSP/RTP源推送過濾器 - 來自實時源的時間戳數據

  • 接收原始的RTP包,並且收集所需要的接收器的一些數據報告
  • 組裝的幀,它們複製到有關它們的緩衝器,並且存儲信息到256 元件隊列,其定義如下:

    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; 
    }; 
    
  • 每個接收的幀與當前流時間時間戳

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

問題是我不知道我該如何設置FillBuffer方法中每個MediaSample的時間戳。我嘗試了幾種方法,但播放停止或速度太慢。 目前FillBuffer方法是這樣的:

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); 
    } 

在這種情況下,我注意到,項目的隊列中的增加非常迅速的數量(因爲某些原因FillBuffer方法不能拔出數據速度不夠快),其結果是播放視頻時延遲時間增加。有沒有人有一個想法,當從實時來源接收數據時,我應該如何做時間戳?

回答

6

渲染器將在圖形的流時間到達樣本對象上的時間戳時繪製框架。如果我正確地讀取了您的代碼,那麼您在到達時使用流時間來標記它們,所以它們在渲染時總是會遲到。音頻渲染器對此有些困惑:如果音頻渲染器正在提供圖形時鐘,那麼它會將當前的流時間報告爲當前正在播放的任何樣本,並且這會導致一些不受歡迎的時間行爲。

  1. 您希望在將來設置一個時間,以允許通過圖形的延遲和過濾器中的任何緩衝。嘗試在未來設置一個300ms的時間(現在流時間+ 300ms)。

  2. 你希望幀之間保持一致,所以不要根據每幀的到達時間對它們進行時間戳記。使用每個幀的RTP時間戳,並將第一個的基線設置爲將來300ms; (rtp - rtp_at_baseline)+ dshow基線(具有適當的單位轉換)

  3. 您需要使用相同的基線以相同的方式爲音頻和視頻流添加時間戳記,但是如果我記得RTP時間戳在每個流中都有不同的基線,因此您需要使用RTCP數據包將RTP時間戳轉換爲(絕對)NTP時間,然後使用您的初始基線(基線NTP = dshow流時間+ 300ms)將NTP轉換爲directshow。

+0

傑蘭特, 感謝您的輸入。我做了一些C在我的代碼中出現了一些問題,然而,視頻在我運行之後就凍結了。在日誌文件中,我注意到FillBuffer方法只被調用了兩次。第一次調用時,流時間爲3633950000,frameStartTime爲3635700000,frameEndTime爲3635703600.第二次,流時間爲3634370000,frameStartTime爲3635703600,frameEndTime爲3635707200.因此,如果我理解正確,渲染器應等待流時間到達第一幀的時間戳,然後平穩運行,但不幸的是,它不會發生。 – mkurek 2010-02-11 13:58:18