Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/amstream/ddrawstream.c | 167 ++++++++++++++-- dlls/amstream/tests/amstream.c | 342 ++++++++++++++++++++++++++++++--- 2 files changed, 470 insertions(+), 39 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index 856c8775445..84f11d3758d 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -60,11 +60,73 @@ struct ddraw_stream FILTER_STATE state; BOOL eos; HANDLE update_queued_event; + 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 >> 3; + 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) { @@ -1083,6 +1145,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; @@ -1195,11 +1259,30 @@ static HRESULT WINAPI ddraw_meminput_GetAllocatorRequirements(IMemInputPin *ifac static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample *sample) { 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) >> 3; + 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) @@ -1207,6 +1290,16 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample * 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; + }
LeaveCriticalSection(&stream->cs); WaitForSingleObject(stream->update_queued_event, INFINITE); @@ -1262,6 +1355,7 @@ HRESULT ddraw_stream_create(IUnknown *outer, void **out) object->format.height = 100;
InitializeCriticalSection(&object->cs); + list_init(&object->update_queue);
TRACE("Created ddraw stream %p.\n", object);
@@ -1270,15 +1364,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); @@ -1332,6 +1417,7 @@ static ULONG WINAPI ddraw_sample_Release(IDirectDrawStreamSample *iface)
if (sample->surface) IDirectDrawSurface_Release(sample->surface); + CloseHandle(sample->update_event); HeapFree(GetProcessHeap(), 0, sample); }
@@ -1370,12 +1456,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); + SetEvent(sample->parent->update_queued_event); + + 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) @@ -1445,6 +1585,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 d0c20f6253a..73d69452536 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); @@ -6946,6 +6949,292 @@ 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); + + 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; @@ -7000,6 +7289,7 @@ START_TEST(amstream) test_ddrawstream_receive();
test_ddrawstreamsample_get_media_stream(); + test_ddrawstreamsample_update();
test_ammediastream_join_am_multi_media_stream(); test_ammediastream_join_filter();