From: Zebediah Figura Subject: Re: [PATCH 5/5] amstream: Implement IDirectDrawStreamSample::Update. Message-Id: Date: Wed, 23 Sep 2020 15:37:41 -0500 In-Reply-To: <20200923185500.9458-5-baskanov@gmail.com> References: <20200923185500.9458-1-baskanov@gmail.com> <20200923185500.9458-5-baskanov@gmail.com> Just a few nitpicks here... On 9/23/20 1:55 PM, Anton Baskanov wrote: > Signed-off-by: Anton Baskanov > --- > 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; "/ 8" is clearer and should compile to the same thing. > + 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; Same here. > + 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); You're not using SSUPDATE_ASYNC, so you can get rid of the Sleep() call here, right? > + 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); And here. > + 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); hr isn't checked here (though omitting the call or assignment is also fine, I think.) > + > + 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(); > -----BEGIN PGP SIGNATURE----- iQEzBAEBCAAdFiEENTo75Twe9rbPART3DZ01igeheEAFAl9rshYACgkQDZ01igeh eEDROQf+LBrEJ3hth6DXiaDf9UQi8NwjlyRcIj4cy9Rm8f5XFy8pfjjssQEnqE55 az6Pl3hnPmS6vkgaOAId4nG+ah8C4BsvSeP174SIKFNWBWcuCkmeBlkI3X/Pg8dM cowrnFpkWu+ZlqFrR20iNtfCYpeHI7dhNSD2cAdrAnI6YF6ryTZNHoE0KWCunGQo qZvmyhqupEKdOy8Rn8GCW5sue6DP+Li6hb0rPt+pHfI1okopt53cIYwAmqStwKnu h5JD2dyu5dORiW2N4WO7jq5SQ6I5dIBSF0OwSsqFrhJhPMjA+CWGBajwgGv/XE8S y18dgAGhhWoXPET8t0q42XDcGdINZw== =N2Wb -----END PGP SIGNATURE-----