编写自定义DirectShow RTSP / RTP源推送过滤器 - 来自实时源的时间戳数据

时间:2010-02-10 20:34:00

标签: filter directshow rtp rtsp

我正在编写自定义DirectShow源推送过滤器,它应该从视频服务器接收RTP数据并将它们推送到渲染器。我写了一个CVideoPushPin类,它继承自CSourceStream和CVideoReceiverThread类,它是从视频服务器接收RTP数据包的线程的包装器。接收者线程基本上做了三件事:

  • 接收原始RTP数据包并收集Receiver Reports所需的一些数据
  • 汇总帧,将它们复制到缓冲区并将有关它们的信息存储到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方法无法足够快地提取数据),结果是播放视频时延迟增加。有没有人知道在从实时源接收数据时我应该如何进行时间戳?

1 个答案:

答案 0 :(得分:6)

当图形的流时间到达样本对象的时间戳时,渲染器将绘制帧。如果我正确地读取了您的代码,那么您将使用到达时的流时间为它​​们加上时间戳,因此它们将始终在渲染时间较晚。这在音频渲染器中有些混淆:如果音频渲染器提供图形的时钟,那么它将报告当前流时间为当前正在播放的任何样本,这将导致一些不期望的时间行为。

  1. 您希望将来设置一个时间,以允许图表中的延迟和过滤器中的任何缓冲。尝试将未来的时间设置为300毫秒(流时间现在为+ 300毫秒)。

  2. 您希望帧之间保持一致,因此请不要根据每帧的到达时间对它们加时间戳。对每个帧使用RTP时间戳,并将第一个的基线设置为将来300ms;然后是后续帧(rtp - rtp_at_baseline)+ dshow基线(具有适当的单位转换。

  3. 您需要使用相同的基线以相同的方式为音频和视频流添加时间戳。但是,如果我记得,RTP时间戳在每个流中都有不同的基线,那么您需要使用RTCP数据包将RTP时间戳转换为(绝对)NTP时间,然后使用您的初始基线将NTP转换为directshow(基线NTP = dshow流时间现在+ 300毫秒)。