mfplat: Implement time source state changes.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
58a93786e2
commit
3865a8c9d5
|
@ -1,5 +1,4 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2014 Austin English
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
|
@ -44,6 +43,8 @@ struct system_time_source
|
|||
IMFPresentationTimeSource IMFPresentationTimeSource_iface;
|
||||
IMFClockStateSink IMFClockStateSink_iface;
|
||||
LONG refcount;
|
||||
MFCLOCK_STATE state;
|
||||
CRITICAL_SECTION cs;
|
||||
};
|
||||
|
||||
static struct system_time_source *impl_from_IMFPresentationTimeSource(IMFPresentationTimeSource *iface)
|
||||
|
@ -3085,7 +3086,10 @@ static ULONG WINAPI system_time_source_Release(IMFPresentationTimeSource *iface)
|
|||
TRACE("%p, refcount %u.\n", iface, refcount);
|
||||
|
||||
if (!refcount)
|
||||
{
|
||||
DeleteCriticalSection(&source->cs);
|
||||
heap_free(source);
|
||||
}
|
||||
|
||||
return refcount;
|
||||
}
|
||||
|
@ -3120,9 +3124,15 @@ static HRESULT WINAPI system_time_source_GetContinuityKey(IMFPresentationTimeSou
|
|||
static HRESULT WINAPI system_time_source_GetState(IMFPresentationTimeSource *iface, DWORD reserved,
|
||||
MFCLOCK_STATE *state)
|
||||
{
|
||||
FIXME("%p, %#x, %p.\n", iface, reserved, state);
|
||||
struct system_time_source *source = impl_from_IMFPresentationTimeSource(iface);
|
||||
|
||||
return E_NOTIMPL;
|
||||
TRACE("%p, %#x, %p.\n", iface, reserved, state);
|
||||
|
||||
EnterCriticalSection(&source->cs);
|
||||
*state = source->state;
|
||||
LeaveCriticalSection(&source->cs);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI system_time_source_GetProperties(IMFPresentationTimeSource *iface, MFCLOCK_PROPERTIES *props)
|
||||
|
@ -3170,32 +3180,107 @@ static ULONG WINAPI system_time_source_sink_Release(IMFClockStateSink *iface)
|
|||
return IMFPresentationTimeSource_Release(&source->IMFPresentationTimeSource_iface);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI system_time_source_sink_OnClockStart(IMFClockStateSink *iface, MFTIME system_time, LONGLONG start_offset)
|
||||
enum clock_command
|
||||
{
|
||||
FIXME("%p, %s, %s.\n", iface, wine_dbgstr_longlong(system_time), wine_dbgstr_longlong(start_offset));
|
||||
CLOCK_CMD_START = 0,
|
||||
CLOCK_CMD_STOP,
|
||||
CLOCK_CMD_PAUSE,
|
||||
CLOCK_CMD_RESTART,
|
||||
CLOCK_CMD_MAX,
|
||||
};
|
||||
|
||||
return E_NOTIMPL;
|
||||
static HRESULT system_time_source_change_state(struct system_time_source *source, enum clock_command command)
|
||||
{
|
||||
static const BYTE state_change_is_allowed[MFCLOCK_STATE_PAUSED+1][CLOCK_CMD_MAX] =
|
||||
{ /* S S* P R */
|
||||
/* INVALID */ { 1, 0, 1, 0 },
|
||||
/* RUNNING */ { 1, 1, 1, 0 },
|
||||
/* STOPPED */ { 1, 1, 0, 0 },
|
||||
/* PAUSED */ { 1, 1, 0, 1 },
|
||||
};
|
||||
static const MFCLOCK_STATE states[CLOCK_CMD_MAX] =
|
||||
{
|
||||
/* CLOCK_CMD_START */ MFCLOCK_STATE_RUNNING,
|
||||
/* CLOCK_CMD_STOP */ MFCLOCK_STATE_STOPPED,
|
||||
/* CLOCK_CMD_PAUSE */ MFCLOCK_STATE_PAUSED,
|
||||
/* CLOCK_CMD_RESTART */ MFCLOCK_STATE_RUNNING,
|
||||
};
|
||||
|
||||
/* Special case that go against usual state change vs return value behavior. */
|
||||
if (source->state == MFCLOCK_STATE_INVALID && command == CLOCK_CMD_STOP)
|
||||
return S_OK;
|
||||
|
||||
if (!state_change_is_allowed[source->state][command])
|
||||
return MF_E_INVALIDREQUEST;
|
||||
|
||||
source->state = states[command];
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI system_time_source_sink_OnClockStart(IMFClockStateSink *iface, MFTIME system_time,
|
||||
LONGLONG start_offset)
|
||||
{
|
||||
struct system_time_source *source = impl_from_IMFClockStateSink(iface);
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("%p, %s, %s.\n", iface, wine_dbgstr_longlong(system_time), wine_dbgstr_longlong(start_offset));
|
||||
|
||||
EnterCriticalSection(&source->cs);
|
||||
hr = system_time_source_change_state(source, CLOCK_CMD_START);
|
||||
LeaveCriticalSection(&source->cs);
|
||||
|
||||
/* FIXME: update timestamps */
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI system_time_source_sink_OnClockStop(IMFClockStateSink *iface, MFTIME system_time)
|
||||
{
|
||||
FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
|
||||
struct system_time_source *source = impl_from_IMFClockStateSink(iface);
|
||||
HRESULT hr;
|
||||
|
||||
return E_NOTIMPL;
|
||||
TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
|
||||
|
||||
EnterCriticalSection(&source->cs);
|
||||
hr = system_time_source_change_state(source, CLOCK_CMD_STOP);
|
||||
LeaveCriticalSection(&source->cs);
|
||||
|
||||
/* FIXME: update timestamps */
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI system_time_source_sink_OnClockPause(IMFClockStateSink *iface, MFTIME system_time)
|
||||
{
|
||||
FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
|
||||
struct system_time_source *source = impl_from_IMFClockStateSink(iface);
|
||||
HRESULT hr;
|
||||
|
||||
return E_NOTIMPL;
|
||||
TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
|
||||
|
||||
EnterCriticalSection(&source->cs);
|
||||
hr = system_time_source_change_state(source, CLOCK_CMD_PAUSE);
|
||||
LeaveCriticalSection(&source->cs);
|
||||
|
||||
/* FIXME: update timestamps */
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI system_time_source_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME system_time)
|
||||
{
|
||||
FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
|
||||
struct system_time_source *source = impl_from_IMFClockStateSink(iface);
|
||||
HRESULT hr;
|
||||
|
||||
return E_NOTIMPL;
|
||||
TRACE("%p, %s.\n", iface, wine_dbgstr_longlong(system_time));
|
||||
|
||||
EnterCriticalSection(&source->cs);
|
||||
hr = system_time_source_change_state(source, CLOCK_CMD_RESTART);
|
||||
LeaveCriticalSection(&source->cs);
|
||||
|
||||
/* FIXME: update timestamps */
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI system_time_source_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME system_time, float rate)
|
||||
|
@ -3226,13 +3311,14 @@ HRESULT WINAPI MFCreateSystemTimeSource(IMFPresentationTimeSource **time_source)
|
|||
|
||||
TRACE("%p.\n", time_source);
|
||||
|
||||
object = heap_alloc(sizeof(*object));
|
||||
object = heap_alloc_zero(sizeof(*object));
|
||||
if (!object)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
object->IMFPresentationTimeSource_iface.lpVtbl = &systemtimesourcevtbl;
|
||||
object->IMFClockStateSink_iface.lpVtbl = &systemtimesourcesinkvtbl;
|
||||
object->refcount = 1;
|
||||
InitializeCriticalSection(&object->cs);
|
||||
|
||||
*time_source = &object->IMFPresentationTimeSource_iface;
|
||||
|
||||
|
|
|
@ -1598,11 +1598,46 @@ static void test_presentation_descriptor(void)
|
|||
IMFMediaType_Release(media_type);
|
||||
}
|
||||
|
||||
enum clock_action
|
||||
{
|
||||
CLOCK_START,
|
||||
CLOCK_STOP,
|
||||
CLOCK_PAUSE,
|
||||
CLOCK_RESTART,
|
||||
};
|
||||
|
||||
static void test_system_time_source(void)
|
||||
{
|
||||
static const struct clock_state_test
|
||||
{
|
||||
enum clock_action action;
|
||||
MFCLOCK_STATE state;
|
||||
BOOL is_invalid;
|
||||
}
|
||||
clock_state_change[] =
|
||||
{
|
||||
{ CLOCK_STOP, MFCLOCK_STATE_INVALID },
|
||||
{ CLOCK_RESTART, MFCLOCK_STATE_INVALID, TRUE },
|
||||
{ CLOCK_PAUSE, MFCLOCK_STATE_PAUSED },
|
||||
{ CLOCK_PAUSE, MFCLOCK_STATE_PAUSED, TRUE },
|
||||
{ CLOCK_STOP, MFCLOCK_STATE_STOPPED },
|
||||
{ CLOCK_STOP, MFCLOCK_STATE_STOPPED },
|
||||
{ CLOCK_RESTART, MFCLOCK_STATE_STOPPED, TRUE },
|
||||
{ CLOCK_START, MFCLOCK_STATE_RUNNING },
|
||||
{ CLOCK_START, MFCLOCK_STATE_RUNNING },
|
||||
{ CLOCK_RESTART, MFCLOCK_STATE_RUNNING, TRUE },
|
||||
{ CLOCK_PAUSE, MFCLOCK_STATE_PAUSED },
|
||||
{ CLOCK_START, MFCLOCK_STATE_RUNNING },
|
||||
{ CLOCK_PAUSE, MFCLOCK_STATE_PAUSED },
|
||||
{ CLOCK_RESTART, MFCLOCK_STATE_RUNNING },
|
||||
{ CLOCK_RESTART, MFCLOCK_STATE_RUNNING, TRUE },
|
||||
{ CLOCK_STOP, MFCLOCK_STATE_STOPPED },
|
||||
{ CLOCK_PAUSE, MFCLOCK_STATE_STOPPED, TRUE },
|
||||
};
|
||||
IMFPresentationTimeSource *time_source;
|
||||
IMFClockStateSink *statesink;
|
||||
MFCLOCK_STATE state;
|
||||
unsigned int i;
|
||||
DWORD value;
|
||||
HRESULT hr;
|
||||
|
||||
|
@ -1620,12 +1655,38 @@ static void test_system_time_source(void)
|
|||
ok(value == 0, "Unexpected value %u.\n", value);
|
||||
|
||||
hr = IMFPresentationTimeSource_GetState(time_source, 0, &state);
|
||||
todo_wine {
|
||||
ok(hr == S_OK, "Failed to get state, hr %#x.\n", hr);
|
||||
ok(state == MFCLOCK_STATE_INVALID, "Unexpected state %d.\n", state);
|
||||
}
|
||||
|
||||
hr = IMFPresentationTimeSource_QueryInterface(time_source, &IID_IMFClockStateSink, (void **)&statesink);
|
||||
ok(hr == S_OK, "Failed to get state sink, hr %#x.\n", hr);
|
||||
|
||||
/* State changes. */
|
||||
for (i = 0; i < ARRAY_SIZE(clock_state_change); ++i)
|
||||
{
|
||||
switch (clock_state_change[i].action)
|
||||
{
|
||||
case CLOCK_STOP:
|
||||
hr = IMFClockStateSink_OnClockStop(statesink, 0);
|
||||
break;
|
||||
case CLOCK_RESTART:
|
||||
hr = IMFClockStateSink_OnClockRestart(statesink, 0);
|
||||
break;
|
||||
case CLOCK_PAUSE:
|
||||
hr = IMFClockStateSink_OnClockPause(statesink, 0);
|
||||
break;
|
||||
case CLOCK_START:
|
||||
hr = IMFClockStateSink_OnClockStart(statesink, 0, 0);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
ok(hr == (clock_state_change[i].is_invalid ? MF_E_INVALIDREQUEST : S_OK), "%u: unexpected hr %#x.\n", i, hr);
|
||||
hr = IMFPresentationTimeSource_GetState(time_source, 0, &state);
|
||||
ok(hr == S_OK, "%u: failed to get state, hr %#x.\n", i, hr);
|
||||
ok(state == clock_state_change[i].state, "%u: unexpected state %d.\n", i, state);
|
||||
}
|
||||
|
||||
IMFClockStateSink_Release(statesink);
|
||||
|
||||
IMFPresentationTimeSource_Release(time_source);
|
||||
|
|
Loading…
Reference in New Issue