Commit 1dc73281 authored by Vitaly Tuzov's avatar Vitaly Tuzov

Added precise seek to MSMF-based VideoCapture::set(CAP_PROP_POS_FRAMES)

parent 80600e5c
...@@ -137,14 +137,14 @@ template <class T> ...@@ -137,14 +137,14 @@ template <class T>
class ComPtr class ComPtr
{ {
public: public:
ComPtr() throw() ComPtr()
{ {
} }
ComPtr(T* lp) throw() ComPtr(T* lp)
{ {
p = lp; p = lp;
} }
ComPtr(_In_ const ComPtr<T>& lp) throw() ComPtr(_In_ const ComPtr<T>& lp)
{ {
p = lp.p; p = lp.p;
} }
...@@ -152,25 +152,25 @@ public: ...@@ -152,25 +152,25 @@ public:
{ {
} }
T** operator&() throw() T** operator&()
{ {
assert(p == NULL); assert(p == NULL);
return p.operator&(); return p.operator&();
} }
T* operator->() const throw() T* operator->() const
{ {
assert(p != NULL); assert(p != NULL);
return p.operator->(); return p.operator->();
} }
bool operator!() const throw() bool operator!() const
{ {
return p.operator==(NULL); return p.operator==(NULL);
} }
bool operator==(_In_opt_ T* pT) const throw() bool operator==(_In_opt_ T* pT) const
{ {
return p.operator==(pT); return p.operator==(pT);
} }
bool operator!=(_In_opt_ T* pT) const throw() bool operator!=(_In_opt_ T* pT) const
{ {
return p.operator!=(pT); return p.operator!=(pT);
} }
...@@ -179,38 +179,38 @@ public: ...@@ -179,38 +179,38 @@ public:
return p.operator!=(NULL); return p.operator!=(NULL);
} }
T* const* GetAddressOf() const throw() T* const* GetAddressOf() const
{ {
return &p; return &p;
} }
T** GetAddressOf() throw() T** GetAddressOf()
{ {
return &p; return &p;
} }
T** ReleaseAndGetAddressOf() throw() T** ReleaseAndGetAddressOf()
{ {
p.Release(); p.Release();
return &p; return &p;
} }
T* Get() const throw() T* Get() const
{ {
return p; return p;
} }
// Attach to an existing interface (does not AddRef) // Attach to an existing interface (does not AddRef)
void Attach(_In_opt_ T* p2) throw() void Attach(_In_opt_ T* p2)
{ {
p.Attach(p2); p.Attach(p2);
} }
// Detach the interface (does not Release) // Detach the interface (does not Release)
T* Detach() throw() T* Detach()
{ {
return p.Detach(); return p.Detach();
} }
_Check_return_ HRESULT CopyTo(_Deref_out_opt_ T** ppT) throw() _Check_return_ HRESULT CopyTo(_Deref_out_opt_ T** ppT)
{ {
assert(ppT != NULL); assert(ppT != NULL);
if (ppT == NULL) if (ppT == NULL)
...@@ -228,13 +228,13 @@ public: ...@@ -228,13 +228,13 @@ public:
// query for U interface // query for U interface
template<typename U> template<typename U>
HRESULT As(_Inout_ U** lp) const throw() HRESULT As(_Inout_ U** lp) const
{ {
return p->QueryInterface(__uuidof(U), reinterpret_cast<void**>(lp)); return p->QueryInterface(__uuidof(U), reinterpret_cast<void**>(lp));
} }
// query for U interface // query for U interface
template<typename U> template<typename U>
HRESULT As(_Out_ ComPtr<U>* lp) const throw() HRESULT As(_Out_ ComPtr<U>* lp) const
{ {
return p->QueryInterface(__uuidof(U), reinterpret_cast<void**>(lp->ReleaseAndGetAddressOf())); return p->QueryInterface(__uuidof(U), reinterpret_cast<void**>(lp->ReleaseAndGetAddressOf()));
} }
...@@ -720,6 +720,7 @@ protected: ...@@ -720,6 +720,7 @@ protected:
bool convertFormat; bool convertFormat;
UINT32 aspectN, aspectD; UINT32 aspectN, aspectD;
MFTIME duration; MFTIME duration;
LONGLONG frameStep;
_ComPtr<IMFSample> videoSample; _ComPtr<IMFSample> videoSample;
LONGLONG sampleTime; LONGLONG sampleTime;
IplImage* frame; IplImage* frame;
...@@ -975,7 +976,11 @@ bool CvCapture_MSMF::open(int _index) ...@@ -975,7 +976,11 @@ bool CvCapture_MSMF::open(int _index)
isOpened = true; isOpened = true;
duration = 0; duration = 0;
if (configureOutput(0, 0, 0, aspectN, aspectD, outputFormat, convertFormat)) if (configureOutput(0, 0, 0, aspectN, aspectD, outputFormat, convertFormat))
{
double fps = getFramerate(nativeFormat);
frameStep = (LONGLONG)(fps > 0 ? 1e7 / fps : 0);
camid = _index; camid = _index;
}
} }
} }
} }
...@@ -1017,6 +1022,8 @@ bool CvCapture_MSMF::open(const char* _filename) ...@@ -1017,6 +1022,8 @@ bool CvCapture_MSMF::open(const char* _filename)
sampleTime = 0; sampleTime = 0;
if (configureOutput(0, 0, 0, aspectN, aspectD, outputFormat, convertFormat)) if (configureOutput(0, 0, 0, aspectN, aspectD, outputFormat, convertFormat))
{ {
double fps = getFramerate(nativeFormat);
frameStep = (LONGLONG)(fps > 0 ? 1e7 / fps : 0);
filename = _filename; filename = _filename;
PROPVARIANT var; PROPVARIANT var;
HRESULT hr; HRESULT hr;
...@@ -1080,10 +1087,12 @@ bool CvCapture_MSMF::grabFrame() ...@@ -1080,10 +1087,12 @@ bool CvCapture_MSMF::grabFrame()
} }
else if (flags & MF_SOURCE_READERF_ENDOFSTREAM) else if (flags & MF_SOURCE_READERF_ENDOFSTREAM)
{ {
sampleTime += frameStep;
DebugPrintOut(L"\tEnd of stream detected\n"); DebugPrintOut(L"\tEnd of stream detected\n");
} }
else else
{ {
sampleTime += frameStep;
if (flags & MF_SOURCE_READERF_NEWSTREAM) if (flags & MF_SOURCE_READERF_NEWSTREAM)
{ {
DebugPrintOut(L"\tNew stream detected\n"); DebugPrintOut(L"\tNew stream detected\n");
...@@ -1182,17 +1191,23 @@ bool CvCapture_MSMF::setTime(double time, bool rough) ...@@ -1182,17 +1191,23 @@ bool CvCapture_MSMF::setTime(double time, bool rough)
{ {
PROPVARIANT var; PROPVARIANT var;
if (SUCCEEDED(videoFileSource->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS, &var)) && if (SUCCEEDED(videoFileSource->GetPresentationAttribute((DWORD)MF_SOURCE_READER_MEDIASOURCE, MF_SOURCE_READER_MEDIASOURCE_CHARACTERISTICS, &var)) &&
var.vt == VT_UI4 && (var.ulVal & MFMEDIASOURCE_CAN_SEEK && (rough || var.ulVal & MFMEDIASOURCE_HAS_SLOW_SEEK))) var.vt == VT_UI4 && var.ulVal & MFMEDIASOURCE_CAN_SEEK)
{ {
if (videoSample)
videoSample.Reset();
bool useGrabbing = time > 0 && !rough && !(var.ulVal & MFMEDIASOURCE_HAS_SLOW_SEEK);
PropVariantClear(&var); PropVariantClear(&var);
sampleTime = (LONGLONG)floor(time + 0.5); sampleTime = (useGrabbing && time >= frameStep) ? (LONGLONG)floor(time + 0.5) - frameStep : (LONGLONG)floor(time + 0.5);
var.vt = VT_I8; var.vt = VT_I8;
var.hVal.QuadPart = sampleTime; var.hVal.QuadPart = sampleTime;
HRESULT hr = videoFileSource->SetCurrentPosition(GUID_NULL, var); bool resOK = SUCCEEDED(videoFileSource->SetCurrentPosition(GUID_NULL, var));
if (videoSample)
videoSample.Reset();
PropVariantClear(&var); PropVariantClear(&var);
return SUCCEEDED(hr); if (resOK && useGrabbing)
{
LONGLONG timeborder = (LONGLONG)floor(time + 0.5) - frameStep / 2;
do { resOK = grabFrame(); videoSample.Reset(); } while (resOK && sampleTime < timeborder);
}
return resOK;
} }
return false; return false;
} }
...@@ -1576,7 +1591,7 @@ bool CvCapture_MSMF::setProperty( int property_id, double value ) ...@@ -1576,7 +1591,7 @@ bool CvCapture_MSMF::setProperty( int property_id, double value )
return setTime(value * 1e7 / getFramerate(nativeFormat), false); return setTime(value * 1e7 / getFramerate(nativeFormat), false);
break; break;
case CV_CAP_PROP_POS_MSEC: case CV_CAP_PROP_POS_MSEC:
return setTime(value * 1e4, true); return setTime(value * 1e4, false);
case CV_CAP_PROP_BRIGHTNESS: case CV_CAP_PROP_BRIGHTNESS:
if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp)))) if (SUCCEEDED(videoFileSource->GetServiceForStream((DWORD)MF_SOURCE_READER_MEDIASOURCE, GUID_NULL, IID_PPV_ARGS(&pProcAmp))))
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment