On 10/8/20 2:02 PM, Anton Baskanov wrote:
Signed-off-by: Anton Baskanov baskanov@gmail.com
dlls/amstream/ddrawstream.c | 36 ++++++++++++++--------- dlls/amstream/tests/amstream.c | 53 ++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 14 deletions(-)
diff --git a/dlls/amstream/ddrawstream.c b/dlls/amstream/ddrawstream.c index 5e6e1555d7c..0e5e54bd80d 100644 --- a/dlls/amstream/ddrawstream.c +++ b/dlls/amstream/ddrawstream.c @@ -75,10 +75,12 @@ struct ddraw_sample RECT rect; STREAM_TIME start_time; STREAM_TIME end_time;
BOOL continuous_update; CONDITION_VARIABLE update_cv;
struct list entry; HRESULT update_hr;
BOOL busy;
As far as I can tell, this is identical to "update_hr == MS_S_PENDING", except that you set update_hr to MS_S_NOUPDATE in the continuous case instead, right?
Would it be simpler, then, to keep most of the code handling update_hr as it is, and instead handle COMPSTAT_NOUPDATEOK/MS_S_NOUPDATE specially in ::CompletionStatus()?
};
static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDrawSurface *surface, @@ -86,6 +88,7 @@ static HRESULT ddrawstreamsample_create(struct ddraw_stream *parent, IDirectDraw
static void remove_queued_update(struct ddraw_sample *sample) {
- sample->busy = FALSE; list_remove(&sample->entry); WakeConditionVariable(&sample->update_cv);
} @@ -1348,7 +1351,16 @@ static HRESULT WINAPI ddraw_meminput_Receive(IMemInputPin *iface, IMediaSample * sample->update_hr = process_update(sample, top_down_stride, top_down_pointer, start_stream_time, end_stream_time);
remove_queued_update(sample);
if (sample->continuous_update && SUCCEEDED(sample->update_hr))
{
list_remove(&sample->entry);
list_add_tail(&sample->parent->update_queue, &sample->entry);
}
else
{
remove_queued_update(sample);
}
LeaveCriticalSection(&stream->cs); return S_OK; }
@@ -1540,12 +1552,6 @@ static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface, 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)
@@ -1559,13 +1565,16 @@ static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface, LeaveCriticalSection(&sample->parent->cs); return MS_S_ENDOFSTREAM; }
- if (MS_S_PENDING == sample->update_hr)
- if (sample->busy) { LeaveCriticalSection(&sample->parent->cs); return MS_E_BUSY; }
- sample->update_hr = MS_S_PENDING;
- sample->continuous_update = (flags & SSUPDATE_ASYNC) && (flags & SSUPDATE_CONTINUOUS);
This implies that specifying SSUPDATE_CONTINUOUS without SSUPDATE_ASYNC is equivalent to zero flags, which seems surprising. Is that correct?
It may not exactly be easy to test, if it's not correct, SSUPDATE_CONTINUOUS without SSUPDATE_ASYNC ends up doing a continuous update but blocking (until EOS?), but if this line is correct as-is, then I'd like to see a test for that.
- sample->update_hr = MS_S_NOUPDATE;
- sample->busy = TRUE; list_add_tail(&sample->parent->update_queue, &sample->entry); WakeConditionVariable(&sample->parent->update_queued_cv);
@@ -1575,7 +1584,7 @@ static HRESULT WINAPI ddraw_sample_Update(IDirectDrawStreamSample *iface, return MS_S_PENDING; }
- while (sample->update_hr == MS_S_PENDING)
while (sample->busy) SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, INFINITE);
LeaveCriticalSection(&sample->parent->cs);
@@ -1592,18 +1601,17 @@ static HRESULT WINAPI ddraw_sample_CompletionStatus(IDirectDrawStreamSample *ifa
EnterCriticalSection(&sample->parent->cs);
- if (sample->update_hr == MS_S_PENDING)
- if (sample->busy) { if (flags & (COMPSTAT_NOUPDATEOK | COMPSTAT_ABORT)) {
sample->update_hr = MS_S_NOUPDATE; remove_queued_update(sample); } else if (flags & COMPSTAT_WAIT) { DWORD start_time = GetTickCount(); DWORD elapsed = 0;
while (sample->update_hr == MS_S_PENDING && elapsed < milliseconds)
while (sample->busy && elapsed < milliseconds) { DWORD sleep_time = milliseconds - elapsed; if (!SleepConditionVariableCS(&sample->update_cv, &sample->parent->cs, sleep_time))
@@ -1613,7 +1621,7 @@ static HRESULT WINAPI ddraw_sample_CompletionStatus(IDirectDrawStreamSample *ifa } }
- hr = sample->update_hr;
hr = sample->busy ? MS_S_PENDING : sample->update_hr;
LeaveCriticalSection(&sample->parent->cs);
diff --git a/dlls/amstream/tests/amstream.c b/dlls/amstream/tests/amstream.c index 9dda5882a4f..6e6f7483b49 100644 --- a/dlls/amstream/tests/amstream.c +++ b/dlls/amstream/tests/amstream.c @@ -7665,6 +7665,59 @@ static void test_ddrawstreamsample_completion_status(void) hr = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN); ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC | SSUPDATE_CONTINUOUS, NULL, NULL, 0);
- ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
- hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_NOUPDATEOK, 0);
- ok(hr == MS_S_NOUPDATE, "Got hr %#x.\n", hr);
- hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC | SSUPDATE_CONTINUOUS, NULL, NULL, 0);
- ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
- hr = IDirectDrawStreamSample_Update(stream_sample2, SSUPDATE_ASYNC, NULL, NULL, 0);
- ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
- hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
- ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
- media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data));
- hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- ref = IMediaSample_Release(media_sample);
- ok(!ref, "Got outstanding refcount %d.\n", ref);
- hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
- ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
Can we check that sample2 isn't satisfied here? [Or is native not consistent?]
- media_sample = ammediastream_allocate_sample(&source, test_data, sizeof(test_data));
- hr = IMemInputPin_Receive(source.source.pMemInputPin, media_sample);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- ref = IMediaSample_Release(media_sample);
- ok(!ref, "Got outstanding refcount %d.\n", ref);
- hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 0);
- ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
- hr = IDirectDrawStreamSample_CompletionStatus(stream_sample2, 0, 0);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, COMPSTAT_NOUPDATEOK, 0);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC | SSUPDATE_CONTINUOUS, NULL, NULL, 0);
- ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
- hr = IPin_EndOfStream(pin);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = IDirectDrawStreamSample_CompletionStatus(stream_sample1, 0, 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 = IAMMultiMediaStream_SetState(mmstream, STREAMSTATE_RUN);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = IDirectDrawStreamSample_Update(stream_sample1, SSUPDATE_ASYNC, NULL, NULL, 0); ok(hr == MS_S_PENDING, "Got hr %#x.\n", hr);
The DirectX documentation is rather vague about what "continuous" means, or the behaviour surrounding this flag, and even after these tests I'm still left with a lot of questions. In particular:
* CompletionStatus() with no flags evidently doesn't take the sample out of continuous state, but does COMPSTAT_NOUPDATEOK? What about COMPSTAT_ABORT?
* IPin::EndOfStream() takes the sample out of continuous state, as far as I think it's possible to tell. The same applies to IPin::BeginFlush() and IAMMediaStream::SetState(State_Stopped), right?
* What about calling Update() again, with the same flags, or different ones?
* COMPSTAT_WAIT blocks until the sample is taken out of continuous state, right? This doesn't necessarily need to be tested if the answer is "yes", since it'll be more than a little annoying; I just want to make sure.
Also, can we test briefly that Receive() does update the ddraw surface every time?