Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/qedit/mediadet.c | 165 ++++++++++++++++++++++++++++++++++-- dlls/qedit/tests/mediadet.c | 40 +++++---- 2 files changed, 178 insertions(+), 27 deletions(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c index bacf520..5eb6aef 100644 --- a/dlls/qedit/mediadet.c +++ b/dlls/qedit/mediadet.c @@ -40,6 +40,7 @@ typedef struct MediaDetImpl { IGraphBuilder *graph; IBaseFilter *source; IBaseFilter *splitter; + ISampleGrabber *grabber; WCHAR *filename; LONG num_streams; LONG cur_stream; @@ -64,6 +65,8 @@ static void MD_cleanup(MediaDetImpl *This) This->source = NULL; if (This->splitter) IBaseFilter_Release(This->splitter); This->splitter = NULL; + if (This->grabber) ISampleGrabber_Release(This->grabber); + This->grabber = NULL; if (This->graph) IGraphBuilder_Release(This->graph); This->graph = NULL; free(This->filename); @@ -224,6 +227,71 @@ next: return hr; }
+static HRESULT seek_graph(MediaDetImpl *detector, double seek_time) +{ + FILTER_STATE state; + LONGLONG pos, stop; + IMediaControl *mc; + IMediaSeeking *ms; + IMediaFilter *mf; + GUID format; + HRESULT hr; + + if (FAILED(hr = IPin_QueryInterface(detector->cur_pin, &IID_IMediaSeeking, (void**)&ms))) + return hr; + + if (IMediaSeeking_IsUsingTimeFormat(ms, &TIME_FORMAT_MEDIA_TIME) != S_OK && + (FAILED(IMediaSeeking_GetTimeFormat(ms, &format)) || + !IsEqualGUID(&format, &TIME_FORMAT_MEDIA_TIME))) + { + /* Windows doesn't implement it */ + hr = E_NOTIMPL; + } + IMediaSeeking_Release(ms); + if (FAILED(hr)) + return hr; + + if (FAILED(hr = IGraphBuilder_QueryInterface(detector->graph, &IID_IMediaControl, (void**)&mc))) + return hr; + + if (FAILED(hr = IMediaControl_Stop(mc))) + goto done; + + if (seek_time >= 0.0) + { + if (FAILED(hr = IGraphBuilder_QueryInterface(detector->graph, &IID_IMediaSeeking, (void**)&ms))) + goto done; + + stop = pos = seek_time * 10000000.0; + hr = IMediaSeeking_SetPositions(ms, &pos, AM_SEEKING_AbsolutePositioning, + &stop, AM_SEEKING_AbsolutePositioning); + IMediaSeeking_Release(ms); + if (FAILED(hr)) + goto done; + } + + if (FAILED(hr = IGraphBuilder_QueryInterface(detector->graph, &IID_IMediaFilter, (void**)&mf))) + goto done; + hr = IMediaFilter_SetSyncSource(mf, NULL); + IMediaFilter_Release(mf); + if (FAILED(hr)) goto done; + + if (FAILED(hr = IMediaControl_Pause(mc))) + goto done; + + /* Testing on Windows shows it waits up to 37500 ms */ + if (FAILED(hr = IMediaControl_GetState(mc, 37500, (OAFilterState*)&state))) + { + if (hr == VFW_S_STATE_INTERMEDIATE) hr = VFW_E_TIME_EXPIRED; + goto done; + } + + hr = S_OK; +done: + IMediaControl_Release(mc); + return hr; +} + /* MediaDet inner IUnknown */ static HRESULT WINAPI MediaDet_inner_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) { @@ -371,7 +439,7 @@ static HRESULT WINAPI MediaDet_get_OutputStreams(IMediaDet* iface, LONG *pVal)
TRACE("(%p)\n", This);
- if (!This->splitter) + if (This->grabber || !This->splitter) return E_INVALIDARG;
if (This->num_streams != -1) @@ -466,6 +534,9 @@ static HRESULT WINAPI MediaDet_put_CurrentStream(IMediaDet* iface, LONG newVal)
TRACE("(%p)->(%d)\n", This, newVal);
+ if (This->grabber) + return E_INVALIDARG; + if (This->num_streams == -1) { LONG n; @@ -495,6 +566,8 @@ static HRESULT WINAPI MediaDet_get_StreamType(IMediaDet *iface, GUID *majortype)
if (!majortype) return E_POINTER; + if (detector->grabber) + return E_INVALIDARG;
if (SUCCEEDED(hr = IMediaDet_get_StreamMediaType(iface, &mt))) { @@ -533,7 +606,7 @@ static HRESULT WINAPI MediaDet_get_StreamLength(IMediaDet *iface, double *length if (!length) return E_POINTER;
- if (!detector->cur_pin) + if (detector->grabber || !detector->cur_pin) return E_INVALIDARG;
if (SUCCEEDED(hr = IPin_QueryInterface(detector->cur_pin, @@ -647,7 +720,7 @@ static HRESULT WINAPI MediaDet_get_StreamMediaType(IMediaDet* iface, if (!pVal) return E_POINTER;
- if (!This->cur_pin) + if (This->grabber || !This->cur_pin) return E_INVALIDARG;
return get_pin_media_type(This->cur_pin, pVal); @@ -672,6 +745,8 @@ static HRESULT WINAPI MediaDet_get_FrameRate(IMediaDet* iface, double *pVal)
if (!pVal) return E_POINTER; + if (This->grabber) + return E_INVALIDARG;
hr = MediaDet_get_StreamMediaType(iface, &mt); if (FAILED(hr)) @@ -693,9 +768,87 @@ static HRESULT WINAPI MediaDet_get_FrameRate(IMediaDet* iface, double *pVal) static HRESULT WINAPI MediaDet_EnterBitmapGrabMode(IMediaDet* iface, double SeekTime) { - MediaDetImpl *This = impl_from_IMediaDet(iface); - FIXME("(%p)->(%f): not implemented!\n", This, SeekTime); - return E_NOTIMPL; + MediaDetImpl *detector = impl_from_IMediaDet(iface); + IPin *sg_inpin, *sg_outpin, *null_pin; + IBaseFilter *sg_filter, *null_filter; + ISampleGrabber *sg; + AM_MEDIA_TYPE mt; + GUID major_type; + IUnknown *unk; + HRESULT hr; + + TRACE("(%p)->(%.16e)\n", detector, SeekTime); + + if (detector->grabber) + return S_OK; + if (!detector->cur_pin) + return E_INVALIDARG; + if (FAILED(hr = get_pin_media_type(detector->cur_pin, &mt))) + return hr; + major_type = mt.majortype; + FreeMediaType(&mt); + if (!IsEqualGUID(&major_type, &MEDIATYPE_Video)) + return VFW_E_INVALIDMEDIATYPE; + + hr = sample_grabber_create(NULL, &unk); + if (FAILED(hr)) return hr; + IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void**)&sg_filter); + IUnknown_Release(unk); + + hr = null_renderer_create(NULL, &unk); + if (FAILED(hr)) + { + IBaseFilter_Release(sg_filter); + return hr; + } + IUnknown_QueryInterface(unk, &IID_IBaseFilter, (void**)&null_filter); + IUnknown_Release(unk); + + memset(&mt, 0, sizeof(mt)); + mt.majortype = MEDIATYPE_Video; + mt.subtype = MEDIASUBTYPE_RGB24; + mt.formattype = FORMAT_VideoInfo; + + IBaseFilter_QueryInterface(sg_filter, &IID_ISampleGrabber, (void**)&sg); + ISampleGrabber_SetMediaType(sg, &mt); + ISampleGrabber_SetBufferSamples(sg, TRUE); + + IBaseFilter_FindPin(sg_filter, L"In", &sg_inpin); + IBaseFilter_FindPin(sg_filter, L"Out", &sg_outpin); + IBaseFilter_FindPin(null_filter, L"In", &null_pin); + + if (FAILED(hr = IGraphBuilder_AddFilter(detector->graph, sg_filter, L"BitBucket"))) + { + ISampleGrabber_Release(sg); + goto done; + } + + if (FAILED(hr = IGraphBuilder_AddFilter(detector->graph, null_filter, L"NullRenderer"))) + { + IGraphBuilder_RemoveFilter(detector->graph, sg_filter); + ISampleGrabber_Release(sg); + goto done; + } + + if (FAILED(hr = IGraphBuilder_Connect(detector->graph, detector->cur_pin, sg_inpin)) || + FAILED(hr = IGraphBuilder_ConnectDirect(detector->graph, sg_outpin, null_pin, NULL)) || + FAILED(hr = seek_graph(detector, SeekTime))) + { + IGraphBuilder_RemoveFilter(detector->graph, null_filter); + IGraphBuilder_RemoveFilter(detector->graph, sg_filter); + ISampleGrabber_Release(sg); + goto done; + } + + detector->grabber = sg; + +done: + IPin_Release(null_pin); + IPin_Release(sg_outpin); + IPin_Release(sg_inpin); + IBaseFilter_Release(null_filter); + IBaseFilter_Release(sg_filter); + return hr; }
static const IMediaDetVtbl IMediaDet_VTable = diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c index 0a05a65..71d4a4b 100644 --- a/dlls/qedit/tests/mediadet.c +++ b/dlls/qedit/tests/mediadet.c @@ -1326,7 +1326,7 @@ static void test_bitmap_grab_mode(void) ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMediaDet_EnterBitmapGrabMode(detector, 0.0); - todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); hr = IMediaDet_GetSampleGrabber(detector, &sg); todo_wine ok(hr == E_NOINTERFACE, "Got hr %#x.\n", hr);
@@ -1337,7 +1337,7 @@ static void test_bitmap_grab_mode(void) ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMediaDet_EnterBitmapGrabMode(detector, 0.0); - todo_wine ok(hr == VFW_E_INVALIDMEDIATYPE, "Got hr %#x.\n", hr); + ok(hr == VFW_E_INVALIDMEDIATYPE, "Got hr %#x.\n", hr);
ref = IMediaDet_Release(detector); ok(!ref, "Got outstanding refcount %d.\n", ref); @@ -1355,10 +1355,10 @@ static void test_bitmap_grab_mode(void) ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMediaDet_EnterBitmapGrabMode(detector, -1.0); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr); ok(testfilter.cur_pos == 0xdeadbeef, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos)); hr = IMediaDet_EnterBitmapGrabMode(detector, 1.0); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr); ok(testfilter.cur_pos == 0xdeadbeef, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
ref = IMediaDet_Release(detector); @@ -1382,11 +1382,11 @@ static void test_bitmap_grab_mode(void) hr = IMediaDet_EnterBitmapGrabMode(detector, 1337.0); if (time_formats[i] == &TIME_FORMAT_MEDIA_TIME) { - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(testfilter.cur_pos == 13370000000LL, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos)); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testfilter.cur_pos == 13370000000LL, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos)); hr = IMediaDet_EnterBitmapGrabMode(detector, 1.0); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(testfilter.cur_pos == 13370000000LL, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos)); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testfilter.cur_pos == 13370000000LL, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos)); } else ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr); @@ -1407,11 +1407,11 @@ static void test_bitmap_grab_mode(void) ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IMediaDet_EnterBitmapGrabMode(detector, 0.0); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(testfilter.cur_pos == 0, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos)); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testfilter.cur_pos == 0, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos)); hr = IMediaDet_EnterBitmapGrabMode(detector, 1.0); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(testfilter.cur_pos == 0, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos)); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testfilter.cur_pos == 0, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
/* These still work */ hr = IMediaDet_get_Filter(detector, &unk); @@ -1426,21 +1426,19 @@ static void test_bitmap_grab_mode(void)
/* These don't work anymore */ hr = IMediaDet_get_OutputStreams(detector, &count); - todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); hr = IMediaDet_get_FrameRate(detector, &duration); - todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); hr = IMediaDet_get_StreamLength(detector, &duration); - todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); hr = IMediaDet_get_StreamMediaType(detector, &mt); - todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); - if (SUCCEEDED(hr)) FreeMediaType(&mt); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); hr = IMediaDet_get_StreamType(detector, &guid); - todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); hr = IMediaDet_get_StreamTypeB(detector, &str); - todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); - if (SUCCEEDED(hr)) SysFreeString(str); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); hr = IMediaDet_put_CurrentStream(detector, 0); - todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
/* Check the SampleGrabber */ hr = IMediaDet_GetSampleGrabber(detector, &sg);