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

Zebediah Figura zfigura at codeweavers.com
Thu Sep 24 16:08:36 CDT 2020



On 9/24/20 2:07 PM, Anton Baskanov wrote:
> On Thursday, 24 September 2020 03:37:41 +07 you wrote:
>> Just a few nitpicks here...
>>
>> On 9/23/20 1:55 PM, Anton Baskanov wrote:
>>> 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;
>> "/ 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?
> 
> This test exercises the code path where Receive() has to wait for an update to 
> be queued. I added the Sleep() call so that the thread has a chance to enter 
> the Receive() function before Update() is called.

Thanks; that makes sense. It's a small enough sleep that I'll call it
harmless.

> 
>>
>>> +    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();
> 
> 
> 
> 
> 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20200924/21759acc/attachment-0001.sig>


More information about the wine-devel mailing list