[PATCH 2/7] qedit: Implement IMediaDet::EnterBitmapGrabMode.
Zebediah Figura
zfigura at codeweavers.com
Tue Oct 20 12:11:52 CDT 2020
On 10/19/20 11:48 AM, Gabriel Ivăncescu wrote:
> Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
> ---
> dlls/qedit/mediadet.c | 191 ++++++++++++++++++++++++++++++++++--
> dlls/qedit/tests/mediadet.c | 38 ++++---
> 2 files changed, 203 insertions(+), 26 deletions(-)
>
> diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c
> index bacf520..11498bd 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);
> @@ -101,6 +104,38 @@ static HRESULT get_filter_info(IMoniker *moniker, GUID *clsid, VARIANT *var)
> return hr;
> }
>
> +static HRESULT get_first_pin(IBaseFilter *filter, PIN_DIRECTION pin_dir, IPin **out)
> +{
> + IEnumPins *pins;
> + HRESULT hr;
> + IPin *pin;
> +
> + if (FAILED(hr = IBaseFilter_EnumPins(filter, &pins)))
> + return hr;
> +
> + while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK)
> + {
> + PIN_DIRECTION dir;
> +
> + hr = IPin_QueryDirection(pin, &dir);
> + if (FAILED(hr))
> + {
> + IPin_Release(pin);
> + IEnumPins_Release(pins);
> + return hr;
> + }
> + if (dir == pin_dir)
> + {
> + *out = pin;
> + IEnumPins_Release(pins);
> + return S_OK;
> + }
> + IPin_Release(pin);
> + }
> + IEnumPins_Release(pins);
> + return E_NOTIMPL;
> +}
> +
> static HRESULT get_pin_media_type(IPin *pin, AM_MEDIA_TYPE *out)
> {
> IEnumMediaTypes *enummt;
> @@ -224,6 +259,71 @@ next:
> return hr;
> }
>
> +static HRESULT seek_source(MediaDetImpl *detector, double seek_time)
"seek_source" is a bit of a weird name for this, because you're really
seeking the graph; it's just that seeking the graph implicitly means
seeking the source.
> +{
> + 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;
Why do you need to stop the graph?
> +
> + 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;
Or pause it?
> +
> + /* 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 = (state == State_Paused) ? S_OK : E_FAIL;
Can this even happen?
> +done:
I don't think that labels are generally worthwhile, not when there's
only one line of cleanup.
> + IMediaControl_Release(mc);
> + return hr;
> +}
> +
> /* MediaDet inner IUnknown */
> static HRESULT WINAPI MediaDet_inner_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
> {
> @@ -371,7 +471,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 +566,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 +598,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 +638,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 +752,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 +777,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 +800,81 @@ 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;
> + HRESULT hr;
> +
> + TRACE("(%p)->(%f)\n", detector, SeekTime);
Use "%.16e" for doubles, please; we'd like to keep full precision.
> +
> + 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;
Can this be tested?
> +
> + hr = CoCreateInstance(&CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,
> + &IID_IBaseFilter, (void**)&sg_filter);
I'd be more than a little tempted ot use sample_grabber_create()
directly, bypassing COM overhead...
> + if (FAILED(hr)) return hr;
> +
> + if (FAILED(hr = IBaseFilter_QueryInterface(sg_filter, &IID_ISampleGrabber, (void**)&sg)))
> + {
> + IBaseFilter_Release(sg_filter);
> + return hr;
> + }
> +
> + memset(&mt, 0, sizeof(mt));
> + mt.majortype = MEDIATYPE_Video;
> + mt.subtype = MEDIASUBTYPE_RGB24;
> + mt.formattype = FORMAT_VideoInfo;
> + if (FAILED(hr = ISampleGrabber_SetMediaType(sg, &mt)) ||
> + FAILED(hr = CoCreateInstance(&CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER,
> + &IID_IBaseFilter, (void**)&null_filter)))
And the same here...
> + {
> + ISampleGrabber_Release(sg);
> + IBaseFilter_Release(sg_filter);
> + return hr;
> + }
> + ISampleGrabber_SetBufferSamples(sg, TRUE);
> +
> + sg_inpin = sg_outpin = null_pin = NULL;
> + if (FAILED(hr = get_first_pin(sg_filter, PINDIR_INPUT, &sg_inpin))) goto err;
> + if (FAILED(hr = get_first_pin(sg_filter, PINDIR_OUTPUT, &sg_outpin))) goto err;
> + if (FAILED(hr = get_first_pin(null_filter, PINDIR_INPUT, &null_pin))) goto err;
IBaseFilter::FindPin() would be simpler. Also, it's our code; the calls
shouldn't fail, which means at best they deserve an assert().
> +
> + if (SUCCEEDED(hr = IGraphBuilder_AddFilter(detector->graph, sg_filter, L"BitBucket")))
> + {
I would probably stick with FAILED() error handling here (i.e. reverse
it); it's consistent with the above and it keeps the indentation level low.
> + if (SUCCEEDED(hr = IGraphBuilder_AddFilter(detector->graph, null_filter, L"NullRenderer")))
> + {
> + if (SUCCEEDED(hr = IGraphBuilder_Connect(detector->graph, detector->cur_pin, sg_inpin)) &&
> + SUCCEEDED(hr = IGraphBuilder_Connect(detector->graph, sg_outpin, null_pin)) &&
At least the latter can be ConnectDirect().
> + SUCCEEDED(hr = seek_source(detector, SeekTime)))
> + {
> + detector->grabber = sg;
> + goto done;
> + }
> + IGraphBuilder_RemoveFilter(detector->graph, null_filter);
> + }
> + IGraphBuilder_RemoveFilter(detector->graph, sg_filter);
> + }
> +
> +err:
> + ISampleGrabber_Release(sg);
> +done:
> + if (null_pin) IPin_Release(null_pin);
> + if (sg_outpin) IPin_Release(sg_outpin);
> + if (sg_inpin) 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 010b746..afad173 100644
> --- a/dlls/qedit/tests/mediadet.c
> +++ b/dlls/qedit/tests/mediadet.c
> @@ -1335,7 +1335,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);
>
> /* EnterBitmapGrabMode only seeks once, and if SeekTime is non-negative */
> testfilter_init(&testfilter);
> @@ -1344,10 +1344,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);
> @@ -1371,11 +1371,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);
> @@ -1396,11 +1396,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);
> @@ -1415,21 +1415,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);
>
> /* Changing filter resets bitmap grab mode */
> testfilter.bitmap_grab_mode = FALSE;
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20201020/7542e19f/attachment-0001.sig>
More information about the wine-devel
mailing list