Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/amstream/ddrawstream.c | 28 +++++++++++---- dlls/amstream/tests/amstream.c | 66 +++++++++++++++++++++++++++++++++- 2 files changed, 87 insertions(+), 7 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index fdfe0374ab1..7817df494d5 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -1387,6 +1387,7 @@ static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDraw const RECT *rect, IDirectDrawStreamSample **ddraw_stream_sample) { struct ddraw_sample *object; + DDSURFACEDESC desc; HRESULT hr;
TRACE("(%p)\n", ddraw_stream_sample); @@ -1408,7 +1409,6 @@ static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDraw } else { - DDSURFACEDESC desc; IDirectDraw *ddraw;
hr = IDirectDrawMediaStream_GetDirectDraw(&parent->IDirectDrawMediaStream_iface, &ddraw); @@ -1449,14 +1449,30 @@ static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDraw } }
+ desc.dwSize = sizeof(desc); + hr = IDirectDrawSurface_GetSurfaceDesc(object->surface, &desc); + if (FAILED(hr)) + { + IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface); + return hr; + } + if (rect) + { object->rect = *rect; - else if (object->surface) + desc.dwWidth = rect->right - rect->left; + desc.dwHeight = rect->bottom - rect->top; + } + else { - DDSURFACEDESC desc = { sizeof(desc) }; - hr = IDirectDrawSurface_GetSurfaceDesc(object->surface, &desc); - if (hr == S_OK) - SetRect(&object->rect, 0, 0, desc.dwWidth, desc.dwHeight); + SetRect(&object->rect, 0, 0, desc.dwWidth, desc.dwHeight); + } + + hr = IDirectDrawMediaStream_SetFormat(&parent->IDirectDrawMediaStream_iface, &desc, NULL); + if (FAILED(hr)) + { + IDirectDrawStreamSample_Release(&object->IDirectDrawStreamSample_iface); + return hr; }
*ddraw_stream_sample = &object->IDirectDrawStreamSample_iface; diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index 1c0b36ea6c5..d2126a15db3 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -6495,6 +6495,7 @@ static void get_ddrawstream_create_sample_desc_(int line, const DDSURFACEDESC *f static void test_ddrawstream_create_sample(void) { IAMMultiMediaStream *mmstream = create_ammultimediastream(); + DDSURFACEDESC desc2 = { sizeof(desc2) }; IDirectDrawSurface *surface, *surface2; DDSURFACEDESC desc = { sizeof(desc) }; IDirectDrawMediaStream *ddraw_stream; @@ -6591,11 +6592,74 @@ static void test_ddrawstream_create_sample(void) hr = IDirectDrawMediaStream_CreateSample(ddraw_stream, surface, &rect, 0, &sample); ok(hr == S_OK, "Got hr %#x.\n", hr);
- IDirectDrawMediaStream_Release(ddraw_stream); ref = IDirectDrawStreamSample_Release(sample); ok(!ref, "Got outstanding refcount %d.\n", ref); ref = IDirectDrawSurface_Release(surface); ok(!ref, "Got outstanding refcount %d.\n", ref); + + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; + desc.dwWidth = 444; + desc.dwHeight = 400; + desc.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS; + desc.ddpfPixelFormat.dwRGBBitCount = 32; + desc.ddpfPixelFormat.dwRBitMask = 0xff0000; + desc.ddpfPixelFormat.dwGBitMask = 0x00ff00; + desc.ddpfPixelFormat.dwBBitMask = 0x0000ff; + desc.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000; + desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; + hr = IDirectDraw_CreateSurface(ddraw, &desc, &surface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + SetRect(&rect, 111, 100, 333, 300); + + hr = IDirectDrawMediaStream_CreateSample(ddraw_stream, surface, &rect, 0, &sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ref = IDirectDrawStreamSample_Release(sample); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + hr = IDirectDrawMediaStream_CreateSample(ddraw_stream, NULL, NULL, 0, &sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + surface2 = NULL; + hr = IDirectDrawStreamSample_GetSurface(sample, &surface2, &rect); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IDirectDrawSurface_GetSurfaceDesc(surface, &desc); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IDirectDrawSurface_GetSurfaceDesc(surface2, &desc2); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(desc2.dwWidth == 222, "Got width %u.\n", desc2.dwWidth); + ok(desc2.dwHeight == 200, "Got height %u.\n", desc2.dwHeight); + ok(memcmp(&desc2.ddpfPixelFormat, &desc.ddpfPixelFormat, sizeof(DDPIXELFORMAT)) == 0, + "Pixel format didn't match.\n"); + + ref = IDirectDrawStreamSample_Release(sample); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IDirectDrawSurface_Release(surface); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IDirectDrawSurface_Release(surface2); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; + desc.dwWidth = 444; + desc.dwHeight = 400; + desc.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT); + desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED4; + desc.ddpfPixelFormat.dwRGBBitCount = 4; + desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; + hr = IDirectDraw_CreateSurface(ddraw, &desc, &surface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IDirectDrawMediaStream_CreateSample(ddraw_stream, surface, NULL, 0, &sample); + ok(hr == DDERR_INVALIDSURFACETYPE, "Got hr %#x.\n", hr); + + IDirectDrawMediaStream_Release(ddraw_stream); + ref = IDirectDrawSurface_Release(surface); + ok(!ref, "Got outstanding refcount %d.\n", ref); ref = IAMMultiMediaStream_Release(mmstream); ok(!ref, "Got outstanding refcount %d.\n", ref); ref = IMediaStream_Release(stream);
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/amstream/ddrawstream.c | 13 ++++-- dlls/amstream/tests/amstream.c | 76 ++++++++++++++++++---------------- 2 files changed, 51 insertions(+), 38 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index 7817df494d5..21cb4437e3d 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -57,6 +57,7 @@ struct ddraw_stream IMemAllocator *allocator; AM_MEDIA_TYPE mt; struct format format; + FILTER_STATE state; };
static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface, @@ -260,11 +261,17 @@ static HRESULT WINAPI ddraw_IAMMediaStream_Initialize(IAMMediaStream *iface, IUn
static HRESULT WINAPI ddraw_IAMMediaStream_SetState(IAMMediaStream *iface, FILTER_STATE state) { - struct ddraw_stream *This = impl_from_IAMMediaStream(iface); + struct ddraw_stream *stream = impl_from_IAMMediaStream(iface);
- FIXME("(%p/%p)->(%u) stub!\n", This, iface, state); + TRACE("stream %p, state %u.\n", stream, state);
- return S_FALSE; + EnterCriticalSection(&stream->cs); + + stream->state = state; + + LeaveCriticalSection(&stream->cs); + + return S_OK; }
static HRESULT WINAPI ddraw_IAMMediaStream_JoinAMMultiMediaStream(IAMMediaStream *iface, IAMMultiMediaStream *mmstream) diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index d2126a15db3..af2d77d813e 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -3613,40 +3613,6 @@ static void test_ddrawstream_receive_connection(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
-static void test_audiostream_set_state(void) -{ - IAMMultiMediaStream *mmstream = create_ammultimediastream(); - IAMMediaStream *am_stream; - IMediaStream *stream; - HRESULT hr; - ULONG ref; - - hr = IAMMultiMediaStream_Initialize(mmstream, STREAMTYPE_READ, 0, NULL); - ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IAMMultiMediaStream_AddMediaStream(mmstream, NULL, &MSPID_PrimaryAudio, 0, &stream); - ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IMediaStream_QueryInterface(stream, &IID_IAMMediaStream, (void **)&am_stream); - ok(hr == S_OK, "Got hr %#x.\n", hr); - - hr = IAMMediaStream_SetState(am_stream, 4); - ok(hr == S_OK, "Got hr %#x.\n", hr); - - hr = IAMMediaStream_SetState(am_stream, State_Running); - ok(hr == S_OK, "Got hr %#x.\n", hr); - - hr = IAMMediaStream_SetState(am_stream, State_Paused); - ok(hr == S_OK, "Got hr %#x.\n", hr); - - hr = IAMMediaStream_SetState(am_stream, State_Stopped); - ok(hr == S_OK, "Got hr %#x.\n", hr); - - ref = IAMMultiMediaStream_Release(mmstream); - ok(!ref, "Got outstanding refcount %d.\n", ref); - IAMMediaStream_Release(am_stream); - ref = IMediaStream_Release(stream); - ok(!ref, "Got outstanding refcount %d.\n", ref); -} - void test_audiostream_end_of_stream(void) { IAMMultiMediaStream *mmstream = create_ammultimediastream(); @@ -5358,6 +5324,46 @@ static void test_ammediastream_join_filter_graph(void) check_ammediastream_join_filter_graph(&MSPID_PrimaryVideo); }
+static void check_ammediastream_set_state(const MSPID *id) +{ + IAMMultiMediaStream *mmstream = create_ammultimediastream(); + IAMMediaStream *am_stream; + IMediaStream *stream; + HRESULT hr; + ULONG ref; + + hr = IAMMultiMediaStream_Initialize(mmstream, STREAMTYPE_READ, 0, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IAMMultiMediaStream_AddMediaStream(mmstream, NULL, id, 0, &stream); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaStream_QueryInterface(stream, &IID_IAMMediaStream, (void **)&am_stream); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IAMMediaStream_SetState(am_stream, 4); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IAMMediaStream_SetState(am_stream, State_Running); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IAMMediaStream_SetState(am_stream, State_Paused); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IAMMediaStream_SetState(am_stream, State_Stopped); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ref = IAMMultiMediaStream_Release(mmstream); + ok(!ref, "Got outstanding refcount %d.\n", ref); + IAMMediaStream_Release(am_stream); + ref = IMediaStream_Release(stream); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + +static void test_ammediastream_set_state(void) +{ + check_ammediastream_set_state(&MSPID_PrimaryAudio); + check_ammediastream_set_state(&MSPID_PrimaryVideo); +} + void test_mediastreamfilter_get_state(void) { IAMMultiMediaStream *mmstream = create_ammultimediastream(); @@ -6851,7 +6857,6 @@ START_TEST(amstream) test_audiostream_get_format(); test_audiostream_set_format(); test_audiostream_receive_connection(); - test_audiostream_set_state(); test_audiostream_end_of_stream(); test_audiostream_receive(); test_audiostream_initialize(); @@ -6876,6 +6881,7 @@ START_TEST(amstream) test_ammediastream_join_am_multi_media_stream(); test_ammediastream_join_filter(); test_ammediastream_join_filter_graph(); + test_ammediastream_set_state();
test_mediastreamfilter_get_state(); test_mediastreamfilter_stop_pause_run();
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/amstream/ddrawstream.c | 23 +++++- dlls/amstream/tests/amstream.c | 126 +++++++++++++++++---------------- 2 files changed, 87 insertions(+), 62 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index 21cb4437e3d..c3cb2fc49a7 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -58,6 +58,7 @@ struct ddraw_stream AM_MEDIA_TYPE mt; struct format format; FILTER_STATE state; + BOOL eos; };
static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface, @@ -267,6 +268,9 @@ static HRESULT WINAPI ddraw_IAMMediaStream_SetState(IAMMediaStream *iface, FILTE
EnterCriticalSection(&stream->cs);
+ if (stream->state == State_Stopped) + stream->eos = FALSE; + stream->state = state;
LeaveCriticalSection(&stream->cs); @@ -1061,8 +1065,23 @@ static HRESULT WINAPI ddraw_sink_QueryInternalConnections(IPin *iface, IPin **pi
static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface) { - FIXME("iface %p, stub!\n", iface); - return E_NOTIMPL; + struct ddraw_stream *stream = impl_from_IPin(iface); + + TRACE("stream %p.\n", stream); + + EnterCriticalSection(&stream->cs); + + if (stream->eos) + { + LeaveCriticalSection(&stream->cs); + return E_FAIL; + } + + stream->eos = TRUE; + + LeaveCriticalSection(&stream->cs); + + return S_OK; }
static HRESULT WINAPI ddraw_sink_BeginFlush(IPin *iface) diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index af2d77d813e..df9d148493f 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -3613,65 +3613,6 @@ static void test_ddrawstream_receive_connection(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
-void test_audiostream_end_of_stream(void) -{ - IAMMultiMediaStream *mmstream = create_ammultimediastream(); - struct testfilter source; - IGraphBuilder *graph; - IMediaStream *stream; - HRESULT hr; - ULONG ref; - IPin *pin; - - hr = IAMMultiMediaStream_Initialize(mmstream, STREAMTYPE_READ, 0, NULL); - ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IAMMultiMediaStream_AddMediaStream(mmstream, NULL, &MSPID_PrimaryAudio, 0, &stream); - ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IMediaStream_QueryInterface(stream, &IID_IPin, (void **)&pin); - ok(hr == S_OK, "Got hr %#x.\n", hr); - hr = IAMMultiMediaStream_GetFilterGraph(mmstream, &graph); - ok(hr == S_OK, "Got hr %#x.\n", hr); - ok(!!graph, "Expected non-NULL graph.\n"); - testfilter_init(&source); - hr = IGraphBuilder_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL); - ok(hr == S_OK, "Got hr %#x.\n", hr); - - hr = IGraphBuilder_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &audio_mt); - ok(hr == S_OK, "Got hr %#x.\n", hr); - - hr = IPin_EndOfStream(pin); - ok(hr == S_OK, "Got hr %#x.\n", hr); - - hr = IPin_EndOfStream(pin); - ok(hr == E_FAIL, "Got hr %#x.\n", hr); - - hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); - ok(hr == S_OK, "Got hr %#x.\n", hr); - - hr = IPin_EndOfStream(pin); - ok(hr == S_OK, "Got hr %#x.\n", hr); - - hr = IPin_EndOfStream(pin); - ok(hr == E_FAIL, "Got hr %#x.\n", hr); - - hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP); - ok(hr == S_OK, "Got hr %#x.\n", hr); - - hr = IPin_EndOfStream(pin); - ok(hr == E_FAIL, "Got hr %#x.\n", hr); - - IGraphBuilder_Disconnect(graph, pin); - IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface); - - ref = IAMMultiMediaStream_Release(mmstream); - ok(!ref, "Got outstanding refcount %d.\n", ref); - ref = IGraphBuilder_Release(graph); - ok(!ref, "Got outstanding refcount %d.\n", ref); - IPin_Release(pin); - ref = IMediaStream_Release(stream); - ok(!ref, "Got outstanding refcount %d.\n", ref); -} - static void test_audiostream_receive(void) { ALLOCATOR_PROPERTIES properties = @@ -5364,6 +5305,71 @@ static void test_ammediastream_set_state(void) check_ammediastream_set_state(&MSPID_PrimaryVideo); }
+static void check_ammediastream_end_of_stream(const MSPID *id, const AM_MEDIA_TYPE *mt) +{ + IAMMultiMediaStream *mmstream = create_ammultimediastream(); + struct testfilter source; + IGraphBuilder *graph; + IMediaStream *stream; + HRESULT hr; + ULONG ref; + IPin *pin; + + hr = IAMMultiMediaStream_Initialize(mmstream, STREAMTYPE_READ, 0, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IAMMultiMediaStream_AddMediaStream(mmstream, NULL, id, 0, &stream); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaStream_QueryInterface(stream, &IID_IPin, (void **)&pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IAMMultiMediaStream_GetFilterGraph(mmstream, &graph); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!!graph, "Expected non-NULL graph.\n"); + testfilter_init(&source); + hr = IGraphBuilder_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IGraphBuilder_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IPin_EndOfStream(pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IPin_EndOfStream(pin); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IPin_EndOfStream(pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IPin_EndOfStream(pin); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IPin_EndOfStream(pin); + ok(hr == E_FAIL, "Got hr %#x.\n", hr); + + IGraphBuilder_Disconnect(graph, pin); + IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface); + + ref = IAMMultiMediaStream_Release(mmstream); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IGraphBuilder_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + IPin_Release(pin); + ref = IMediaStream_Release(stream); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + +static void test_ammediastream_end_of_stream(void) +{ + check_ammediastream_end_of_stream(&MSPID_PrimaryAudio, &audio_mt); + check_ammediastream_end_of_stream(&MSPID_PrimaryVideo, &rgb32_mt); +} + void test_mediastreamfilter_get_state(void) { IAMMultiMediaStream *mmstream = create_ammultimediastream(); @@ -6857,7 +6863,6 @@ START_TEST(amstream) test_audiostream_get_format(); test_audiostream_set_format(); test_audiostream_receive_connection(); - test_audiostream_end_of_stream(); test_audiostream_receive(); test_audiostream_initialize(); test_audiostream_begin_flush_end_flush(); @@ -6882,6 +6887,7 @@ START_TEST(amstream) test_ammediastream_join_filter(); test_ammediastream_join_filter_graph(); test_ammediastream_set_state(); + test_ammediastream_end_of_stream();
test_mediastreamfilter_get_state(); test_mediastreamfilter_stop_pause_run();
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/amstream/ddrawstream.c | 189 ++++++++++++-- dlls/amstream/tests/amstream.c | 446 +++++++++++++++++++++++++++++++-- 2 files changed, 594 insertions(+), 41 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index c3cb2fc49a7..972c2b9f4d0 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -59,11 +59,74 @@ struct ddraw_stream struct format format; FILTER_STATE state; BOOL eos; + CONDITION_VARIABLE update_queued_cv; + struct list update_queue; +}; + +struct ddraw_sample +{ + IDirectDrawStreamSample IDirectDrawStreamSample_iface; + LONG ref; + struct ddraw_stream *parent; + IDirectDrawSurface *surface; + RECT rect; + HANDLE update_event; + + struct list entry; + HRESULT update_hr; };
static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface, const RECT *rect, IDirectDrawStreamSample **ddraw_stream_sample);
+static void remove_queued_update(struct ddraw_sample *sample) +{ + list_remove(&sample->entry); + SetEvent(sample->update_event); +} + +static void flush_update_queue(struct ddraw_stream *stream, HRESULT update_hr) +{ + struct list *entry; + while ((entry = list_head(&stream->update_queue))) + { + struct ddraw_sample *sample = LIST_ENTRY(entry, struct ddraw_sample, entry); + sample->update_hr = update_hr; + remove_queued_update(sample); + } +} + +static HRESULT process_update(struct ddraw_sample *sample, int stride, BYTE *pointer) +{ + DDSURFACEDESC desc; + DWORD row_size; + const BYTE *src_row; + BYTE *dst_row; + DWORD row; + HRESULT hr; + + desc.dwSize = sizeof(desc); + hr = IDirectDrawSurface_Lock(sample->surface, &sample->rect, &desc, DDLOCK_WAIT, NULL); + if (FAILED(hr)) + return hr; + + row_size = (sample->rect.right - sample->rect.left) * desc.ddpfPixelFormat.u1.dwRGBBitCount / 8; + src_row = pointer; + dst_row = desc.lpSurface; + for (row = sample->rect.top; row < sample->rect.bottom; ++row) + { + memcpy(dst_row, src_row, row_size); + src_row += stride; + dst_row += desc.u1.lPitch; + } + + hr = IDirectDrawSurface_Unlock(sample->surface, desc.lpSurface); + if (FAILED(hr)) + return hr; + + return S_OK; +} + static BOOL is_format_compatible(struct ddraw_stream *stream, DWORD width, DWORD height, const DDPIXELFORMAT *connection_pf) { @@ -268,6 +331,8 @@ static HRESULT WINAPI ddraw_IAMMediaStream_SetState(IAMMediaStream *iface, FILTE
EnterCriticalSection(&stream->cs);
+ if (state == State_Stopped) + WakeConditionVariable(&stream->update_queued_cv); if (stream->state == State_Stopped) stream->eos = FALSE;
@@ -1079,6 +1144,8 @@ static HRESULT WINAPI ddraw_sink_EndOfStream(IPin *iface)
stream->eos = TRUE;
+ flush_update_queue(stream, MS_S_ENDOFSTREAM); + LeaveCriticalSection(&stream->cs);
return S_OK; @@ -1190,8 +1257,51 @@ static HRESULT WINAPI ddraw_meminput_GetAllocatorRequirements(IMemInputPin *ifac
static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample *sample) { - FIXME("iface %p, sample %p, stub!\n", iface, sample); - return E_NOTIMPL; + struct ddraw_stream *stream = impl_from_IMemInputPin(iface); + BITMAPINFOHEADER *bitmap_info; + BYTE *top_down_pointer; + int top_down_stride; + BYTE *pointer; + BOOL top_down; + int stride; + HRESULT hr; + + TRACE("stream %p, sample %p.\n", stream, sample); + + hr = IMediaSample_GetPointer(sample, &pointer); + if (FAILED(hr)) + return hr; + + EnterCriticalSection(&stream->cs); + + bitmap_info = &((VIDEOINFOHEADER *)stream->mt.pbFormat)->bmiHeader; + + stride = ((bitmap_info->biWidth * bitmap_info->biBitCount + 31) & ~31) / 8; + top_down = (bitmap_info->biHeight < 0); + + top_down_stride = top_down ? stride : -stride; + top_down_pointer = top_down ? pointer : pointer + stride * (bitmap_info->biHeight - 1); + + for (;;) + { + if (stream->state == State_Stopped) + { + LeaveCriticalSection(&stream->cs); + return S_OK; + } + if (!list_empty(&stream->update_queue)) + { + struct ddraw_sample *sample = LIST_ENTRY(list_head(&stream->update_queue), struct ddraw_sample, entry); + + sample->update_hr = process_update(sample, top_down_stride, top_down_pointer); + + remove_queued_update(sample); + LeaveCriticalSection(&stream->cs); + return S_OK; + } + + SleepConditionVariableCS(&stream->update_queued_cv, &stream->cs, INFINITE); + } }
static HRESULT WINAPI ddraw_meminput_ReceiveMultiple(IMemInputPin *iface, @@ -1241,6 +1351,8 @@ HRESULT ddraw_stream_create(IUnknown *outer, void **out) object->format.height = 100;
InitializeCriticalSection(&object->cs); + InitializeConditionVariable(&object->update_queued_cv); + list_init(&object->update_queue);
TRACE("Created ddraw stream %p.\n", object);
@@ -1249,15 +1361,6 @@ HRESULT ddraw_stream_create(IUnknown *outer, void **out) return S_OK; }
-struct ddraw_sample -{ - IDirectDrawStreamSample IDirectDrawStreamSample_iface; - LONG ref; - struct ddraw_stream *parent; - IDirectDrawSurface *surface; - RECT rect; -}; - static inline struct ddraw_sample *impl_from_IDirectDrawStreamSample(IDirectDrawStreamSample *iface) { return CONTAINING_RECORD(iface, struct ddraw_sample, IDirectDrawStreamSample_iface); @@ -1311,6 +1414,7 @@ static ULONG WINAPI ddraw_sample_Release(IDirectDrawStreamSample *iface)
if (sample->surface) IDirectDrawSurface_Release(sample->surface); + CloseHandle(sample->update_event); HeapFree(GetProcessHeap(), 0, sample); }
@@ -1349,12 +1453,66 @@ static HRESULT WINAPI ddraw_sample_SetSampleTimes(IDirectDrawStreamSample *iface return E_NOTIMPL; }
-static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface, DWORD flags, HANDLE event, - PAPCFUNC func_APC, DWORD APC_data) +static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface, + DWORD flags, HANDLE event, PAPCFUNC apc_func, DWORD apc_data) { - FIXME("(%p)->(%x,%p,%p,%u): stub\n", iface, flags, event, func_APC, APC_data); + struct ddraw_sample *sample = impl_from_IDirectDrawStreamSample(iface);
- return S_OK; + TRACE("sample %p, flags %#x, event %p, apc_func %p, apc_data %#x.\n", + sample, flags, event, apc_func, apc_data); + + if (event && apc_func) + return E_INVALIDARG; + + if (apc_func) + { + FIXME("APC support is not implemented!\n"); + return E_NOTIMPL; + } + + if (event) + { + FIXME("Event parameter support is not implemented!\n"); + return E_NOTIMPL; + } + + if (flags & ~SSUPDATE_ASYNC) + { + FIXME("Unsupported flags %#x.\n", flags); + return E_NOTIMPL; + } + + EnterCriticalSection(&sample->parent->cs); + + if (sample->parent->state != State_Running) + { + LeaveCriticalSection(&sample->parent->cs); + return MS_E_NOTRUNNING; + } + if (!sample->parent->peer || sample->parent->eos) + { + LeaveCriticalSection(&sample->parent->cs); + return MS_S_ENDOFSTREAM; + } + if (MS_S_PENDING == sample->update_hr) + { + LeaveCriticalSection(&sample->parent->cs); + return MS_E_BUSY; + } + + sample->update_hr = MS_S_PENDING; + ResetEvent(sample->update_event); + list_add_tail(&sample->parent->update_queue, &sample->entry); + WakeConditionVariable(&sample->parent->update_queued_cv); + + LeaveCriticalSection(&sample->parent->cs); + + if (flags & SSUPDATE_ASYNC) + return MS_S_PENDING; + + WaitForSingleObject(sample->update_event, INFINITE); + + return sample->update_hr; }
static HRESULT WINAPI ddraw_sample_CompletionStatus(IDirectDrawStreamSample *iface, DWORD flags, DWORD milliseconds) @@ -1425,6 +1583,7 @@ static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDraw object->IDirectDrawStreamSample_iface.lpVtbl = &DirectDrawStreamSample_Vtbl; object->ref = 1; object->parent = parent; + object->update_event = CreateEventW(NULL, FALSE, FALSE, NULL); IAMMediaStream_AddRef(&parent->IAMMediaStream_iface); ++parent->sample_refs;
diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index df9d148493f..e5d1dd621f3 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -3867,7 +3867,7 @@ static void test_audiostream_begin_flush_end_flush(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
-static IMediaSample *audiostream_allocate_sample(struct testfilter *source, const BYTE *input_data, DWORD input_length) +static IMediaSample *ammediastream_allocate_sample(struct testfilter *source, const BYTE *input_data, DWORD input_length) { IMediaSample *sample; BYTE *sample_data; @@ -3936,7 +3936,7 @@ static void test_audiostream_new_segment(void) hr = IPin_NewSegment(pin, 11111111, 22222222, 1.0); ok(hr == S_OK, "Got hr %#x.\n", hr);
- media_sample = audiostream_allocate_sample(&source, test_data, 5); + media_sample = ammediastream_allocate_sample(&source, test_data, 5); start_time = 12345678; end_time = 23456789; hr = IMediaSample_SetTime(media_sample, &start_time, &end_time); @@ -3958,7 +3958,7 @@ static void test_audiostream_new_segment(void) hr = IPin_NewSegment(pin, 11111111, 22222222, 2.0); ok(hr == S_OK, "Got hr %#x.\n", hr);
- media_sample = audiostream_allocate_sample(&source, test_data, 5); + media_sample = ammediastream_allocate_sample(&source, test_data, 5); start_time = 12345678; end_time = 23456789; hr = IMediaSample_SetTime(media_sample, &start_time, &end_time); @@ -4001,27 +4001,28 @@ static void CALLBACK apc_func(ULONG_PTR param) { }
-static IPin *audiostream_pin; -static IMemInputPin *audiostream_mem_input_pin; -static IMediaSample *audiostream_media_sample; +static IPin *ammediastream_pin; +static IMemInputPin *ammediastream_mem_input_pin; +static IMediaSample *ammediastream_media_sample; +static DWORD ammediastream_sleep_time;
-static DWORD CALLBACK audiostream_end_of_stream(void *param) +static DWORD CALLBACK ammediastream_end_of_stream(void *param) { HRESULT hr;
- Sleep(100); - hr = IPin_EndOfStream(audiostream_pin); + Sleep(ammediastream_sleep_time); + hr = IPin_EndOfStream(ammediastream_pin); ok(hr == S_OK, "Got hr %#x.\n", hr);
return 0; }
-static DWORD CALLBACK audiostream_receive(void *param) +static DWORD CALLBACK ammediastream_receive(void *param) { HRESULT hr;
- Sleep(100); - hr = IMemInputPin_Receive(audiostream_mem_input_pin, audiostream_media_sample); + Sleep(ammediastream_sleep_time); + hr = IMemInputPin_Receive(ammediastream_mem_input_pin, ammediastream_media_sample); ok(hr == S_OK, "Got hr %#x.\n", hr);
return 0; @@ -4102,7 +4103,7 @@ static void test_audiostreamsample_update(void) hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); ok(hr == S_OK, "Got hr %#x.\n", hr);
- media_sample1 = audiostream_allocate_sample(&source, test_data, 8); + media_sample1 = ammediastream_allocate_sample(&source, test_data, 8); hr = IMemInputPin_Receive(mem_input_pin, media_sample1); ok(hr == S_OK, "Got hr %#x.\n", hr); ref = get_refcount(media_sample1); @@ -4120,7 +4121,7 @@ static void test_audiostreamsample_update(void) ref = get_refcount(media_sample1); ok(ref == 2, "Got unexpected refcount %d.\n", ref);
- media_sample2 = audiostream_allocate_sample(&source, test_data, 8); + media_sample2 = ammediastream_allocate_sample(&source, test_data, 8); hr = IMemInputPin_Receive(mem_input_pin, media_sample2); ok(hr == S_OK, "Got hr %#x.\n", hr); ref = get_refcount(media_sample2); @@ -4162,7 +4163,7 @@ static void test_audiostreamsample_update(void) hr = IMediaControl_Pause(media_control); ok(hr == S_OK, "Got hr %#x.\n", hr);
- media_sample1 = audiostream_allocate_sample(&source, test_data, 6); + media_sample1 = ammediastream_allocate_sample(&source, test_data, 6); hr = IMemInputPin_Receive(mem_input_pin, media_sample1); ok(hr == S_OK, "Got hr %#x.\n", hr); ref = IMediaSample_Release(media_sample1); @@ -4176,11 +4177,12 @@ static void test_audiostreamsample_update(void) hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); ok(hr == S_OK, "Got hr %#x.\n", hr);
- media_sample1 = audiostream_allocate_sample(&source, test_data, 6); + media_sample1 = ammediastream_allocate_sample(&source, test_data, 6);
- audiostream_mem_input_pin = mem_input_pin; - audiostream_media_sample = media_sample1; - thread = CreateThread(NULL, 0, audiostream_receive, NULL, 0, NULL); + ammediastream_mem_input_pin = mem_input_pin; + ammediastream_media_sample = media_sample1; + ammediastream_sleep_time = 100; + thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL);
hr = IAudioStreamSample_Update(stream_sample, 0, NULL, NULL, 0); ok(hr == S_OK, "Got hr %#x.\n", hr); @@ -4197,8 +4199,9 @@ static void test_audiostreamsample_update(void) ref = IMediaSample_Release(media_sample1); ok(!ref, "Got outstanding refcount %d.\n", ref);
- audiostream_pin = pin; - thread = CreateThread(NULL, 0, audiostream_end_of_stream, NULL, 0, NULL); + ammediastream_pin = pin; + ammediastream_sleep_time = 100; + thread = CreateThread(NULL, 0, ammediastream_end_of_stream, NULL, 0, NULL);
hr = IAudioStreamSample_Update(stream_sample, 0, NULL, NULL, 0); ok(hr == MS_S_ENDOFSTREAM, "Got hr %#x.\n", hr); @@ -4312,7 +4315,7 @@ void test_audiostreamsample_completion_status(void) hr = IAudioStreamSample_CompletionStatus(stream_sample1, 0, 0); ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
- media_sample = audiostream_allocate_sample(&source, test_data, 6); + media_sample = ammediastream_allocate_sample(&source, test_data, 6); hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample); ok(hr == S_OK, "Got hr %#x.\n", hr); ref = IMediaSample_Release(media_sample); @@ -4327,7 +4330,7 @@ void test_audiostreamsample_completion_status(void) hr = IAudioStreamSample_Update(stream_sample2, SSUPDATE_ASYNC, NULL, NULL, 0); ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
- media_sample = audiostream_allocate_sample(&source, test_data, 12); + media_sample = ammediastream_allocate_sample(&source, test_data, 12); hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample); ok(hr == S_OK, "Got hr %#x.\n", hr); ref = IMediaSample_Release(media_sample); @@ -4365,7 +4368,7 @@ void test_audiostreamsample_completion_status(void) hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); ok(hr == S_OK, "Got hr %#x.\n", hr);
- media_sample = audiostream_allocate_sample(&source, test_data, 6); + media_sample = ammediastream_allocate_sample(&source, test_data, 6); hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample); ok(hr == S_OK, "Got hr %#x.\n", hr); ref = IMediaSample_Release(media_sample); @@ -4506,7 +4509,7 @@ static void test_audiostreamsample_get_sample_times(void) ok(start_time == 0, "Got start time %s.\n", wine_dbgstr_longlong(start_time)); ok(end_time == 0, "Got end time %s.\n", wine_dbgstr_longlong(end_time));
- media_sample = audiostream_allocate_sample(&source, test_data, 8); + media_sample = ammediastream_allocate_sample(&source, test_data, 8); start_time = 12345678; end_time = 23456789; hr = IMediaSample_SetTime(media_sample, &start_time, &end_time); @@ -4525,7 +4528,7 @@ static void test_audiostreamsample_get_sample_times(void) ok(start_time == 12345678, "Got start time %s.\n", wine_dbgstr_longlong(start_time)); ok(end_time == 12347946, "Got end time %s.\n", wine_dbgstr_longlong(end_time));
- media_sample = audiostream_allocate_sample(&source, test_data, 6); + media_sample = ammediastream_allocate_sample(&source, test_data, 6); start_time = 12345678; end_time = 23456789; hr = IMediaSample_SetTime(media_sample, &start_time, &end_time); @@ -5076,6 +5079,108 @@ static void test_ddrawstream_set_format(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+static void test_ddrawstream_receive(void) +{ + ALLOCATOR_PROPERTIES properties = + { + .cBuffers = 1, + .cbBuffer = 16, + .cbAlign = 1, + }; + + IAMMultiMediaStream *mmstream = create_ammultimediastream(); + ALLOCATOR_PROPERTIES actual; + IMediaStreamFilter *filter; + struct testfilter source; + IMemAllocator *allocator; + IGraphBuilder *graph; + IMediaStream *stream; + IMediaSample *sample; + HANDLE thread; + HRESULT hr; + ULONG ref; + IPin *pin; + + hr = IAMMultiMediaStream_Initialize(mmstream, STREAMTYPE_READ, 0, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IAMMultiMediaStream_GetFilter(mmstream, &filter); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(!!filter, "Expected non-null filter.\n"); + hr = IAMMultiMediaStream_AddMediaStream(mmstream, NULL, &MSPID_PrimaryVideo, 0, &stream); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaStream_QueryInterface(stream, &IID_IPin, (void **)&pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IAMMultiMediaStream_GetFilterGraph(mmstream, &graph); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(graph != NULL, "Expected non-NULL graph.\n"); + testfilter_init(&source); + hr = IGraphBuilder_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (void **)&allocator); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMemAllocator_SetProperties(allocator, &properties, &actual); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMemAllocator_Commit(allocator); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IGraphBuilder_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &rgb32_mt); + 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 = IMemInputPin_Receive(source.source.pMemInputPin, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ref = IMediaSample_Release(sample); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); + 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); + + ammediastream_mem_input_pin = source.source.pMemInputPin; + ammediastream_media_sample = sample; + ammediastream_sleep_time = 0; + thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL); + + ok(WaitForSingleObject(thread, 100) == WAIT_TIMEOUT, "Receive returned prematurely.\n"); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n"); + CloseHandle(thread); + + ref = IMediaSample_Release(sample); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMemInputPin_Receive(source.source.pMemInputPin, sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ref = IMediaSample_Release(sample); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + IGraphBuilder_Disconnect(graph, pin); + IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface); + + hr = IMemAllocator_Decommit(allocator); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ref = IAMMultiMediaStream_Release(mmstream); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IGraphBuilder_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IMediaStreamFilter_Release(filter); + ok(!ref, "Got outstanding refcount %d.\n", ref); + IPin_Release(pin); + ref = IMediaStream_Release(stream); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IMemAllocator_Release(allocator); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + static void check_ammediastream_join_am_multi_media_stream(const CLSID *clsid) { IAMMultiMediaStream *mmstream = create_ammultimediastream(); @@ -6829,6 +6934,293 @@ static void test_ddrawstreamsample_get_media_stream(void) ok(!ref, "Got outstanding refcount %d.\n", ref); }
+static void test_ddrawstreamsample_update(void) +{ + static const BYTE initial_data[] = + { + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + }; + static const BYTE test_data[] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + }; + IAMMultiMediaStream *mmstream = create_ammultimediastream(); + IDirectDrawStreamSample *stream_sample; + IDirectDrawMediaStream *ddraw_stream; + IMediaControl *media_control; + IDirectDrawSurface *surface; + IMemInputPin *mem_input_pin; + IMediaSample *media_sample; + IMediaFilter *media_filter; + struct testfilter source; + IGraphBuilder *graph; + IMediaStream *stream; + VIDEOINFO video_info; + DDSURFACEDESC desc; + IDirectDraw *ddraw; + AM_MEDIA_TYPE mt; + HANDLE thread; + HANDLE event; + HRESULT hr; + ULONG ref; + IPin *pin; + RECT rect; + int i; + + hr = IAMMultiMediaStream_Initialize(mmstream, STREAMTYPE_READ, 0, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IAMMultiMediaStream_AddMediaStream(mmstream, NULL, &MSPID_PrimaryVideo, 0, &stream); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaStream_QueryInterface(stream, &IID_IDirectDrawMediaStream, (void **)&ddraw_stream); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaStream_QueryInterface(stream, &IID_IPin, (void **)&pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaStream_QueryInterface(stream, &IID_IMemInputPin, (void **)&mem_input_pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IDirectDrawMediaStream_GetDirectDraw(ddraw_stream, &ddraw); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IAMMultiMediaStream_GetFilterGraph(mmstream, &graph); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(graph != NULL, "Expected non-NULL graph.\n"); + hr = IGraphBuilder_QueryInterface(graph, &IID_IMediaControl, (void **)&media_control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IGraphBuilder_QueryInterface(graph, &IID_IMediaFilter, (void **)&media_filter); + ok(hr == S_OK, "Got hr %#x.\n", hr); + testfilter_init(&source); + hr = IGraphBuilder_AddFilter(graph, &source.filter.IBaseFilter_iface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(event != NULL, "Expected non-NULL event."); + + hr = IMediaFilter_SetSyncSource(media_filter, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + desc = rgb24_format; + desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + desc.dwWidth = 4; + desc.dwHeight = 5; + desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; + hr = IDirectDraw_CreateSurface(ddraw, &desc, &surface, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + /* Make the rect width equal to the surface width, as the native + * implementation incorrectly handles rects that are not full-width + * when the ddraw stream's custom allocator is not used. */ + SetRect(&rect, 0, 1, 4, 3); + hr = IDirectDrawMediaStream_CreateSample(ddraw_stream, surface, &rect, 0, &stream_sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IDirectDrawStreamSample_Update(stream_sample, 0, event, apc_func, 0); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + + hr = IDirectDrawStreamSample_Update(stream_sample, 0, NULL, NULL, 0); + ok(hr == MS_E_NOTRUNNING, "Got hr %#x.\n", hr); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IDirectDrawStreamSample_Update(stream_sample, 0, NULL, NULL, 0); + ok(hr == MS_S_ENDOFSTREAM, "Got hr %#x.\n", hr); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP); + ok(hr == S_OK, "Got hr %#x.\n", hr); + video_info = rgb24_video_info; + video_info.bmiHeader.biWidth = 4; + video_info.bmiHeader.biHeight = -2; + mt = rgb24_mt; + mt.pbFormat = (BYTE *)&video_info; + hr = IGraphBuilder_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IDirectDrawSurface_Lock(surface, NULL, &desc, 0, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + for (i = 0; i < 5; ++i) + memcpy((BYTE *)desc.lpSurface + i * desc.lPitch, initial_data, 12); + hr = IDirectDrawSurface_Unlock(surface, desc.lpSurface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data)); + + ammediastream_mem_input_pin = mem_input_pin; + ammediastream_media_sample = media_sample; + ammediastream_sleep_time = 0; + thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL); + + Sleep(100); + hr = IDirectDrawStreamSample_Update(stream_sample, 0, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IDirectDrawSurface_Lock(surface, NULL, &desc, 0, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(memcmp((BYTE *)desc.lpSurface + 0 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n"); + ok(memcmp((BYTE *)desc.lpSurface + 1 * desc.lPitch, &test_data[0], 12) == 0, "Sample data didn't match.\n"); + ok(memcmp((BYTE *)desc.lpSurface + 2 * desc.lPitch, &test_data[12], 12) == 0, "Sample data didn't match.\n"); + ok(memcmp((BYTE *)desc.lpSurface + 3 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n"); + ok(memcmp((BYTE *)desc.lpSurface + 4 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n"); + hr = IDirectDrawSurface_Unlock(surface, desc.lpSurface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n"); + CloseHandle(thread); + + ref = IMediaSample_Release(media_sample); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IGraphBuilder_Disconnect(graph, pin); + IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface); + video_info = rgb24_video_info; + video_info.bmiHeader.biWidth = 4; + video_info.bmiHeader.biHeight = 2; + mt = rgb24_mt; + mt.pbFormat = (BYTE *)&video_info; + hr = IGraphBuilder_ConnectDirect(graph, &source.source.pin.IPin_iface, pin, &mt); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IDirectDrawSurface_Lock(surface, NULL, &desc, 0, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + for (i = 0; i < 5; ++i) + memcpy((BYTE *)desc.lpSurface + i * desc.lPitch, initial_data, 12); + hr = IDirectDrawSurface_Unlock(surface, desc.lpSurface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data)); + + ammediastream_mem_input_pin = mem_input_pin; + ammediastream_media_sample = media_sample; + ammediastream_sleep_time = 0; + thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL); + + Sleep(100); + hr = IDirectDrawStreamSample_Update(stream_sample, 0, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IDirectDrawSurface_Lock(surface, NULL, &desc, 0, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(memcmp((BYTE *)desc.lpSurface + 0 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n"); + ok(memcmp((BYTE *)desc.lpSurface + 1 * desc.lPitch, &test_data[12], 12) == 0, "Sample data didn't match.\n"); + ok(memcmp((BYTE *)desc.lpSurface + 2 * desc.lPitch, &test_data[0], 12) == 0, "Sample data didn't match.\n"); + ok(memcmp((BYTE *)desc.lpSurface + 3 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n"); + ok(memcmp((BYTE *)desc.lpSurface + 4 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n"); + hr = IDirectDrawSurface_Unlock(surface, desc.lpSurface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n"); + CloseHandle(thread); + + ref = IMediaSample_Release(media_sample); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + hr = IPin_EndOfStream(pin); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IDirectDrawStreamSample_Update(stream_sample, 0, NULL, NULL, 0); + ok(hr == MS_S_ENDOFSTREAM, "Got hr %#x.\n", hr); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IMediaControl_Pause(media_control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IDirectDrawStreamSample_Update(stream_sample, 0, NULL, NULL, 0); + ok(hr == MS_E_NOTRUNNING, "Got hr %#x.\n", hr); + + hr = IMediaControl_Stop(media_control); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IDirectDrawSurface_Lock(surface, NULL, &desc, 0, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + for (i = 0; i < 5; ++i) + memcpy((BYTE *)desc.lpSurface + i * desc.lPitch, initial_data, 12); + hr = IDirectDrawSurface_Unlock(surface, desc.lpSurface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data)); + + ammediastream_mem_input_pin = mem_input_pin; + ammediastream_media_sample = media_sample; + ammediastream_sleep_time = 100; + thread = CreateThread(NULL, 0, ammediastream_receive, NULL, 0, NULL); + + hr = IDirectDrawStreamSample_Update(stream_sample, 0, NULL, NULL, 0); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IDirectDrawSurface_Lock(surface, NULL, &desc, 0, NULL); + ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(memcmp((BYTE *)desc.lpSurface + 0 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n"); + ok(memcmp((BYTE *)desc.lpSurface + 1 * desc.lPitch, &test_data[12], 12) == 0, "Sample data didn't match.\n"); + ok(memcmp((BYTE *)desc.lpSurface + 2 * desc.lPitch, &test_data[0], 12) == 0, "Sample data didn't match.\n"); + ok(memcmp((BYTE *)desc.lpSurface + 3 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n"); + ok(memcmp((BYTE *)desc.lpSurface + 4 * desc.lPitch, initial_data, 12) == 0, "Sample data didn't match.\n"); + hr = IDirectDrawSurface_Unlock(surface, desc.lpSurface); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n"); + CloseHandle(thread); + + ref = IMediaSample_Release(media_sample); + ok(!ref, "Got outstanding refcount %d.\n", ref); + + ammediastream_pin = pin; + ammediastream_sleep_time = 100; + thread = CreateThread(NULL, 0, ammediastream_end_of_stream, NULL, 0, NULL); + + hr = IDirectDrawStreamSample_Update(stream_sample, 0, NULL, NULL, 0); + ok(hr == MS_S_ENDOFSTREAM, "Got hr %#x.\n", hr); + + ok(!WaitForSingleObject(thread, 2000), "Wait timed out.\n"); + CloseHandle(thread); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP); + ok(hr == S_OK, "Got hr %#x.\n", hr); + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IDirectDrawStreamSample_Update(stream_sample, SSUPDATE_ASYNC, NULL, NULL, 0); + ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr); + EXPECT_REF(stream_sample, 1); + + hr = IDirectDrawStreamSample_Update(stream_sample, SSUPDATE_ASYNC, NULL, NULL, 0); + ok(hr == MS_E_BUSY, "Got hr %#x.\n", hr); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP); + ok(hr == S_OK, "Got hr %#x.\n", hr); + IGraphBuilder_Disconnect(graph, pin); + IGraphBuilder_Disconnect(graph, &source.source.pin.IPin_iface); + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + hr = IDirectDrawStreamSample_Update(stream_sample, 0, NULL, NULL, 0); + ok(hr == MS_S_ENDOFSTREAM, "Got hr %#x.\n", hr); + + hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_STOP); + ok(hr == S_OK, "Got hr %#x.\n", hr); + + CloseHandle(event); + ref = IDirectDrawStreamSample_Release(stream_sample); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IDirectDrawSurface_Release(surface); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IAMMultiMediaStream_Release(mmstream); + ok(!ref, "Got outstanding refcount %d.\n", ref); + IMediaControl_Release(media_control); + IMediaFilter_Release(media_filter); + ref = IGraphBuilder_Release(graph); + ok(!ref, "Got outstanding refcount %d.\n", ref); + IPin_Release(pin); + IMemInputPin_Release(mem_input_pin); + IDirectDrawMediaStream_Release(ddraw_stream); + ref = IMediaStream_Release(stream); + ok(!ref, "Got outstanding refcount %d.\n", ref); + ref = IDirectDraw_Release(ddraw); + ok(!ref, "Got outstanding refcount %d.\n", ref); +} + START_TEST(amstream) { const WCHAR *test_avi_path; @@ -6880,8 +7272,10 @@ START_TEST(amstream) test_ddrawstream_create_sample(); test_ddrawstream_get_format(); test_ddrawstream_set_format(); + test_ddrawstream_receive();
test_ddrawstreamsample_get_media_stream(); + test_ddrawstreamsample_update();
test_ammediastream_join_am_multi_media_stream(); test_ammediastream_join_filter();
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
Signed-off-by: Zebediah Figura z.figura12@gmail.com
(Patches 2 and 3 in this series were already committed.)