From ed8d3d325fa53bcc70e16e17811f36e94f2b75c7 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Thu, 20 Feb 2020 20:42:54 -0600 Subject: [PATCH] qasf/dmowrapper: Implement receiving and delivering samples. Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard --- 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;