qasf/dmowrapper: Implement receiving and delivering samples.
Signed-off-by: Zebediah Figura <zfigura@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
e7c735b825
commit
ed8d3d325f
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue