2010-11-21 26 views
2

挨拶、DirectShowのオーディオ/ビデオPTS計算

クロッキング私はひるみ/ ARMビデオプロセッサ上で書かれたATSC-153の放送からAVC/AACビデオフレーム/ AACアクセスユニットをとるDirectShowのソースフィルタを書かれています。出力ピン(2つはビデオ用、1つはオーディオ用)は適切なデコーダとレンダラに接続されています。現在、私は適切なRTPヘッダーからPTSを取り出し、ソースフィルターに渡して、directshowクロックに計算を実行しています。ビデオPTSは90Khzのレートで、オーディオのPTSレートはさまざまで、私の現在のテストストリームは55.2Khzでオーディオティックを持っています。

以下は、convert_to_dshow_timestamp()およびFillBuffer()ルーチンです。ビデオ/オーディオがフィルタによって取り出されるときに、変換されたタイムスタンプをプリントアウトするので、時間は100〜200msの差の範囲内にあります。これは悪いことではありません。ただし、ビデオはオーディオを2〜3秒間追跡します。

/* DirectShowのクロックレートにクロック・レートを変換するルーチン*/ スタティック符号なしの長い長いconvert_to_dshow_timestamp( のunsigned long長いTS、 unsigned long型レート ) {長い二ヘルツ。 long double multi; long double tmp;

if (rate == 0) 
{ 
    return 0; 
} 

hz = (long double) 1.0/rate; 
multi = hz/1e-7; 

tmp = ((long double) ts * multi) + 0.5; 
return (unsigned long long) tmp; 

}

/*ソースフィルタFillBuffer()ルーチン*/ HRESULT OutputPin :: FillBuffer(IMediaSample * PSAMP) {BYTE * pDataを。 DWORD dataSize; pipeStreamストリーム。 BOOL retVal; DWORD returnBytes; HRESULT hr; DWORDが無効です。 REFERENCE_TIME ts; REFERENCE_TIME df; 符号なしlong long difPts; 符号なしlong long difTimeRef;

pSamp->GetPointer(&pData); 
dataSize = pSamp->GetSize(); 

ZeroMemory(pData, dataSize); 

stream.lBuf = pData; 
stream.dataSize = dataSize; 

/* Pin type 1 is H.264 AVC video frames */ 
if (m_iPinType == 1) 
{ 
    retVal = DeviceIoControl(
           ghMHTune, 
           IOCTL_MHTUNE_RVIDEO_STREAM, 
           NULL, 
           0, 
           &stream, 
           sizeof(pipeStream), 
           &returnBytes, 
           NULL 
          ); 
    if (retVal == TRUE) 
    { 
     /* Get the data */ 
     /* Check for the first of the stream, if so, set the start time */ 
     pSamp->SetActualDataLength(returnBytes); 
     hr = S_OK; 
     if (returnBytes > 0) 
     { 
      /* The discontinuety is set in upper layers, when an RTP 
      * sequence number has been lost. 
      */ 
      discont = stream.discont; 

      /* Check for another break in stream time */ 
      if (
       m_PrevTimeRef && 
       ((m_PrevTimeRef > (stream.timeRef + 90000 * 10)) || 
       ((m_PrevTimeRef + 90000 * 10) < stream.timeRef)) 
       ) 
      { 
       dbg_log(TEXT("MY:DISC HERE\n")); 
       if (m_StartStream > 0) 
       { 
        discont = 1; 
       } 
      } 

      /* If the stream has not started yet, or there is a 
      * discontinuety then reset the stream time. 
      */ 
      if ((m_StartStream == 0) || (discont != 0)) 
      { 
       sys_time = timeGetTime() - m_ClockStartTime; 
       m_OtherSide->sys_time = sys_time; 

       /* For Video, the clockRate is 90Khz */ 
       m_RefGap = (sys_time * (stream.clockRate/1000)) + 
                (stream.clockRate/2); 

       /* timeRef is the PTS for the frame from the RTP header */ 
       m_TimeGap = stream.timeRef; 
       m_StartStream = 1; 
       difTimeRef = 1; 
       m_PrevPTS = 0; 
       m_PrevSysTime = timeGetTime(); 
       dbg_log(
         TEXT("MY:StartStream %lld: %lld: %lld\n"), 
         sys_time, 
         m_RefGap, 
         m_TimeGap 
         ); 
      } 
      else 
      { 
       m_StartStream++; 
      } 

      difTimeRef = stream.timeRef - m_PrevTimeRef; 
      m_PrevTimeRef = stream.timeRef; 

      /* Difference in 90 Khz clocking */ 
      ts = stream.timeRef - m_TimeGap + m_RefGap; 
      ts = convert_to_dshow_timestamp(ts, stream.clockRate); 

      if (discont != 0) 
      { 
       dbg_log(TEXT("MY:VDISC TRUE\n")); 
       pSamp->SetDiscontinuity(TRUE); 
      } 
      else 
      { 
       pSamp->SetDiscontinuity(FALSE); 
       pSamp->SetSyncPoint(TRUE); 
      } 

      difPts = ts - m_PrevPTS; 

      df = ts + 1; 
      m_PrevPTS = ts; 
      dbg_log(
        TEXT("MY:T %lld: %lld = %lld: %d: %lld\n"), 
        ts, 
        m_OtherSide->m_PrevPTS, 
        stream.timeRef, 
        (timeGetTime() - m_PrevSysTime), 
        difPts 
        ); 

      pSamp->SetTime(&ts, &df); 
      m_PrevSysTime = timeGetTime(); 
     } 
     else 
     { 
      Sleep(10); 
     } 
    } 
    else 
    { 
     dbg_log(TEXT("MY: Fill FAIL\n")); 
     hr = E_FAIL; 
    } 
} 
else if (m_iPinType == 2) 
{ 
    /* Pin Type 2 is audio AAC Access units, with ADTS headers */ 
    retVal = DeviceIoControl(
           ghMHTune, 
           IOCTL_MHTUNE_RAUDIO_STREAM, 
           NULL, 
           0, 
           &stream, 
           sizeof(pipeStream), 
           &returnBytes, 
           NULL 
          ); 

    if (retVal == TRUE) 
    { 
     /* Get the data */ 
     /* Check for the first of the stream, if so, set the start time */ 
     hr = S_OK; 
     if (returnBytes > 0) 
     { 
      discont = stream.discont; 
      if ((m_StartStream == 0) || (discont != 0)) 
      { 
       sys_time = timeGetTime() - m_ClockStartTime; 
       m_RefGap = (sys_time * (stream.clockRate/1000)) + 
                (stream.clockRate/2); 

       /* Mark the first PTS from stream. This PTS is from the 
       * RTP header, and is usually clocked differently than the 
       * video clock. 
       */ 
       m_TimeGap = stream.timeRef; 
       m_StartStream = 1; 
       difTimeRef = 1; 
       m_PrevPTS = 0; 
       m_PrevSysTime = timeGetTime(); 
       dbg_log(
         TEXT("MY:AStartStream %lld: %lld: %lld\n"), 
         sys_time, 
         m_RefGap, 
         m_TimeGap 
         ); 
      } 

      /* Let the video side stream in first before letting audio 
      * start to flow. 
      */ 
      if (m_OtherSide->m_StartStream < 32) 
      { 
       pSamp->SetActualDataLength(0); 
       Sleep(10); 
       return hr; 
      } 
      else 
      { 
       pSamp->SetActualDataLength(returnBytes); 
      } 

      difTimeRef = stream.timeRef - m_PrevTimeRef; 
      m_PrevTimeRef = stream.timeRef; 

      if (discont != 0) 
      { 
       dbg_log(TEXT("MY:ADISC TRUE\n")); 
       pSamp->SetDiscontinuity(TRUE); 
      } 
      else 
      { 
       pSamp->SetDiscontinuity(FALSE); 
       pSamp->SetSyncPoint(TRUE); 
      } 

      /* Difference in Audio PTS clock, TESTING AT 55.2 Khz */ 
      ts = stream.timeRef - m_TimeGap + m_RefGap; 
      ts = convert_to_dshow_timestamp(ts, stream.clockRate); 

      difPts = ts - m_PrevPTS; 

      df = ts + 1; 
      m_PrevPTS = ts; 
      dbg_log(
        TEXT("MY:AT %lld = %lld: %d: %lld\n"), 
        ts, 
        stream.timeRef, 
        (timeGetTime() - m_PrevSysTime), 
        difPts 
        ); 

      pSamp->SetTime(&ts, &df); 
      m_PrevSysTime = timeGetTime(); 
     } 
     else 
     { 
      pSamp->SetActualDataLength(0); 
      Sleep(10); 
     } 
    } 
} 
return hr; 

} /*コードの終了*/

私は、ビデオがはるか先のオーディオの行くかどうかを確認するために、単純に(* 10 90000)を追加することにより、ビデオPTSを調整しようとしていますしかしそれはしません。ビデオはまだオーディオを2秒以上たどります。なぜこれがうまくいかないのか分かりません。各ビデオフレームは10秒先に表示されます。これは正しくないでしょうか?

主な質問は、基本的にアルゴリズムの音ですか?彼らはビデオ/オーディオを独立して動作させても問題ないようです。

ソースフィルタはプッシュフィルタではありません。違いがあるかどうかはわかりません。私は、デコーダが放送からの入力と同期しなくなるという問題はない。

多くのありがとうございます。

+0

時間の経過に伴って後続処理が行われるのですか、またはすぐに2-3秒の遅延で開始されますか?また、読みやすいようにコードを再フォーマットしてください。 – BeemerGuy

+0

コードフォーマットは残念です。私は次回よりもうまくやってみよう。 – davroslyrad

答えて

3

実際に私は2つの問題がありました。

最初のものは、SPS H.264フレームに悪影響がありました。デコーダーが起動すると、SPSフレームが見つかるまで、すべてのフレームが取り除かれます。ストリームは毎秒15フレームでエンコードされていました。これは、デコーダが10ms未満で第2の価値のビデオを消費するので、タイミングを逸らすであろう。それ以降に提示されたすべてのフレームは遅れていると見なされ、追いつくためにフレームを早送りしようとします。ライブソースであると、フレームが再び不足することになります。この回避策は、少なくとも32フレーム(約2秒)のバッファが存在することを確認するために、私の前のコードに置かれていました。

2番目の問題は、実際には、問題の根本にあります。私は時間参照としてRTPヘッダーからPTSを使用していました。これは個々のオーディオおよび/またはビデオのケースでは機能するが、ビデオRTP PTSが対応するオーディオRTP PTSと一致し、通常はそうでないという保証はない。従ってスペック通りの下記の式に従ってRTCP NTP時間の使用:

PTS = RTCP_SR_NTP_timestamp + (RTP_timestamp - RTCP_SR_RTP_timestamp)/media_clock_rate 

これは私は、対応するオーディオPTSに実際のビデオPTSと一致することを可能にします。