5

我正在编写自定义 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 方法无法足够快地提取数据),结果是在播放视频时增加了延迟。有谁知道从实时源接收数据时我应该如何做时间戳?

4

1 回答 1

6

当图形的流时间达到示例对象上的时间戳时,渲染器将绘制帧。如果我正确阅读了您的代码,您将在到达时使用流时间为它​​们加上时间戳,因此它们在渲染时总是会迟到。音频渲染器对此有些困惑:如果音频渲染器提供图形的时钟,那么它将报告当前流时间是它当前正在播放的任何样本,这将导致一些不希望的时间行为。

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

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

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

G

于 2010-02-11T09:32:19.877 回答