[PATCH 5/5] amstream: Implement IDirectDrawStreamSample::Update.

Anton Baskanov baskanov at gmail.com
Wed Sep 23 13:55:00 CDT 2020


Signed-off-by: Anton Baskanov <baskanov at 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();
-- 
2.17.1




More information about the wine-devel mailing list