Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qasf/dmowrapper.c | 247 +++++++++++++++++++++++- dlls/qasf/tests/dmowrapper.c | 365 +++++++++++++++++++++++++++++++++-- include/mediaobj.idl | 17 ++ 3 files changed, 609 insertions(+), 20 deletions(-)
diff --git a/dlls/qasf/dmowrapper.c b/dlls/qasf/dmowrapper.c index 9480d3b95bb..41fe34cf1ed 100644 --- a/dlls/qasf/dmowrapper.c +++ b/dlls/qasf/dmowrapper.c @@ -22,9 +22,16 @@
WINE_DEFAULT_DEBUG_CHANNEL(qasf);
+struct buffer +{ + IMediaBuffer IMediaBuffer_iface; + IMediaSample *sample; +}; + struct dmo_wrapper_source { struct strmbase_source pin; + struct buffer buffer; };
struct dmo_wrapper @@ -37,6 +44,80 @@ struct dmo_wrapper DWORD sink_count, source_count; struct strmbase_sink *sinks; struct dmo_wrapper_source *sources; + DMO_OUTPUT_DATA_BUFFER *buffers; + struct buffer input_buffer; +}; + +static struct buffer *impl_from_IMediaBuffer(IMediaBuffer *iface) +{ + return CONTAINING_RECORD(iface, struct buffer, IMediaBuffer_iface); +} + +static HRESULT WINAPI buffer_QueryInterface(IMediaBuffer *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IMediaBuffer)) + { + IMediaBuffer_AddRef(iface); + *out = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI buffer_AddRef(IMediaBuffer *iface) +{ + TRACE("iface %p.\n", iface); + return 2; +} + +static ULONG WINAPI buffer_Release(IMediaBuffer *iface) +{ + TRACE("iface %p.\n", iface); + return 1; +} + +static HRESULT WINAPI buffer_SetLength(IMediaBuffer *iface, DWORD len) +{ + struct buffer *buffer = impl_from_IMediaBuffer(iface); + + TRACE("iface %p, len %u.\n", iface, len); + + return IMediaSample_SetActualDataLength(buffer->sample, len); +} + +static HRESULT WINAPI buffer_GetMaxLength(IMediaBuffer *iface, DWORD *len) +{ + struct buffer *buffer = impl_from_IMediaBuffer(iface); + + TRACE("iface %p, len %p.\n", iface, len); + + *len = IMediaSample_GetSize(buffer->sample); + return S_OK; +} + +static HRESULT WINAPI buffer_GetBufferAndLength(IMediaBuffer *iface, BYTE **data, DWORD *len) +{ + struct buffer *buffer = impl_from_IMediaBuffer(iface); + + TRACE("iface %p, data %p, len %p.\n", iface, data, len); + + *len = IMediaSample_GetActualDataLength(buffer->sample); + return IMediaSample_GetPointer(buffer->sample, data); +} + +static const IMediaBufferVtbl buffer_vtbl = +{ + buffer_QueryInterface, + buffer_AddRef, + buffer_Release, + buffer_SetLength, + buffer_GetMaxLength, + buffer_GetBufferAndLength, };
static inline struct dmo_wrapper *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -120,6 +201,140 @@ static void dmo_wrapper_sink_disconnect(struct strmbase_sink *iface) IMediaObject_Release(dmo); }
+static HRESULT process_output(struct dmo_wrapper *filter, IMediaObject *dmo) +{ + DMO_OUTPUT_DATA_BUFFER *buffers = filter->buffers; + DWORD status, i; + BOOL more_data; + HRESULT hr; + + for (i = 0; i < filter->source_count; ++i) + { + if (filter->sources[i].pin.pin.peer) + { + if (FAILED(hr = IMemAllocator_GetBuffer(filter->sources[i].pin.pAllocator, + &filter->sources[i].buffer.sample, NULL, NULL, 0))) + { + ERR("Failed to get sample, hr %#x.\n", hr); + goto out; + } + buffers[i].pBuffer = &filter->sources[i].buffer.IMediaBuffer_iface; + IMediaSample_SetActualDataLength(filter->sources[i].buffer.sample, 0); + } + else + buffers[i].pBuffer = NULL; + } + + do + { + more_data = FALSE; + + hr = IMediaObject_ProcessOutput(dmo, DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER, + filter->source_count, buffers, &status); + if (hr != S_OK) + break; + + for (i = 0; i < filter->source_count; ++i) + { + IMediaSample *sample = filter->sources[i].buffer.sample; + + if (!buffers[i].pBuffer) + continue; + + if (buffers[i].dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE) + more_data = TRUE; + + if (buffers[i].dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIME) + { + if (buffers[i].dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH) + { + REFERENCE_TIME stop = buffers[i].rtTimestamp + buffers[i].rtTimelength; + IMediaSample_SetTime(sample, &buffers[i].rtTimestamp, &stop); + } + else + IMediaSample_SetTime(sample, &buffers[i].rtTimestamp, NULL); + } + + if (buffers[i].dwStatus & DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT) + IMediaSample_SetSyncPoint(sample, TRUE); + + if (IMediaSample_GetActualDataLength(sample)) + { + if (FAILED(hr = IMemInputPin_Receive(filter->sources[i].pin.pMemInputPin, sample))) + { + WARN("Downstream sink returned %#x.\n", hr); + goto out; + } + IMediaSample_SetActualDataLength(sample, 0); + } + + } + } while (more_data); + +out: + for (i = 0; i < filter->source_count; ++i) + { + if (filter->sources[i].buffer.sample) + { + IMediaSample_Release(filter->sources[i].buffer.sample); + filter->sources[i].buffer.sample = NULL; + } + } + + return hr; +} + +static HRESULT WINAPI dmo_wrapper_sink_Receive(struct strmbase_sink *iface, IMediaSample *sample) +{ + struct dmo_wrapper *filter = impl_from_strmbase_filter(iface->pin.filter); + DWORD index = iface - filter->sinks; + REFERENCE_TIME start = 0, stop = 0; + IMediaObject *dmo; + DWORD flags = 0; + HRESULT hr; + + IUnknown_QueryInterface(filter->dmo, &IID_IMediaObject, (void **)&dmo); + + if (IMediaSample_IsDiscontinuity(sample) == S_OK) + { + if (FAILED(hr = IMediaObject_Discontinuity(dmo, index))) + { + ERR("Discontinuity() failed, hr %#x.\n", hr); + goto out; + } + + /* Calling Discontinuity() might change the DMO's mind about whether it + * has more data to process. The DirectX documentation explicitly + * states that we should call ProcessOutput() again in this case. */ + process_output(filter, dmo); + } + + if (IMediaSample_IsSyncPoint(sample) == S_OK) + flags |= DMO_INPUT_DATA_BUFFERF_SYNCPOINT; + + if (SUCCEEDED(hr = IMediaSample_GetTime(sample, &start, &stop))) + { + flags |= DMO_INPUT_DATA_BUFFERF_TIME | DMO_INPUT_DATA_BUFFERF_TIMELENGTH; + if (hr == VFW_S_NO_STOP_TIME) + stop = start + 1; + } + + filter->input_buffer.sample = sample; + if (FAILED(hr = IMediaObject_ProcessInput(dmo, index, + &filter->input_buffer.IMediaBuffer_iface, flags, start, stop - start))) + { + ERR("ProcessInput() failed, hr %#x.\n", hr); + goto out; + } + + process_output(filter, dmo); + +out: + filter->input_buffer.sample = NULL; + IMediaObject_Release(dmo); + return hr; +} + static const struct strmbase_sink_ops sink_ops = { .base.pin_query_interface = dmo_wrapper_sink_query_interface, @@ -127,6 +342,7 @@ static const struct strmbase_sink_ops sink_ops = .base.pin_get_media_type = dmo_wrapper_sink_get_media_type, .sink_connect = dmo_wrapper_sink_connect, .sink_disconnect = dmo_wrapper_sink_disconnect, + .pfnReceive = dmo_wrapper_sink_Receive, };
static inline struct dmo_wrapper_source *impl_source_from_strmbase_pin(struct strmbase_pin *iface) @@ -245,6 +461,7 @@ static HRESULT WINAPI dmo_wrapper_filter_Init(IDMOWrapperFilter *iface, REFCLSID { struct dmo_wrapper *filter = impl_from_IDMOWrapperFilter(iface); struct dmo_wrapper_source *sources; + DMO_OUTPUT_DATA_BUFFER *buffers; DWORD input_count, output_count; struct strmbase_sink *sinks; IMediaObject *dmo; @@ -270,10 +487,12 @@ static HRESULT WINAPI dmo_wrapper_filter_Init(IDMOWrapperFilter *iface, REFCLSID
sinks = calloc(sizeof(*sinks), input_count); sources = calloc(sizeof(*sources), output_count); - if (!sinks || !sources) + buffers = calloc(sizeof(*buffers), output_count); + if (!sinks || !sources || !buffers) { free(sinks); free(sources); + free(buffers); IMediaObject_Release(dmo); IUnknown_Release(unk); return hr; @@ -289,6 +508,7 @@ static HRESULT WINAPI dmo_wrapper_filter_Init(IDMOWrapperFilter *iface, REFCLSID { swprintf(id, ARRAY_SIZE(id), L"out%u", i); strmbase_source_init(&sources[i].pin, &filter->filter, id, &source_ops); + sources[i].buffer.IMediaBuffer_iface.lpVtbl = &buffer_vtbl; }
EnterCriticalSection(&filter->filter.csFilter); @@ -298,6 +518,7 @@ static HRESULT WINAPI dmo_wrapper_filter_Init(IDMOWrapperFilter *iface, REFCLSID filter->source_count = output_count; filter->sinks = sinks; filter->sources = sources; + filter->buffers = buffers;
LeaveCriticalSection(&filter->filter.csFilter);
@@ -358,13 +579,34 @@ static HRESULT dmo_wrapper_query_interface(struct strmbase_filter *iface, REFIID return E_NOINTERFACE; }
+static HRESULT dmo_wrapper_init_stream(struct strmbase_filter *iface) +{ + struct dmo_wrapper *filter = impl_from_strmbase_filter(iface); + DWORD i; + + for (i = 0; i < filter->source_count; ++i) + { + if (filter->sources[i].pin.pin.peer) + IMemAllocator_Commit(filter->sources[i].pin.pAllocator); + } + + return S_OK; +} + static HRESULT dmo_wrapper_cleanup_stream(struct strmbase_filter *iface) { struct dmo_wrapper *filter = impl_from_strmbase_filter(iface); IMediaObject *dmo; + DWORD i;
IUnknown_QueryInterface(filter->dmo, &IID_IMediaObject, (void **)&dmo);
+ for (i = 0; i < filter->source_count; ++i) + { + if (filter->sources[i].pin.pin.peer) + IMemAllocator_Decommit(filter->sources[i].pin.pAllocator); + } + IMediaObject_Flush(dmo);
IMediaObject_Release(dmo); @@ -376,6 +618,7 @@ static struct strmbase_filter_ops filter_ops = .filter_get_pin = dmo_wrapper_get_pin, .filter_destroy = dmo_wrapper_destroy, .filter_query_interface = dmo_wrapper_query_interface, + .filter_init_stream = dmo_wrapper_init_stream, .filter_cleanup_stream = dmo_wrapper_cleanup_stream, };
@@ -391,6 +634,8 @@ HRESULT dmo_wrapper_create(IUnknown *outer, IUnknown **out)
object->IDMOWrapperFilter_iface.lpVtbl = &dmo_wrapper_filter_vtbl;
+ object->input_buffer.IMediaBuffer_iface.lpVtbl = &buffer_vtbl; + TRACE("Created DMO wrapper %p.\n", object); *out = &object->filter.IUnknown_inner;
diff --git a/dlls/qasf/tests/dmowrapper.c b/dlls/qasf/tests/dmowrapper.c index 42d3a4f0e0e..00ca09de2e7 100644 --- a/dlls/qasf/tests/dmowrapper.c +++ b/dlls/qasf/tests/dmowrapper.c @@ -56,6 +56,13 @@ static inline BOOL compare_media_types(const AM_MEDIA_TYPE *a, const AM_MEDIA_TY && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat); }
+static ULONG get_refcount(void *iface) +{ + IUnknown *unknown = iface; + IUnknown_AddRef(unknown); + return IUnknown_Release(unknown); +} + static const IMediaObjectVtbl dmo_vtbl;
static IMediaObject testdmo = {&dmo_vtbl}; @@ -69,7 +76,11 @@ static HRESULT testdmo_GetOutputSizeInfo_hr = S_OK; static DWORD testdmo_output_size = 123; static DWORD testdmo_output_alignment = 1;
-static unsigned int got_Flush; +static unsigned int got_Flush, got_Discontinuity, got_ProcessInput, got_ProcessOutput, got_Receive; + +static IMediaBuffer *testdmo_buffer; + +static int testmode;
static HRESULT WINAPI dmo_inner_QueryInterface(IUnknown *iface, REFIID iid, void **out) { @@ -249,8 +260,9 @@ static HRESULT WINAPI dmo_Flush(IMediaObject *iface)
static HRESULT WINAPI dmo_Discontinuity(IMediaObject *iface, DWORD index) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + if (winetest_debug > 1) trace("Discontinuity(index %u)\n", index); + ++got_Discontinuity; + return S_OK; }
static HRESULT WINAPI dmo_AllocateStreamingResources(IMediaObject *iface) @@ -267,22 +279,132 @@ static HRESULT WINAPI dmo_FreeStreamingResources(IMediaObject *iface)
static HRESULT WINAPI dmo_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + if (winetest_debug > 1) trace("GetInputStatus(index %u)\n", index); + *flags = DMO_INPUT_STATUSF_ACCEPT_DATA; + return S_OK; }
static HRESULT WINAPI dmo_ProcessInput(IMediaObject *iface, DWORD index, IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + BYTE *data, expect[200]; + DWORD len, i; + HRESULT hr; + + if (winetest_debug > 1) trace("ProcessInput(index %u, flags %#x, timestamp %I64d, timelength %I64d)\n", + index, flags, timestamp, timelength); + + ++got_ProcessInput; + + hr = IMediaBuffer_GetBufferAndLength(buffer, &data, &len); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(len == 200, "Got length %u.\n", len); + for (i = 0; i < 200; ++i) + expect[i] = i; + ok(!memcmp(data, expect, 200), "Data didn't match.\n"); + + hr = IMediaBuffer_GetMaxLength(buffer, &len); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(len == 256, "Got length %u.\n", len); + + if (testmode == 0) + { + ok(!flags, "Got flags %#x.\n", flags); + ok(!timestamp, "Got timestamp %s.\n", wine_dbgstr_longlong(timestamp)); + ok(!timelength, "Got length %s.\n", wine_dbgstr_longlong(timelength)); + } + else if (testmode == 1) + { + ok(flags == (DMO_INPUT_DATA_BUFFERF_TIME | DMO_INPUT_DATA_BUFFERF_TIMELENGTH), "Got flags %#x.\n", flags); + ok(timestamp == 20000, "Got timestamp %s.\n", wine_dbgstr_longlong(timestamp)); + ok(timelength == 1, "Got length %s.\n", wine_dbgstr_longlong(timelength)); + } + else if (testmode == 6) + { + ok(flags == (DMO_INPUT_DATA_BUFFERF_TIME | DMO_INPUT_DATA_BUFFERF_TIMELENGTH + | DMO_INPUT_DATA_BUFFERF_SYNCPOINT), "Got flags %#x.\n", flags); + ok(timestamp == 20000, "Got timestamp %s.\n", wine_dbgstr_longlong(timestamp)); + ok(timelength == 10000, "Got length %s.\n", wine_dbgstr_longlong(timelength)); + } + else + { + ok(flags == (DMO_INPUT_DATA_BUFFERF_TIME | DMO_INPUT_DATA_BUFFERF_TIMELENGTH), "Got flags %#x.\n", flags); + ok(timestamp == 20000, "Got timestamp %s.\n", wine_dbgstr_longlong(timestamp)); + ok(timelength == 10000, "Got length %s.\n", wine_dbgstr_longlong(timelength)); + } + + testdmo_buffer = buffer; + IMediaBuffer_AddRef(buffer); + + return S_OK; }
static HRESULT WINAPI dmo_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count, DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + DWORD len, i; + HRESULT hr; + BYTE *data; + + if (winetest_debug > 1) trace("ProcessOutput(flags %#x, count %u)\n", flags, count); + + ++got_ProcessOutput; + + *status = 0; + + ok(flags == DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER, "Got flags %#x.\n", flags); + ok(count == 2, "Got count %u.\n", count); + + ok(!!buffers[0].pBuffer, "Expected a buffer.\n"); + ok(!buffers[1].pBuffer, "Got unexpected buffer %p.\n", buffers[1].pBuffer); + + buffers[1].dwStatus = DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE; + + hr = IMediaBuffer_GetBufferAndLength(buffers[0].pBuffer, &data, &len); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!len, "Got length %u.\n", len); + + hr = IMediaBuffer_GetMaxLength(buffers[0].pBuffer, &len); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(len == 16384, "Got length %u.\n", len); + + buffers[0].dwStatus = DMO_OUTPUT_DATA_BUFFERF_TIME | DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH; + buffers[0].rtTimelength = 1000; + buffers[0].rtTimestamp = 5000; + + if (testmode == 3) + { + hr = IMediaBuffer_SetLength(buffers[0].pBuffer, 16200); + ok(hr == S_OK, "Got hr %#x.\n", hr); + buffers[0].dwStatus |= DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE; + return S_OK; + } + else if (testmode == 5) + { + hr = IMediaBuffer_SetLength(buffers[0].pBuffer, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IMediaBuffer_Release(testdmo_buffer); + return S_FALSE; + } + else + { + if (testmode == 7) + buffers[0].dwStatus |= DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT; + else if (testmode == 8) + buffers[0].dwStatus = DMO_OUTPUT_DATA_BUFFERF_TIME; + else if (testmode == 9) + buffers[0].dwStatus = 0; + + for (i = 0; i < 300; ++i) + data[i] = 111 - i; + hr = IMediaBuffer_SetLength(buffers[0].pBuffer, 300); + ok(hr == S_OK, "Got hr %#x.\n", hr); + if (testmode != 10) + IMediaBuffer_Release(testdmo_buffer); + return S_OK; + } + + return S_OK; }
static HRESULT WINAPI dmo_Lock(IMediaObject *iface, LONG lock) @@ -384,13 +506,6 @@ static IBaseFilter *create_dmo_wrapper(void) return filter; }
-static ULONG get_refcount(void *iface) -{ - IUnknown *unknown = iface; - IUnknown_AddRef(unknown); - return IUnknown_Release(unknown); -} - #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) { @@ -1077,6 +1192,61 @@ static HRESULT testsink_get_media_type(struct strmbase_pin *iface, unsigned int
static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample *sample) { + REFERENCE_TIME start, stop; + LONG len, i; + HRESULT hr; + + ++got_Receive; + + len = IMediaSample_GetSize(sample); + ok(len == 16384, "Got size %u.\n", len); + len = IMediaSample_GetActualDataLength(sample); + if (testmode == 3) + ok(len == 16200, "Got length %u.\n", len); + else + { + BYTE *data, expect[300]; + + ok(len == 300, "Got length %u.\n", len); + + hr = IMediaSample_GetPointer(sample, &data); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + for (i = 0; i < 300; ++i) + expect[i] = 111 - i; + ok(!memcmp(data, expect, 300), "Data didn't match.\n"); + } + + hr = IMediaSample_GetTime(sample, &start, &stop); + if (testmode == 8) + { + ok(hr == VFW_S_NO_STOP_TIME, "Got hr %#x.\n", hr); + ok(start == 5000, "Got start time %s.\n", wine_dbgstr_longlong(start)); + } + else if (testmode == 9) + ok(hr == VFW_E_SAMPLE_TIME_NOT_SET, "Got hr %#x.\n", hr); + else + { + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(start == 5000, "Got start time %s.\n", wine_dbgstr_longlong(start)); + ok(stop == 6000, "Got stop time %s.\n", wine_dbgstr_longlong(stop)); + } + + hr = IMediaSample_GetMediaTime(sample, &start, &stop); + ok(hr == VFW_E_MEDIA_TIME_NOT_SET, "Got hr %#x.\n", hr); + + hr = IMediaSample_IsDiscontinuity(sample); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + hr = IMediaSample_IsPreroll(sample); + ok(hr == S_FALSE, "Got hr %#x.\n", hr); + hr = IMediaSample_IsSyncPoint(sample); + ok(hr == (testmode == 7 ? S_OK : S_FALSE), "Got hr %#x.\n", hr); + + if (testmode == 3) + testmode = 4; + if (testmode == 10) + testmode = 11; + return S_OK; }
@@ -1100,7 +1270,7 @@ static void testfilter_init(struct testfilter *filter) static void test_sink_allocator(IMemInputPin *input) { IMemAllocator *req_allocator, *ret_allocator; - ALLOCATOR_PROPERTIES props; + ALLOCATOR_PROPERTIES props, ret_props; HRESULT hr;
hr = IMemInputPin_GetAllocatorRequirements(input, &props); @@ -1141,6 +1311,13 @@ static void test_sink_allocator(IMemInputPin *input) CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (void **)&req_allocator);
+ props.cBuffers = 1; + props.cbBuffer = 256; + props.cbAlign = 1; + props.cbPrefix = 0; + hr = IMemAllocator_SetProperties(req_allocator, &props, &ret_props); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMemInputPin_NotifyAllocator(input, req_allocator, TRUE); ok(hr == S_OK, "Got hr %#x.\n", hr);
@@ -1275,6 +1452,155 @@ static void test_filter_state(IMediaControl *control) ok(state == State_Stopped, "Got state %u.\n", state); }
+static void test_sample_processing(IMediaControl *control, IMemInputPin *input) +{ + REFERENCE_TIME start, stop; + IMemAllocator *allocator; + IMediaSample *sample; + LONG size, i; + HRESULT hr; + BYTE *data; + + hr = IMemInputPin_ReceiveCanBlock(input); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemInputPin_GetAllocator(input, &allocator); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMediaControl_Pause(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0); + ok(hr == VFW_E_NOT_COMMITTED, "Got hr %#x.\n", hr); + + hr = IMemAllocator_Commit(allocator); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IMediaSample_GetPointer(sample, &data); + ok(hr == S_OK, "Got hr %#x.\n", hr); + size = IMediaSample_GetSize(sample); + ok(size == 256, "Got size %d.\n", size); + for (i = 0; i < 200; ++i) + data[i] = i; + hr = IMediaSample_SetActualDataLength(sample, 200); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + start = 10000; + stop = 20000; + hr = IMediaSample_SetMediaTime(sample, &start, &stop); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaSample_SetPreroll(sample, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + testmode = 0; + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(got_ProcessInput == 1, "Got %u calls to ProcessInput().\n", got_ProcessInput); + ok(got_ProcessOutput == 1, "Got %u calls to ProcessOutput().\n", got_ProcessOutput); + ok(got_Receive == 1, "Got %u calls to Receive().\n", got_Receive); + got_ProcessInput = got_ProcessOutput = got_Receive = 0; + + start = 20000; + hr = IMediaSample_SetTime(sample, &start, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + testmode = 1; + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(got_ProcessInput == 1, "Got %u calls to ProcessInput().\n", got_ProcessInput); + ok(got_ProcessOutput == 1, "Got %u calls to ProcessOutput().\n", got_ProcessOutput); + ok(got_Receive == 1, "Got %u calls to Receive().\n", got_Receive); + got_ProcessInput = got_ProcessOutput = got_Receive = 0; + + stop = 30000; + hr = IMediaSample_SetTime(sample, &start, &stop); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + testmode = 2; + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(got_ProcessInput == 1, "Got %u calls to ProcessInput().\n", got_ProcessInput); + ok(got_ProcessOutput == 1, "Got %u calls to ProcessOutput().\n", got_ProcessOutput); + ok(got_Receive == 1, "Got %u calls to Receive().\n", got_Receive); + got_ProcessInput = got_ProcessOutput = got_Receive = 0; + + testmode = 3; + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(got_ProcessInput == 1, "Got %u calls to ProcessInput().\n", got_ProcessInput); + ok(got_ProcessOutput == 2, "Got %u calls to ProcessOutput().\n", got_ProcessOutput); + ok(got_Receive == 2, "Got %u calls to Receive().\n", got_Receive); + got_ProcessInput = got_ProcessOutput = got_Receive = 0; + + testmode = 5; + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(got_ProcessInput == 1, "Got %u calls to ProcessInput().\n", got_ProcessInput); + ok(got_ProcessOutput == 1, "Got %u calls to ProcessOutput().\n", got_ProcessOutput); + ok(!got_Receive, "Got %u calls to Receive().\n", got_Receive); + got_ProcessInput = got_ProcessOutput = got_Receive = 0; + + hr = IMediaSample_SetSyncPoint(sample, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + testmode = 6; + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(got_ProcessInput == 1, "Got %u calls to ProcessInput().\n", got_ProcessInput); + ok(got_ProcessOutput == 1, "Got %u calls to ProcessOutput().\n", got_ProcessOutput); + ok(got_Receive == 1, "Got %u calls to Receive().\n", got_Receive); + got_ProcessInput = got_ProcessOutput = got_Receive = 0; + + hr = IMediaSample_SetSyncPoint(sample, FALSE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + testmode = 7; + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(got_ProcessInput == 1, "Got %u calls to ProcessInput().\n", got_ProcessInput); + ok(got_ProcessOutput == 1, "Got %u calls to ProcessOutput().\n", got_ProcessOutput); + ok(got_Receive == 1, "Got %u calls to Receive().\n", got_Receive); + got_ProcessInput = got_ProcessOutput = got_Receive = 0; + + testmode = 8; + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(got_ProcessInput == 1, "Got %u calls to ProcessInput().\n", got_ProcessInput); + ok(got_ProcessOutput == 1, "Got %u calls to ProcessOutput().\n", got_ProcessOutput); + ok(got_Receive == 1, "Got %u calls to Receive().\n", got_Receive); + got_ProcessInput = got_ProcessOutput = got_Receive = 0; + + testmode = 9; + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(got_ProcessInput == 1, "Got %u calls to ProcessInput().\n", got_ProcessInput); + ok(got_ProcessOutput == 1, "Got %u calls to ProcessOutput().\n", got_ProcessOutput); + ok(got_Receive == 1, "Got %u calls to Receive().\n", got_Receive); + got_ProcessInput = got_ProcessOutput = got_Receive = 0; + + hr = IMediaSample_SetDiscontinuity(sample, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ok(!got_Discontinuity, "Got %u calls to Discontinuity().\n", got_Discontinuity); + testmode = 10; + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(got_ProcessInput == 1, "Got %u calls to ProcessInput().\n", got_ProcessInput); + ok(got_ProcessOutput == 2, "Got %u calls to ProcessOutput().\n", got_ProcessOutput); + ok(got_Receive == 2, "Got %u calls to Receive().\n", got_Receive); + ok(got_Discontinuity == 1, "Got %u calls to Discontinuity().\n", got_Discontinuity); + got_ProcessInput = got_ProcessOutput = got_Receive = 0; + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + IMediaSample_Release(sample); + IMemAllocator_Release(allocator); +} + static void test_connect_pin(void) { AM_MEDIA_TYPE req_mt = @@ -1366,6 +1692,9 @@ static void test_connect_pin(void) ok(testdmo_output_mt_set, "Ouput type should be set.\n"); ok(compare_media_types(&testdmo_output_mt, &req_mt), "Media types didn't match.\n");
+ test_filter_state(control); + test_sample_processing(control, meminput); + hr = IFilterGraph2_Disconnect(graph, source); ok(hr == S_OK, "Got hr %#x.\n", hr); hr = IFilterGraph2_Disconnect(graph, source); @@ -1383,8 +1712,6 @@ static void test_connect_pin(void)
ok(!testdmo_output_mt_set, "Output type should not be set.\n");
- test_filter_state(control); - req_mt.lSampleSize = 0; hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); diff --git a/include/mediaobj.idl b/include/mediaobj.idl index 793e1bcf8e0..4c2e4963174 100644 --- a/include/mediaobj.idl +++ b/include/mediaobj.idl @@ -87,6 +87,23 @@ interface IMediaBuffer : IUnknown ); }
+enum _DMO_INPUT_STATUS_FLAGS +{ + DMO_INPUT_STATUSF_ACCEPT_DATA = 0x00000001, +}; + +enum _DMO_INPUT_DATA_BUFFER_FLAGS +{ + DMO_INPUT_DATA_BUFFERF_SYNCPOINT = 0x00000001, + DMO_INPUT_DATA_BUFFERF_TIME = 0x00000002, + DMO_INPUT_DATA_BUFFERF_TIMELENGTH = 0x00000004, +}; + +enum _DMO_PROCESS_OUTPUT_FLAGS +{ + DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER = 0x00000001, +}; + typedef struct _DMO_OUTPUT_DATA_BUFFER { IMediaBuffer *pBuffer; DWORD dwStatus;
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qasf/tests/dmowrapper.c | 53 ++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/dlls/qasf/tests/dmowrapper.c b/dlls/qasf/tests/dmowrapper.c index 00ca09de2e7..5dcc75d555c 100644 --- a/dlls/qasf/tests/dmowrapper.c +++ b/dlls/qasf/tests/dmowrapper.c @@ -1108,6 +1108,7 @@ struct testfilter struct strmbase_source source; struct strmbase_sink sink; const AM_MEDIA_TYPE *sink_mt; + unsigned int got_new_segment; };
static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -1250,12 +1251,24 @@ static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample return S_OK; }
+static HRESULT testsink_new_segment(struct strmbase_sink *iface, + REFERENCE_TIME start, REFERENCE_TIME stop, double rate) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + ++filter->got_new_segment; + ok(start == 10000, "Got start %s.\n", wine_dbgstr_longlong(start)); + ok(stop == 20000, "Got stop %s.\n", wine_dbgstr_longlong(stop)); + ok(rate == 1.0, "Got rate %.16e.\n", rate); + return 0xdeadbeef; +} + static const struct strmbase_sink_ops testsink_ops = { .base.pin_query_interface = testsink_query_interface, .base.pin_query_accept = testsink_query_accept, .base.pin_get_media_type = testsink_get_media_type, .pfnReceive = testsink_Receive, + .sink_new_segment = testsink_new_segment, };
static void testfilter_init(struct testfilter *filter) @@ -1601,6 +1614,25 @@ static void test_sample_processing(IMediaControl *control, IMemInputPin *input) IMemAllocator_Release(allocator); }
+static void test_streaming_events(IMediaControl *control, IPin *sink, IMemInputPin *input, + struct testfilter *testsink, struct testfilter *testsink2) +{ + HRESULT hr; + + hr = IMediaControl_Pause(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ok(!testsink->got_new_segment, "Got %u calls to IPin::NewSegment().\n", testsink->got_new_segment); + ok(!testsink2->got_new_segment, "Got %u calls to IPin::NewSegment().\n", testsink2->got_new_segment); + hr = IPin_NewSegment(sink, 10000, 20000, 1.0); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testsink->got_new_segment == 1, "Got %u calls to IPin::NewSegment().\n", testsink->got_new_segment); + ok(testsink2->got_new_segment == 1, "Got %u calls to IPin::NewSegment().\n", testsink2->got_new_segment); + + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#x.\n", hr); +} + static void test_connect_pin(void) { AM_MEDIA_TYPE req_mt = @@ -1609,9 +1641,9 @@ static void test_connect_pin(void) .subtype = MEDIASUBTYPE_Avi, .formattype = FORMAT_None, }; + struct testfilter testsource, testsink, testsink2; IBaseFilter *filter = create_dmo_wrapper(); - struct testfilter testsource, testsink; - IPin *sink, *source, *peer; + IPin *sink, *source, *source2, *peer; IMediaControl *control; IMemInputPin *meminput; IFilterGraph2 *graph; @@ -1621,14 +1653,17 @@ static void test_connect_pin(void)
testfilter_init(&testsource); testfilter_init(&testsink); + testfilter_init(&testsink2); CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IFilterGraph2, (void **)&graph); IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control); IFilterGraph2_AddFilter(graph, &testsource.filter.IBaseFilter_iface, L"source"); IFilterGraph2_AddFilter(graph, &testsink.filter.IBaseFilter_iface, L"sink"); + IFilterGraph2_AddFilter(graph, &testsink2.filter.IBaseFilter_iface, L"sink2"); IFilterGraph2_AddFilter(graph, filter, L"DMO wrapper"); IBaseFilter_FindPin(filter, L"in0", &sink); IBaseFilter_FindPin(filter, L"out0", &source); + IBaseFilter_FindPin(filter, L"out1", &source2); IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&meminput);
/* Test sink connection. */ @@ -1695,6 +1730,17 @@ static void test_connect_pin(void) test_filter_state(control); test_sample_processing(control, meminput);
+ /* Streaming event tests are more interesting if multiple source pins are + * connected. */ + + hr = IFilterGraph2_ConnectDirect(graph, source2, &testsink2.sink.pin.IPin_iface, &req_mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + test_streaming_events(control, sink, meminput, &testsink, &testsink2); + + IFilterGraph2_Disconnect(graph, source2); + IFilterGraph2_Disconnect(graph, &testsink2.sink.pin.IPin_iface); + hr = IFilterGraph2_Disconnect(graph, source); ok(hr == S_OK, "Got hr %#x.\n", hr); hr = IFilterGraph2_Disconnect(graph, source); @@ -1830,6 +1876,7 @@ static void test_connect_pin(void)
IPin_Release(sink); IPin_Release(source); + IPin_Release(source2); IMemInputPin_Release(meminput); IMediaControl_Release(control); ref = IFilterGraph2_Release(graph); @@ -1840,6 +1887,8 @@ static void test_connect_pin(void) ok(!ref, "Got outstanding refcount %d.\n", ref); ref = IBaseFilter_Release(&testsink.filter.IBaseFilter_iface); ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IBaseFilter_Release(&testsink2.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %d.\n", ref); }
START_TEST(dmowrapper)
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qasf/dmowrapper.c | 27 +++++++++++ dlls/qasf/tests/dmowrapper.c | 88 +++++++++++++++++++++++++++++++----- 2 files changed, 104 insertions(+), 11 deletions(-)
diff --git a/dlls/qasf/dmowrapper.c b/dlls/qasf/dmowrapper.c index 41fe34cf1ed..9e0a178542a 100644 --- a/dlls/qasf/dmowrapper.c +++ b/dlls/qasf/dmowrapper.c @@ -335,6 +335,32 @@ out: return hr; }
+static HRESULT dmo_wrapper_sink_eos(struct strmbase_sink *iface) +{ + struct dmo_wrapper *filter = impl_from_strmbase_filter(iface->pin.filter); + DWORD index = iface - filter->sinks, i; + IMediaObject *dmo; + HRESULT hr; + + IUnknown_QueryInterface(filter->dmo, &IID_IMediaObject, (void **)&dmo); + + if (FAILED(hr = IMediaObject_Discontinuity(dmo, index))) + ERR("Discontinuity() failed, hr %#x.\n", hr); + + process_output(filter, dmo); + if (FAILED(hr = IMediaObject_Flush(dmo))) + ERR("Flush() failed, hr %#x.\n", hr); + + for (i = 0; i < filter->source_count; ++i) + { + if (filter->sources[i].pin.pin.peer) + IPin_EndOfStream(filter->sources[i].pin.pin.peer); + } + + IMediaObject_Release(dmo); + return hr; +} + static const struct strmbase_sink_ops sink_ops = { .base.pin_query_interface = dmo_wrapper_sink_query_interface, @@ -342,6 +368,7 @@ static const struct strmbase_sink_ops sink_ops = .base.pin_get_media_type = dmo_wrapper_sink_get_media_type, .sink_connect = dmo_wrapper_sink_connect, .sink_disconnect = dmo_wrapper_sink_disconnect, + .sink_eos = dmo_wrapper_sink_eos, .pfnReceive = dmo_wrapper_sink_Receive, };
diff --git a/dlls/qasf/tests/dmowrapper.c b/dlls/qasf/tests/dmowrapper.c index 5dcc75d555c..b509839de45 100644 --- a/dlls/qasf/tests/dmowrapper.c +++ b/dlls/qasf/tests/dmowrapper.c @@ -307,7 +307,7 @@ static HRESULT WINAPI dmo_ProcessInput(IMediaObject *iface, DWORD index, ok(hr == S_OK, "Got hr %#x.\n", hr); ok(len == 256, "Got length %u.\n", len);
- if (testmode == 0) + if (testmode == 0 || testmode == 12) { ok(!flags, "Got flags %#x.\n", flags); ok(!timestamp, "Got timestamp %s.\n", wine_dbgstr_longlong(timestamp)); @@ -356,7 +356,10 @@ static HRESULT WINAPI dmo_ProcessOutput(IMediaObject *iface, DWORD flags, ok(count == 2, "Got count %u.\n", count);
ok(!!buffers[0].pBuffer, "Expected a buffer.\n"); - ok(!buffers[1].pBuffer, "Got unexpected buffer %p.\n", buffers[1].pBuffer); + if (testmode == 12) + ok(!!buffers[1].pBuffer, "Expected a buffer.\n"); + else + ok(!buffers[1].pBuffer, "Got unexpected buffer %p.\n", buffers[1].pBuffer);
buffers[1].dwStatus = DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE;
@@ -372,6 +375,15 @@ static HRESULT WINAPI dmo_ProcessOutput(IMediaObject *iface, DWORD flags, buffers[0].rtTimelength = 1000; buffers[0].rtTimestamp = 5000;
+ if (buffers[1].pBuffer) + { + buffers[1].dwStatus = buffers[0].dwStatus; + buffers[1].rtTimelength = buffers[0].rtTimelength; + buffers[1].rtTimestamp = buffers[0].rtTimestamp; + hr = IMediaBuffer_SetLength(buffers[1].pBuffer, 300); + ok(hr == S_OK, "Got hr %#x.\n", hr); + } + if (testmode == 3) { hr = IMediaBuffer_SetLength(buffers[0].pBuffer, 16200); @@ -399,8 +411,9 @@ static HRESULT WINAPI dmo_ProcessOutput(IMediaObject *iface, DWORD flags, data[i] = 111 - i; hr = IMediaBuffer_SetLength(buffers[0].pBuffer, 300); ok(hr == S_OK, "Got hr %#x.\n", hr); - if (testmode != 10) + if (testdmo_buffer) IMediaBuffer_Release(testdmo_buffer); + testdmo_buffer = NULL; return S_OK; }
@@ -1108,7 +1121,7 @@ struct testfilter struct strmbase_source source; struct strmbase_sink sink; const AM_MEDIA_TYPE *sink_mt; - unsigned int got_new_segment; + unsigned int got_new_segment, got_eos; };
static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -1210,12 +1223,15 @@ static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample
ok(len == 300, "Got length %u.\n", len);
- hr = IMediaSample_GetPointer(sample, &data); - ok(hr == S_OK, "Got hr %#x.\n", hr); + if (testmode != 12) + { + hr = IMediaSample_GetPointer(sample, &data); + ok(hr == S_OK, "Got hr %#x.\n", hr);
- for (i = 0; i < 300; ++i) - expect[i] = 111 - i; - ok(!memcmp(data, expect, 300), "Data didn't match.\n"); + for (i = 0; i < 300; ++i) + expect[i] = 111 - i; + ok(!memcmp(data, expect, 300), "Data didn't match.\n"); + } }
hr = IMediaSample_GetTime(sample, &start, &stop); @@ -1262,6 +1278,13 @@ static HRESULT testsink_new_segment(struct strmbase_sink *iface, return 0xdeadbeef; }
+static HRESULT testsink_eos(struct strmbase_sink *iface) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + ++filter->got_eos; + return 0xdeadbeef; +} + static const struct strmbase_sink_ops testsink_ops = { .base.pin_query_interface = testsink_query_interface, @@ -1269,6 +1292,7 @@ static const struct strmbase_sink_ops testsink_ops = .base.pin_get_media_type = testsink_get_media_type, .pfnReceive = testsink_Receive, .sink_new_segment = testsink_new_segment, + .sink_eos = testsink_eos, };
static void testfilter_init(struct testfilter *filter) @@ -1605,11 +1629,10 @@ static void test_sample_processing(IMediaControl *control, IMemInputPin *input) ok(got_ProcessOutput == 2, "Got %u calls to ProcessOutput().\n", got_ProcessOutput); ok(got_Receive == 2, "Got %u calls to Receive().\n", got_Receive); ok(got_Discontinuity == 1, "Got %u calls to Discontinuity().\n", got_Discontinuity); - got_ProcessInput = got_ProcessOutput = got_Receive = 0; + got_ProcessInput = got_ProcessOutput = got_Receive = got_Discontinuity = 0;
hr = IMediaControl_Stop(control); ok(hr == S_OK, "Got hr %#x.\n", hr); - IMediaSample_Release(sample); IMemAllocator_Release(allocator); } @@ -1617,11 +1640,30 @@ static void test_sample_processing(IMediaControl *control, IMemInputPin *input) static void test_streaming_events(IMediaControl *control, IPin *sink, IMemInputPin *input, struct testfilter *testsink, struct testfilter *testsink2) { + IMemAllocator *allocator; + IMediaSample *sample; HRESULT hr; + BYTE *data; + LONG i;
hr = IMediaControl_Pause(control); ok(hr == S_OK, "Got hr %#x.\n", hr);
+ got_Flush = 0; + + hr = IMemInputPin_GetAllocator(input, &allocator); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMemAllocator_Commit(allocator); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaSample_GetPointer(sample, &data); + ok(hr == S_OK, "Got hr %#x.\n", hr); + for (i = 0; i < 200; ++i) + data[i] = i; + hr = IMediaSample_SetActualDataLength(sample, 200); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!testsink->got_new_segment, "Got %u calls to IPin::NewSegment().\n", testsink->got_new_segment); ok(!testsink2->got_new_segment, "Got %u calls to IPin::NewSegment().\n", testsink2->got_new_segment); hr = IPin_NewSegment(sink, 10000, 20000, 1.0); @@ -1629,8 +1671,32 @@ static void test_streaming_events(IMediaControl *control, IPin *sink, IMemInputP ok(testsink->got_new_segment == 1, "Got %u calls to IPin::NewSegment().\n", testsink->got_new_segment); ok(testsink2->got_new_segment == 1, "Got %u calls to IPin::NewSegment().\n", testsink2->got_new_segment);
+ ok(!testsink->got_eos, "Got %u calls to IPin::EndOfStream().\n", testsink->got_eos); + ok(!testsink2->got_eos, "Got %u calls to IPin::EndOfStream().\n", testsink2->got_eos); + testmode = 12; + hr = IPin_EndOfStream(sink); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!got_ProcessInput, "Got %u calls to ProcessInput().\n", got_ProcessInput); + ok(got_Discontinuity == 1, "Got %u calls to Discontinuity().\n", got_Discontinuity); + ok(got_ProcessOutput == 1, "Got %u calls to ProcessOutput().\n", got_ProcessOutput); + ok(got_Receive == 2, "Got %u calls to Receive().\n", got_Receive); + ok(got_Flush == 1, "Got %u calls to Flush().\n", got_Flush); + ok(testsink->got_eos == 1, "Got %u calls to IPin::EndOfStream().\n", testsink->got_eos); + ok(testsink2->got_eos == 1, "Got %u calls to IPin::EndOfStream().\n", testsink2->got_eos); + got_ProcessInput = got_ProcessOutput = got_Receive = got_Discontinuity = 0; + + hr = IPin_EndOfStream(sink); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(testsink->got_eos == 1, "Got %u calls to IPin::EndOfStream().\n", testsink->got_eos); + todo_wine ok(testsink2->got_eos == 1, "Got %u calls to IPin::EndOfStream().\n", testsink2->got_eos); + + hr = IMemInputPin_Receive(input, sample); + todo_wine ok(hr == VFW_E_SAMPLE_REJECTED_EOS, "Got hr %#x.\n", hr); + hr = IMediaControl_Stop(control); ok(hr == S_OK, "Got hr %#x.\n", hr); + IMediaSample_Release(sample); + IMemAllocator_Release(allocator); }
static void test_connect_pin(void)
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qasf/dmowrapper.c | 23 ++++++++++++++++++ dlls/qasf/tests/dmowrapper.c | 47 +++++++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/dlls/qasf/dmowrapper.c b/dlls/qasf/dmowrapper.c index 9e0a178542a..32a9d41b7a8 100644 --- a/dlls/qasf/dmowrapper.c +++ b/dlls/qasf/dmowrapper.c @@ -361,6 +361,28 @@ static HRESULT dmo_wrapper_sink_eos(struct strmbase_sink *iface) return hr; }
+static HRESULT dmo_wrapper_end_flush(struct strmbase_sink *iface) +{ + struct dmo_wrapper *filter = impl_from_strmbase_filter(iface->pin.filter); + IMediaObject *dmo; + HRESULT hr; + DWORD i; + + IUnknown_QueryInterface(filter->dmo, &IID_IMediaObject, (void **)&dmo); + + if (FAILED(hr = IMediaObject_Flush(dmo))) + ERR("Flush() failed, hr %#x.\n", hr); + + for (i = 0; i < filter->source_count; ++i) + { + if (filter->sources[i].pin.pin.peer) + IPin_EndFlush(filter->sources[i].pin.pin.peer); + } + + IMediaObject_Release(dmo); + return hr; +} + static const struct strmbase_sink_ops sink_ops = { .base.pin_query_interface = dmo_wrapper_sink_query_interface, @@ -369,6 +391,7 @@ static const struct strmbase_sink_ops sink_ops = .sink_connect = dmo_wrapper_sink_connect, .sink_disconnect = dmo_wrapper_sink_disconnect, .sink_eos = dmo_wrapper_sink_eos, + .sink_end_flush = dmo_wrapper_end_flush, .pfnReceive = dmo_wrapper_sink_Receive, };
diff --git a/dlls/qasf/tests/dmowrapper.c b/dlls/qasf/tests/dmowrapper.c index b509839de45..9ec9f85d55f 100644 --- a/dlls/qasf/tests/dmowrapper.c +++ b/dlls/qasf/tests/dmowrapper.c @@ -1121,7 +1121,7 @@ struct testfilter struct strmbase_source source; struct strmbase_sink sink; const AM_MEDIA_TYPE *sink_mt; - unsigned int got_new_segment, got_eos; + unsigned int got_new_segment, got_eos, got_begin_flush, got_end_flush; };
static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -1285,6 +1285,20 @@ static HRESULT testsink_eos(struct strmbase_sink *iface) return 0xdeadbeef; }
+static HRESULT testsink_begin_flush(struct strmbase_sink *iface) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + ++filter->got_begin_flush; + return 0xdeadbeef; +} + +static HRESULT testsink_end_flush(struct strmbase_sink *iface) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface->pin.filter); + ++filter->got_end_flush; + return 0xdeadbeef; +} + static const struct strmbase_sink_ops testsink_ops = { .base.pin_query_interface = testsink_query_interface, @@ -1293,6 +1307,8 @@ static const struct strmbase_sink_ops testsink_ops = .pfnReceive = testsink_Receive, .sink_new_segment = testsink_new_segment, .sink_eos = testsink_eos, + .sink_begin_flush = testsink_begin_flush, + .sink_end_flush = testsink_end_flush, };
static void testfilter_init(struct testfilter *filter) @@ -1693,6 +1709,35 @@ static void test_streaming_events(IMediaControl *control, IPin *sink, IMemInputP hr = IMemInputPin_Receive(input, sample); todo_wine ok(hr == VFW_E_SAMPLE_REJECTED_EOS, "Got hr %#x.\n", hr);
+ got_Flush = 0; + ok(!testsink->got_begin_flush, "Got %u calls to IPin::BeginFlush().\n", testsink->got_begin_flush); + ok(!testsink2->got_begin_flush, "Got %u calls to IPin::BeginFlush().\n", testsink2->got_begin_flush); + hr = IPin_BeginFlush(sink); + todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testsink->got_begin_flush == 1, "Got %u calls to IPin::BeginFlush().\n", testsink->got_begin_flush); + ok(testsink2->got_begin_flush == 1, "Got %u calls to IPin::BeginFlush().\n", testsink2->got_begin_flush); + + hr = IMemInputPin_Receive(input, sample); + todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr); + + hr = IPin_EndOfStream(sink); + todo_wine ok(hr == S_FALSE, "Got hr %#x.\n", hr); + + ok(!testsink->got_end_flush, "Got %u calls to IPin::EndFlush().\n", testsink->got_end_flush); + ok(!testsink2->got_end_flush, "Got %u calls to IPin::EndFlush().\n", testsink2->got_end_flush); + hr = IPin_EndFlush(sink); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(testsink->got_end_flush == 1, "Got %u calls to IPin::EndFlush().\n", testsink->got_end_flush); + ok(testsink2->got_end_flush == 1, "Got %u calls to IPin::EndFlush().\n", testsink2->got_end_flush); + ok(got_Flush, "Expected IMediaObject::Flush().\n"); + + hr = IMemInputPin_Receive(input, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + todo_wine ok(got_ProcessInput == 1, "Got %u calls to ProcessInput().\n", got_ProcessInput); + todo_wine ok(got_ProcessOutput == 1, "Got %u calls to ProcessOutput().\n", got_ProcessOutput); + todo_wine ok(got_Receive == 2, "Got %u calls to Receive().\n", got_Receive); + got_ProcessInput = got_ProcessOutput = got_Receive = 0; + hr = IMediaControl_Stop(control); ok(hr == S_OK, "Got hr %#x.\n", hr); IMediaSample_Release(sample);
From: Zebediah Figura z.figura12@gmail.com
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/qasf/dmowrapper.c | 26 ++++++++++++++++++++++++++ dlls/qasf/tests/dmowrapper.c | 4 ++-- 2 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/dlls/qasf/dmowrapper.c b/dlls/qasf/dmowrapper.c index 32a9d41b7a8..cba9023e13f 100644 --- a/dlls/qasf/dmowrapper.c +++ b/dlls/qasf/dmowrapper.c @@ -32,6 +32,7 @@ struct dmo_wrapper_source { struct strmbase_source pin; struct buffer buffer; + IUnknown *seeking; };
struct dmo_wrapper @@ -400,6 +401,16 @@ static inline struct dmo_wrapper_source *impl_source_from_strmbase_pin(struct st return CONTAINING_RECORD(iface, struct dmo_wrapper_source, pin.pin); }
+static HRESULT dmo_wrapper_source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) +{ + struct dmo_wrapper_source *pin = impl_source_from_strmbase_pin(iface); + + if (IsEqualGUID(iid, &IID_IMediaSeeking) || IsEqualGUID(iid, &IID_IMediaPosition)) + return IUnknown_QueryInterface(pin->seeking, iid, out); + + return E_NOINTERFACE; +} + static HRESULT dmo_wrapper_source_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) { struct dmo_wrapper *filter = impl_from_strmbase_filter(iface->filter); @@ -476,6 +487,7 @@ static void dmo_wrapper_source_disconnect(struct strmbase_source *iface)
static const struct strmbase_source_ops source_ops = { + .base.pin_query_interface = dmo_wrapper_source_query_interface, .base.pin_query_accept = dmo_wrapper_source_query_accept, .base.pin_get_media_type = dmo_wrapper_source_get_media_type, .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, @@ -556,9 +568,20 @@ static HRESULT WINAPI dmo_wrapper_filter_Init(IDMOWrapperFilter *iface, REFCLSID
for (i = 0; i < output_count; ++i) { + ISeekingPassThru *passthrough; + swprintf(id, ARRAY_SIZE(id), L"out%u", i); strmbase_source_init(&sources[i].pin, &filter->filter, id, &source_ops); sources[i].buffer.IMediaBuffer_iface.lpVtbl = &buffer_vtbl; + + if (FAILED(hr = CoCreateInstance(&CLSID_SeekingPassThru, + (IUnknown *)&sources[i].pin.pin.IPin_iface, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (void **)&sources[i].seeking))) + ERR("Failed to create SeekingPassThru object, hr %#x.\n", hr); + + IUnknown_QueryInterface(sources[i].seeking, &IID_ISeekingPassThru, (void **)&passthrough); + ISeekingPassThru_Init(passthrough, FALSE, &sinks[0].pin.IPin_iface); + ISeekingPassThru_Release(passthrough); }
EnterCriticalSection(&filter->filter.csFilter); @@ -606,7 +629,10 @@ static void dmo_wrapper_destroy(struct strmbase_filter *iface) for (i = 0; i < filter->sink_count; ++i) strmbase_sink_cleanup(&filter->sinks[i]); for (i = 0; i < filter->source_count; ++i) + { + IUnknown_Release(filter->sources[i].seeking); strmbase_source_cleanup(&filter->sources[i].pin); + } free(filter->sinks); free(filter->sources); strmbase_filter_cleanup(&filter->filter); diff --git a/dlls/qasf/tests/dmowrapper.c b/dlls/qasf/tests/dmowrapper.c index 9ec9f85d55f..50546ec2a88 100644 --- a/dlls/qasf/tests/dmowrapper.c +++ b/dlls/qasf/tests/dmowrapper.c @@ -574,8 +574,8 @@ static void test_interfaces(void)
IBaseFilter_FindPin(filter, L"out0", &pin);
- todo_wine check_interface(pin, &IID_IMediaPosition, TRUE); - todo_wine check_interface(pin, &IID_IMediaSeeking, TRUE); + check_interface(pin, &IID_IMediaPosition, TRUE); + check_interface(pin, &IID_IMediaSeeking, TRUE); check_interface(pin, &IID_IPin, TRUE); todo_wine check_interface(pin, &IID_IQualityControl, TRUE); check_interface(pin, &IID_IUnknown, TRUE);