Commit ed8d3d32 authored by Zebediah Figura's avatar Zebediah Figura Committed by Alexandre Julliard

qasf/dmowrapper: Implement receiving and delivering samples.

parent e7c735b8
...@@ -22,9 +22,16 @@ ...@@ -22,9 +22,16 @@
WINE_DEFAULT_DEBUG_CHANNEL(qasf); WINE_DEFAULT_DEBUG_CHANNEL(qasf);
struct buffer
{
IMediaBuffer IMediaBuffer_iface;
IMediaSample *sample;
};
struct dmo_wrapper_source struct dmo_wrapper_source
{ {
struct strmbase_source pin; struct strmbase_source pin;
struct buffer buffer;
}; };
struct dmo_wrapper struct dmo_wrapper
...@@ -37,6 +44,80 @@ struct dmo_wrapper ...@@ -37,6 +44,80 @@ struct dmo_wrapper
DWORD sink_count, source_count; DWORD sink_count, source_count;
struct strmbase_sink *sinks; struct strmbase_sink *sinks;
struct dmo_wrapper_source *sources; 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) 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) ...@@ -120,6 +201,140 @@ static void dmo_wrapper_sink_disconnect(struct strmbase_sink *iface)
IMediaObject_Release(dmo); 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 = static const struct strmbase_sink_ops sink_ops =
{ {
.base.pin_query_interface = dmo_wrapper_sink_query_interface, .base.pin_query_interface = dmo_wrapper_sink_query_interface,
...@@ -127,6 +342,7 @@ static const struct strmbase_sink_ops sink_ops = ...@@ -127,6 +342,7 @@ static const struct strmbase_sink_ops sink_ops =
.base.pin_get_media_type = dmo_wrapper_sink_get_media_type, .base.pin_get_media_type = dmo_wrapper_sink_get_media_type,
.sink_connect = dmo_wrapper_sink_connect, .sink_connect = dmo_wrapper_sink_connect,
.sink_disconnect = dmo_wrapper_sink_disconnect, .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) 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 ...@@ -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 *filter = impl_from_IDMOWrapperFilter(iface);
struct dmo_wrapper_source *sources; struct dmo_wrapper_source *sources;
DMO_OUTPUT_DATA_BUFFER *buffers;
DWORD input_count, output_count; DWORD input_count, output_count;
struct strmbase_sink *sinks; struct strmbase_sink *sinks;
IMediaObject *dmo; IMediaObject *dmo;
...@@ -270,10 +487,12 @@ static HRESULT WINAPI dmo_wrapper_filter_Init(IDMOWrapperFilter *iface, REFCLSID ...@@ -270,10 +487,12 @@ static HRESULT WINAPI dmo_wrapper_filter_Init(IDMOWrapperFilter *iface, REFCLSID
sinks = calloc(sizeof(*sinks), input_count); sinks = calloc(sizeof(*sinks), input_count);
sources = calloc(sizeof(*sources), output_count); sources = calloc(sizeof(*sources), output_count);
if (!sinks || !sources) buffers = calloc(sizeof(*buffers), output_count);
if (!sinks || !sources || !buffers)
{ {
free(sinks); free(sinks);
free(sources); free(sources);
free(buffers);
IMediaObject_Release(dmo); IMediaObject_Release(dmo);
IUnknown_Release(unk); IUnknown_Release(unk);
return hr; return hr;
...@@ -289,6 +508,7 @@ static HRESULT WINAPI dmo_wrapper_filter_Init(IDMOWrapperFilter *iface, REFCLSID ...@@ -289,6 +508,7 @@ static HRESULT WINAPI dmo_wrapper_filter_Init(IDMOWrapperFilter *iface, REFCLSID
{ {
swprintf(id, ARRAY_SIZE(id), L"out%u", i); swprintf(id, ARRAY_SIZE(id), L"out%u", i);
strmbase_source_init(&sources[i].pin, &filter->filter, id, &source_ops); strmbase_source_init(&sources[i].pin, &filter->filter, id, &source_ops);
sources[i].buffer.IMediaBuffer_iface.lpVtbl = &buffer_vtbl;
} }
EnterCriticalSection(&filter->filter.csFilter); EnterCriticalSection(&filter->filter.csFilter);
...@@ -298,6 +518,7 @@ static HRESULT WINAPI dmo_wrapper_filter_Init(IDMOWrapperFilter *iface, REFCLSID ...@@ -298,6 +518,7 @@ static HRESULT WINAPI dmo_wrapper_filter_Init(IDMOWrapperFilter *iface, REFCLSID
filter->source_count = output_count; filter->source_count = output_count;
filter->sinks = sinks; filter->sinks = sinks;
filter->sources = sources; filter->sources = sources;
filter->buffers = buffers;
LeaveCriticalSection(&filter->filter.csFilter); LeaveCriticalSection(&filter->filter.csFilter);
...@@ -358,13 +579,34 @@ static HRESULT dmo_wrapper_query_interface(struct strmbase_filter *iface, REFIID ...@@ -358,13 +579,34 @@ static HRESULT dmo_wrapper_query_interface(struct strmbase_filter *iface, REFIID
return E_NOINTERFACE; 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) static HRESULT dmo_wrapper_cleanup_stream(struct strmbase_filter *iface)
{ {
struct dmo_wrapper *filter = impl_from_strmbase_filter(iface); struct dmo_wrapper *filter = impl_from_strmbase_filter(iface);
IMediaObject *dmo; IMediaObject *dmo;
DWORD i;
IUnknown_QueryInterface(filter->dmo, &IID_IMediaObject, (void **)&dmo); 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_Flush(dmo);
IMediaObject_Release(dmo); IMediaObject_Release(dmo);
...@@ -376,6 +618,7 @@ static struct strmbase_filter_ops filter_ops = ...@@ -376,6 +618,7 @@ static struct strmbase_filter_ops filter_ops =
.filter_get_pin = dmo_wrapper_get_pin, .filter_get_pin = dmo_wrapper_get_pin,
.filter_destroy = dmo_wrapper_destroy, .filter_destroy = dmo_wrapper_destroy,
.filter_query_interface = dmo_wrapper_query_interface, .filter_query_interface = dmo_wrapper_query_interface,
.filter_init_stream = dmo_wrapper_init_stream,
.filter_cleanup_stream = dmo_wrapper_cleanup_stream, .filter_cleanup_stream = dmo_wrapper_cleanup_stream,
}; };
...@@ -391,6 +634,8 @@ HRESULT dmo_wrapper_create(IUnknown *outer, IUnknown **out) ...@@ -391,6 +634,8 @@ HRESULT dmo_wrapper_create(IUnknown *outer, IUnknown **out)
object->IDMOWrapperFilter_iface.lpVtbl = &dmo_wrapper_filter_vtbl; object->IDMOWrapperFilter_iface.lpVtbl = &dmo_wrapper_filter_vtbl;
object->input_buffer.IMediaBuffer_iface.lpVtbl = &buffer_vtbl;
TRACE("Created DMO wrapper %p.\n", object); TRACE("Created DMO wrapper %p.\n", object);
*out = &object->filter.IUnknown_inner; *out = &object->filter.IUnknown_inner;
......
...@@ -56,6 +56,13 @@ static inline BOOL compare_media_types(const AM_MEDIA_TYPE *a, const AM_MEDIA_TY ...@@ -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); && !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 const IMediaObjectVtbl dmo_vtbl;
static IMediaObject testdmo = {&dmo_vtbl}; static IMediaObject testdmo = {&dmo_vtbl};
...@@ -69,7 +76,11 @@ static HRESULT testdmo_GetOutputSizeInfo_hr = S_OK; ...@@ -69,7 +76,11 @@ static HRESULT testdmo_GetOutputSizeInfo_hr = S_OK;
static DWORD testdmo_output_size = 123; static DWORD testdmo_output_size = 123;
static DWORD testdmo_output_alignment = 1; 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) static HRESULT WINAPI dmo_inner_QueryInterface(IUnknown *iface, REFIID iid, void **out)
{ {
...@@ -249,8 +260,9 @@ static HRESULT WINAPI dmo_Flush(IMediaObject *iface) ...@@ -249,8 +260,9 @@ static HRESULT WINAPI dmo_Flush(IMediaObject *iface)
static HRESULT WINAPI dmo_Discontinuity(IMediaObject *iface, DWORD index) static HRESULT WINAPI dmo_Discontinuity(IMediaObject *iface, DWORD index)
{ {
ok(0, "Unexpected call.\n"); if (winetest_debug > 1) trace("Discontinuity(index %u)\n", index);
return E_NOTIMPL; ++got_Discontinuity;
return S_OK;
} }
static HRESULT WINAPI dmo_AllocateStreamingResources(IMediaObject *iface) static HRESULT WINAPI dmo_AllocateStreamingResources(IMediaObject *iface)
...@@ -267,22 +279,132 @@ static HRESULT WINAPI dmo_FreeStreamingResources(IMediaObject *iface) ...@@ -267,22 +279,132 @@ static HRESULT WINAPI dmo_FreeStreamingResources(IMediaObject *iface)
static HRESULT WINAPI dmo_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags) static HRESULT WINAPI dmo_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags)
{ {
ok(0, "Unexpected call.\n"); if (winetest_debug > 1) trace("GetInputStatus(index %u)\n", index);
return E_NOTIMPL; *flags = DMO_INPUT_STATUSF_ACCEPT_DATA;
return S_OK;
} }
static HRESULT WINAPI dmo_ProcessInput(IMediaObject *iface, DWORD index, static HRESULT WINAPI dmo_ProcessInput(IMediaObject *iface, DWORD index,
IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength)
{ {
ok(0, "Unexpected call.\n"); BYTE *data, expect[200];
return E_NOTIMPL; 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, static HRESULT WINAPI dmo_ProcessOutput(IMediaObject *iface, DWORD flags,
DWORD count, DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) DWORD count, DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status)
{ {
ok(0, "Unexpected call.\n"); DWORD len, i;
return E_NOTIMPL; 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) static HRESULT WINAPI dmo_Lock(IMediaObject *iface, LONG lock)
...@@ -384,13 +506,6 @@ static IBaseFilter *create_dmo_wrapper(void) ...@@ -384,13 +506,6 @@ static IBaseFilter *create_dmo_wrapper(void)
return filter; 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) #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) 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 ...@@ -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) 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; return S_OK;
} }
...@@ -1100,7 +1270,7 @@ static void testfilter_init(struct testfilter *filter) ...@@ -1100,7 +1270,7 @@ static void testfilter_init(struct testfilter *filter)
static void test_sink_allocator(IMemInputPin *input) static void test_sink_allocator(IMemInputPin *input)
{ {
IMemAllocator *req_allocator, *ret_allocator; IMemAllocator *req_allocator, *ret_allocator;
ALLOCATOR_PROPERTIES props; ALLOCATOR_PROPERTIES props, ret_props;
HRESULT hr; HRESULT hr;
hr = IMemInputPin_GetAllocatorRequirements(input, &props); hr = IMemInputPin_GetAllocatorRequirements(input, &props);
...@@ -1141,6 +1311,13 @@ static void test_sink_allocator(IMemInputPin *input) ...@@ -1141,6 +1311,13 @@ static void test_sink_allocator(IMemInputPin *input)
CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
&IID_IMemAllocator, (void **)&req_allocator); &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); hr = IMemInputPin_NotifyAllocator(input, req_allocator, TRUE);
ok(hr == S_OK, "Got hr %#x.\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
...@@ -1275,6 +1452,155 @@ static void test_filter_state(IMediaControl *control) ...@@ -1275,6 +1452,155 @@ static void test_filter_state(IMediaControl *control)
ok(state == State_Stopped, "Got state %u.\n", state); 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) static void test_connect_pin(void)
{ {
AM_MEDIA_TYPE req_mt = AM_MEDIA_TYPE req_mt =
...@@ -1366,6 +1692,9 @@ static void test_connect_pin(void) ...@@ -1366,6 +1692,9 @@ static void test_connect_pin(void)
ok(testdmo_output_mt_set, "Ouput type should be set.\n"); 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"); 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); hr = IFilterGraph2_Disconnect(graph, source);
ok(hr == S_OK, "Got hr %#x.\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IFilterGraph2_Disconnect(graph, source); hr = IFilterGraph2_Disconnect(graph, source);
...@@ -1383,8 +1712,6 @@ static void test_connect_pin(void) ...@@ -1383,8 +1712,6 @@ static void test_connect_pin(void)
ok(!testdmo_output_mt_set, "Output type should not be set.\n"); ok(!testdmo_output_mt_set, "Output type should not be set.\n");
test_filter_state(control);
req_mt.lSampleSize = 0; req_mt.lSampleSize = 0;
hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt); hr = IFilterGraph2_ConnectDirect(graph, source, &testsink.sink.pin.IPin_iface, &req_mt);
ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr); ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#x.\n", hr);
......
...@@ -87,6 +87,23 @@ interface IMediaBuffer : IUnknown ...@@ -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 { typedef struct _DMO_OUTPUT_DATA_BUFFER {
IMediaBuffer *pBuffer; IMediaBuffer *pBuffer;
DWORD dwStatus; DWORD dwStatus;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment