如何在自定义 DirectShow 过滤器中以秒为单位获得正确的帧时间?
How to get correct frame time in seconds in custom DirectShow filter?
我想从视频文件中抓取帧。
由于 Directshow 的 SampleGrabber 中的一些错误,我决定创建一个类似的过滤器(不是变换过滤器而是渲染器)。
我正在尝试创建一个基于 Windows SDK 转储过滤器 (Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\filters\dump
) 的 DirectShow 过滤器。
我的滤镜只接受 RGB24 格式。
class CDumpInputPin : public CRenderedInputPin
{
//...
STDMETHODIMP Receive(IMediaSample *pSample) override {
//...
REFERENCE_TIME tStart=0, tStop=0;
if (FAILED(pSample->GetTime(&tStart, &tStop))) {
LOG(ERROR) << "Unable to get sample time";
}
LOG(INFO) << "tStart=" << tStart << " tStop=" << tStop ;
}
HRESULT CheckMediaType(const CMediaType *pmt){
if (*pmt->Type() != MEDIATYPE_Video) {
return S_FALSE;
}
if ((*pmt->FormatType() != FORMAT_VideoInfo)) {
return S_FALSE;
}
if ((*pmt->Subtype() != MEDIASUBTYPE_RGB24)) {
return S_FALSE;
}
return S_OK;
}
}
我得到了正确的 RGB 帧,但我不明白如何解释从 IMediaSample::GetTime() 方法返回的值。
我使用 pSeeking->SetPositions( &Start, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame, 0, AM_SEEKING_NoPositioning);
来寻找源文件中的不同位置。
当我尝试抓取 8 帧时,请查看我的日志。
tStart=222223 tStop=622223
tStart=266668 tStop=666668
tStart=311113 tStop=711113
tStart=355558 tStop=755558
tStart=3 tStop=400003
tStart=44448 tStop=444448
tStart=88893 tStop=488893
tStart=133338 tStop=533338
我不明白这些数字是什么意思,为什么它们不是递增序列。
这些帧的正确时间戳应该是:
00:00:12
00:00:37
00:01:01
00:01:26
00:01:51
00:02:15
00:02:40
00:03:05
您获得正确的时间 - 以 100ns 为单位的 64 位值。参见 REFERENCE_TIME
and Time and Clocks in DirectShow。
The REFERENCE_TIME data type defines the units for reference times in DirectShow. Each unit of reference time is 100 nanoseconds.
...
The time stamp defines a media sample's start and finish times, measured in stream time. The time stamp is sometimes called the presentation time
...
File playback: The first sample is time stamped with a start time of zero. Subsequent time stamps are determined by the sample length and the playback rate, which itself is determined by the file format. The filter that parses the file is responsible for calculating the correct time stamps.
所以,
How to get correct frame time in seconds...
DOUBLE Time = tStart / 1E7; // <<--- presentation time (see above) in seconds
我想从视频文件中抓取帧。 由于 Directshow 的 SampleGrabber 中的一些错误,我决定创建一个类似的过滤器(不是变换过滤器而是渲染器)。
我正在尝试创建一个基于 Windows SDK 转储过滤器 (Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\filters\dump
) 的 DirectShow 过滤器。
我的滤镜只接受 RGB24 格式。
class CDumpInputPin : public CRenderedInputPin
{
//...
STDMETHODIMP Receive(IMediaSample *pSample) override {
//...
REFERENCE_TIME tStart=0, tStop=0;
if (FAILED(pSample->GetTime(&tStart, &tStop))) {
LOG(ERROR) << "Unable to get sample time";
}
LOG(INFO) << "tStart=" << tStart << " tStop=" << tStop ;
}
HRESULT CheckMediaType(const CMediaType *pmt){
if (*pmt->Type() != MEDIATYPE_Video) {
return S_FALSE;
}
if ((*pmt->FormatType() != FORMAT_VideoInfo)) {
return S_FALSE;
}
if ((*pmt->Subtype() != MEDIASUBTYPE_RGB24)) {
return S_FALSE;
}
return S_OK;
}
}
我得到了正确的 RGB 帧,但我不明白如何解释从 IMediaSample::GetTime() 方法返回的值。
我使用 pSeeking->SetPositions( &Start, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame, 0, AM_SEEKING_NoPositioning);
来寻找源文件中的不同位置。
当我尝试抓取 8 帧时,请查看我的日志。
tStart=222223 tStop=622223
tStart=266668 tStop=666668
tStart=311113 tStop=711113
tStart=355558 tStop=755558
tStart=3 tStop=400003
tStart=44448 tStop=444448
tStart=88893 tStop=488893
tStart=133338 tStop=533338
我不明白这些数字是什么意思,为什么它们不是递增序列。
这些帧的正确时间戳应该是:
00:00:12
00:00:37
00:01:01
00:01:26
00:01:51
00:02:15
00:02:40
00:03:05
您获得正确的时间 - 以 100ns 为单位的 64 位值。参见 REFERENCE_TIME
and Time and Clocks in DirectShow。
The REFERENCE_TIME data type defines the units for reference times in DirectShow. Each unit of reference time is 100 nanoseconds.
...
The time stamp defines a media sample's start and finish times, measured in stream time. The time stamp is sometimes called the presentation time
...
File playback: The first sample is time stamped with a start time of zero. Subsequent time stamps are determined by the sample length and the playback rate, which itself is determined by the file format. The filter that parses the file is responsible for calculating the correct time stamps.
所以,
How to get correct frame time in seconds...
DOUBLE Time = tStart / 1E7; // <<--- presentation time (see above) in seconds