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