我正在编写自定义 DirectShow 源推送过滤器,该过滤器应该从视频服务器接收 RTP 数据并将它们推送到渲染器。我编写了一个 CVideoPushPin 类,它继承自 CSourceStream 和 CVideoReceiverThread 类,它是从视频服务器接收 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 方法无法足够快地提取数据),结果是播放视频时增加了延迟。有人知道从实时来源接收数据时应该如何做时间戳吗?
当图形的流时间达到示例对象上的时间戳时,渲染器将绘制帧。如果我正确地阅读了您的代码,您将使用到达时的流时间对它们进行时间戳记,因此它们在渲染时总是会迟到。这在某种程度上被音频渲染器混淆了:如果音频渲染器提供图形的时钟,那么它将报告当前流时间为当前正在播放的任何样本,这将导致一些不良的时间行为。
您想要设置一个未来的时间,以允许图表中的延迟和过滤器中的任何缓冲。尝试将时间设置为未来 300 毫秒(现在的流时间 + 300 毫秒)。
您希望帧之间保持一致,因此不要根据每个帧的到达时间对它们添加时间戳。对每一帧使用 RTP 时间戳,并将第一帧的基线设置为未来 300 毫秒;随后的帧是 (rtp - rtp_at_baseline) + dshow 基线(具有适当的单位转换。
您需要使用相同的基线以相同的方式为音频和视频流添加时间戳。但是,如果我记得的话,RTP 时间戳在每个流中都有不同的基线,因此您需要使用 RTCP 数据包将 RTP 时间戳转换为(绝对)NTP 时间,然后使用初始基线将 NTP 转换为 directshow (基线 NTP = dshow现在的流时间 + 300 毫秒)。
G
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)