Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
11483222
Commit
11483222
authored
Jul 14, 2020
by
Zebediah Figura
Committed by
Alexandre Julliard
Jul 15, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
quartz: Run the graph asynchronously if necessary.
Signed-off-by:
Zebediah Figura
<
z.figura12@gmail.com
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
9dd5aa17
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
208 additions
and
52 deletions
+208
-52
filtergraph.c
dlls/quartz/filtergraph.c
+196
-40
filtergraph.c
dlls/quartz/tests/filtergraph.c
+6
-6
videorenderer.c
dlls/quartz/tests/videorenderer.c
+3
-3
vmr9.c
dlls/quartz/tests/vmr9.c
+3
-3
No files found.
dlls/quartz/filtergraph.c
View file @
11483222
...
...
@@ -191,6 +191,9 @@ struct filter_graph
struct
list
filters
;
unsigned
int
name_index
;
OAFilterState
state
;
TP_WORK
*
async_run_work
;
IReferenceClock
*
refClock
;
IBaseFilter
*
refClockProvider
;
EventsQueue
evqueue
;
...
...
@@ -202,7 +205,6 @@ struct filter_graph
int
HandleEcComplete
;
int
HandleEcRepaint
;
int
HandleEcClockChanged
;
OAFilterState
state
;
CRITICAL_SECTION
cs
;
ITF_CACHE_ENTRY
ItfCacheEntries
[
MAX_ITF_CACHE_ENTRIES
];
int
nItfCacheEntries
;
...
...
@@ -219,6 +221,8 @@ struct filter_graph
REFERENCE_TIME
stream_start
,
stream_elapsed
;
LONGLONG
current_pos
;
unsigned
int
needs_async_run
:
1
;
};
struct
enum_filters
...
...
@@ -1719,13 +1723,179 @@ static HRESULT WINAPI MediaControl_Invoke(IMediaControl *iface, DISPID dispIdMem
return
S_OK
;
}
static
void
update_render_count
(
struct
filter_graph
*
graph
)
{
/* Some filters (e.g. MediaStreamFilter) can become renderers when they are
* already in the graph. */
struct
filter
*
filter
;
graph
->
nRenderers
=
0
;
LIST_FOR_EACH_ENTRY
(
filter
,
&
graph
->
filters
,
struct
filter
,
entry
)
{
if
(
is_renderer
(
filter
))
++
graph
->
nRenderers
;
}
}
/* Perform the paused -> running transition. The caller must hold graph->cs. */
static
HRESULT
graph_start
(
struct
filter_graph
*
graph
,
REFERENCE_TIME
stream_start
)
{
struct
filter
*
filter
;
HRESULT
hr
=
S_OK
;
graph
->
EcCompleteCount
=
0
;
update_render_count
(
graph
);
if
(
graph
->
defaultclock
&&
!
graph
->
refClock
)
IFilterGraph2_SetDefaultSyncSource
(
&
graph
->
IFilterGraph2_iface
);
if
(
!
stream_start
&&
graph
->
refClock
)
{
IReferenceClock_GetTime
(
graph
->
refClock
,
&
graph
->
stream_start
);
stream_start
=
graph
->
stream_start
-
graph
->
stream_elapsed
;
/* Delay presentation time by 200 ms, to give filters time to
* initialize. */
stream_start
+=
200
*
10000
;
}
LIST_FOR_EACH_ENTRY
(
filter
,
&
graph
->
filters
,
struct
filter
,
entry
)
{
HRESULT
filter_hr
=
IBaseFilter_Run
(
filter
->
filter
,
stream_start
);
if
(
hr
==
S_OK
)
hr
=
filter_hr
;
TRACE
(
"Filter %p returned %#x.
\n
"
,
filter
->
filter
,
filter_hr
);
}
if
(
FAILED
(
hr
))
WARN
(
"Failed to start stream, hr %#x.
\n
"
,
hr
);
return
hr
;
}
static
void
CALLBACK
async_run_cb
(
TP_CALLBACK_INSTANCE
*
instance
,
void
*
context
,
TP_WORK
*
work
)
{
struct
filter_graph
*
graph
=
context
;
struct
filter
*
filter
;
FILTER_STATE
state
;
HRESULT
hr
;
TRACE
(
"Performing asynchronous state change.
\n
"
);
/* We can't just call GetState(), since that will return State_Running and
* VFW_S_STATE_INTERMEDIATE regardless of whether we're done pausing yet.
* Instead replicate it here. */
for
(;;)
{
IBaseFilter
*
async_filter
=
NULL
;
hr
=
S_OK
;
EnterCriticalSection
(
&
graph
->
cs
);
if
(
!
graph
->
needs_async_run
)
break
;
LIST_FOR_EACH_ENTRY
(
filter
,
&
graph
->
filters
,
struct
filter
,
entry
)
{
hr
=
IBaseFilter_GetState
(
filter
->
filter
,
0
,
&
state
);
if
(
hr
==
VFW_S_STATE_INTERMEDIATE
)
async_filter
=
filter
->
filter
;
if
(
SUCCEEDED
(
hr
)
&&
state
!=
State_Paused
)
ERR
(
"Filter %p reported incorrect state %u.
\n
"
,
filter
->
filter
,
state
);
if
(
hr
!=
S_OK
)
break
;
}
if
(
hr
!=
VFW_S_STATE_INTERMEDIATE
)
break
;
LeaveCriticalSection
(
&
graph
->
cs
);
IBaseFilter_GetState
(
async_filter
,
10
,
&
state
);
}
if
(
hr
==
S_OK
&&
graph
->
needs_async_run
)
{
sort_filters
(
graph
);
graph_start
(
graph
,
0
);
graph
->
needs_async_run
=
0
;
}
LeaveCriticalSection
(
&
graph
->
cs
);
IUnknown_Release
(
graph
->
outer_unk
);
}
static
HRESULT
WINAPI
MediaControl_Run
(
IMediaControl
*
iface
)
{
struct
filter_graph
*
graph
=
impl_from_IMediaControl
(
iface
);
BOOL
need_async_run
=
TRUE
;
struct
filter
*
filter
;
FILTER_STATE
state
;
HRESULT
hr
=
S_OK
;
TRACE
(
"graph %p.
\n
"
,
graph
);
return
IMediaFilter_Run
(
&
graph
->
IMediaFilter_iface
,
0
);
EnterCriticalSection
(
&
graph
->
cs
);
if
(
graph
->
state
==
State_Running
)
{
LeaveCriticalSection
(
&
graph
->
cs
);
return
S_OK
;
}
sort_filters
(
graph
);
update_render_count
(
graph
);
if
(
graph
->
state
==
State_Stopped
)
{
if
(
graph
->
defaultclock
&&
!
graph
->
refClock
)
IFilterGraph2_SetDefaultSyncSource
(
&
graph
->
IFilterGraph2_iface
);
LIST_FOR_EACH_ENTRY
(
filter
,
&
graph
->
filters
,
struct
filter
,
entry
)
{
HRESULT
filter_hr
=
IBaseFilter_Pause
(
filter
->
filter
);
if
(
hr
==
S_OK
)
hr
=
filter_hr
;
TRACE
(
"Filter %p returned %#x.
\n
"
,
filter
->
filter
,
filter_hr
);
/* If a filter returns VFW_S_CANT_CUE, we shouldn't wait for a
* paused state. */
filter_hr
=
IBaseFilter_GetState
(
filter
->
filter
,
0
,
&
state
);
if
(
filter_hr
!=
S_OK
&&
filter_hr
!=
VFW_S_STATE_INTERMEDIATE
)
need_async_run
=
FALSE
;
}
if
(
FAILED
(
hr
))
{
LeaveCriticalSection
(
&
graph
->
cs
);
WARN
(
"Failed to pause, hr %#x.
\n
"
,
hr
);
return
hr
;
}
}
graph
->
state
=
State_Running
;
if
(
SUCCEEDED
(
hr
))
{
if
(
hr
!=
S_OK
&&
need_async_run
)
{
if
(
!
graph
->
async_run_work
)
graph
->
async_run_work
=
CreateThreadpoolWork
(
async_run_cb
,
graph
,
NULL
);
graph
->
needs_async_run
=
1
;
IUnknown_AddRef
(
graph
->
outer_unk
);
SubmitThreadpoolWork
(
graph
->
async_run_work
);
}
else
{
graph_start
(
graph
,
0
);
}
}
LeaveCriticalSection
(
&
graph
->
cs
);
return
hr
;
}
static
HRESULT
WINAPI
MediaControl_Pause
(
IMediaControl
*
iface
)
...
...
@@ -4778,6 +4948,7 @@ static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
struct
filter_graph
*
graph
=
impl_from_IMediaFilter
(
iface
);
HRESULT
hr
=
S_OK
,
filter_hr
;
struct
filter
*
filter
;
TP_WORK
*
work
;
TRACE
(
"graph %p.
\n
"
,
graph
);
...
...
@@ -4809,26 +4980,20 @@ static HRESULT WINAPI MediaFilter_Stop(IMediaFilter *iface)
}
graph
->
state
=
State_Stopped
;
graph
->
needs_async_run
=
0
;
work
=
graph
->
async_run_work
;
/* Update the current position, probably to synchronize multiple streams. */
IMediaSeeking_SetPositions
(
&
graph
->
IMediaSeeking_iface
,
&
graph
->
current_pos
,
AM_SEEKING_AbsolutePositioning
,
NULL
,
AM_SEEKING_NoPositioning
);
LeaveCriticalSection
(
&
graph
->
cs
);
return
hr
;
}
static
void
update_render_count
(
struct
filter_graph
*
graph
)
{
/* Some filters (e.g. MediaStreamFilter) can become renderers when they are
* already in the graph. */
struct
filter
*
filter
;
graph
->
nRenderers
=
0
;
LIST_FOR_EACH_ENTRY
(
filter
,
&
graph
->
filters
,
struct
filter
,
entry
)
{
if
(
is_renderer
(
filter
))
++
graph
->
nRenderers
;
}
/* Don't cancel the callback; it's holding a reference to the graph. */
if
(
work
)
WaitForThreadpoolWorkCallbacks
(
work
,
FALSE
);
return
hr
;
}
static
HRESULT
WINAPI
MediaFilter_Pause
(
IMediaFilter
*
iface
)
...
...
@@ -4836,6 +5001,7 @@ static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
struct
filter_graph
*
graph
=
impl_from_IMediaFilter
(
iface
);
HRESULT
hr
=
S_OK
,
filter_hr
;
struct
filter
*
filter
;
TP_WORK
*
work
;
TRACE
(
"graph %p.
\n
"
,
graph
);
...
...
@@ -4869,17 +5035,22 @@ static HRESULT WINAPI MediaFilter_Pause(IMediaFilter *iface)
}
graph
->
state
=
State_Paused
;
graph
->
needs_async_run
=
0
;
work
=
graph
->
async_run_work
;
LeaveCriticalSection
(
&
graph
->
cs
);
/* Don't cancel the callback; it's holding a reference to the graph. */
if
(
work
)
WaitForThreadpoolWorkCallbacks
(
work
,
FALSE
);
return
hr
;
}
static
HRESULT
WINAPI
MediaFilter_Run
(
IMediaFilter
*
iface
,
REFERENCE_TIME
start
)
{
struct
filter_graph
*
graph
=
impl_from_IMediaFilter
(
iface
);
REFERENCE_TIME
stream_start
=
start
;
HRESULT
hr
=
S_OK
,
filter_hr
;
struct
filter
*
filter
;
HRESULT
hr
;
TRACE
(
"graph %p, start %s.
\n
"
,
graph
,
debugstr_time
(
start
));
...
...
@@ -4890,31 +5061,13 @@ static HRESULT WINAPI MediaFilter_Run(IMediaFilter *iface, REFERENCE_TIME start)
LeaveCriticalSection
(
&
graph
->
cs
);
return
S_OK
;
}
graph
->
EcCompleteCount
=
0
;
sort_filters
(
graph
);
update_render_count
(
graph
);
if
(
graph
->
defaultclock
&&
!
graph
->
refClock
)
IFilterGraph2_SetDefaultSyncSource
(
&
graph
->
IFilterGraph2_iface
);
if
(
!
start
&&
graph
->
refClock
)
{
IReferenceClock_GetTime
(
graph
->
refClock
,
&
graph
->
stream_start
);
stream_start
=
graph
->
stream_start
-
graph
->
stream_elapsed
;
/* Delay presentation time by 200 ms, to give filters time to
* initialize. */
stream_start
+=
200
*
10000
;
}
LIST_FOR_EACH_ENTRY
(
filter
,
&
graph
->
filters
,
struct
filter
,
entry
)
{
filter_hr
=
IBaseFilter_Run
(
filter
->
filter
,
stream_start
);
if
(
hr
==
S_OK
)
hr
=
filter_hr
;
}
hr
=
graph_start
(
graph
,
start
);
graph
->
state
=
State_Running
;
graph
->
needs_async_run
=
0
;
LeaveCriticalSection
(
&
graph
->
cs
);
return
hr
;
...
...
@@ -4924,6 +5077,7 @@ static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD timeout, F
{
struct
filter_graph
*
graph
=
impl_from_IMediaFilter
(
iface
);
DWORD
end
=
GetTickCount
()
+
timeout
;
FILTER_STATE
expect_state
;
HRESULT
hr
;
TRACE
(
"graph %p, timeout %u, state %p.
\n
"
,
graph
,
timeout
,
state
);
...
...
@@ -4939,6 +5093,7 @@ static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD timeout, F
EnterCriticalSection
(
&
graph
->
cs
);
*
state
=
graph
->
state
;
expect_state
=
graph
->
needs_async_run
?
State_Paused
:
graph
->
state
;
for
(;;)
{
...
...
@@ -4970,8 +5125,9 @@ static HRESULT WINAPI MediaFilter_GetState(IMediaFilter *iface, DWORD timeout, F
else
if
(
filter_state
!=
graph
->
state
&&
filter_state
!=
State_Paused
)
hr
=
E_FAIL
;
if
(
filter_state
!=
graph
->
state
)
ERR
(
"Filter %p reported incorrect state %u.
\n
"
,
filter
->
filter
,
filter_state
);
if
(
filter_state
!=
expect_state
)
ERR
(
"Filter %p reported incorrect state %u (expected %u).
\n
"
,
filter
->
filter
,
filter_state
,
expect_state
);
}
LeaveCriticalSection
(
&
graph
->
cs
);
...
...
dlls/quartz/tests/filtergraph.c
View file @
11483222
...
...
@@ -3497,8 +3497,8 @@ todo_wine
hr
=
IMediaControl_GetState
(
control
,
0
,
&
state
);
ok
(
hr
==
VFW_S_STATE_INTERMEDIATE
,
"Got hr %#x.
\n
"
,
hr
);
ok
(
state
==
State_Running
,
"Got state %u.
\n
"
,
state
);
todo_wine
ok
(
sink
.
state
==
State_Paused
,
"Got state %u.
\n
"
,
sink
.
state
);
todo_wine
ok
(
source
.
state
==
State_Paused
,
"Got state %u.
\n
"
,
source
.
state
);
ok
(
sink
.
state
==
State_Paused
,
"Got state %u.
\n
"
,
sink
.
state
);
ok
(
source
.
state
==
State_Paused
,
"Got state %u.
\n
"
,
source
.
state
);
hr
=
IMediaControl_Run
(
control
);
todo_wine
ok
(
hr
==
S_FALSE
,
"Got hr %#x.
\n
"
,
hr
);
...
...
@@ -3506,16 +3506,16 @@ todo_wine
hr
=
IMediaControl_GetState
(
control
,
0
,
&
state
);
ok
(
hr
==
VFW_S_STATE_INTERMEDIATE
,
"Got hr %#x.
\n
"
,
hr
);
ok
(
state
==
State_Running
,
"Got state %u.
\n
"
,
state
);
todo_wine
ok
(
sink
.
state
==
State_Paused
,
"Got state %u.
\n
"
,
sink
.
state
);
todo_wine
ok
(
source
.
state
==
State_Paused
,
"Got state %u.
\n
"
,
source
.
state
);
ok
(
sink
.
state
==
State_Paused
,
"Got state %u.
\n
"
,
sink
.
state
);
ok
(
source
.
state
==
State_Paused
,
"Got state %u.
\n
"
,
source
.
state
);
sink
.
state_hr
=
sink
.
GetState_hr
=
S_OK
;
while
((
hr
=
IMediaControl_GetState
(
control
,
INFINITE
,
&
state
))
==
VFW_S_STATE_INTERMEDIATE
)
{
ok
(
state
==
State_Running
,
"Got state %u.
\n
"
,
state
);
todo_wine
ok
(
sink
.
state
==
State_Paused
,
"Got state %u.
\n
"
,
sink
.
state
);
todo_wine
ok
(
source
.
state
==
State_Paused
,
"Got state %u.
\n
"
,
source
.
state
);
ok
(
sink
.
state
==
State_Paused
,
"Got state %u.
\n
"
,
sink
.
state
);
ok
(
source
.
state
==
State_Paused
,
"Got state %u.
\n
"
,
source
.
state
);
Sleep
(
10
);
}
ok
(
hr
==
S_OK
,
"Got hr %#x.
\n
"
,
hr
);
...
...
dlls/quartz/tests/videorenderer.c
View file @
11483222
...
...
@@ -1172,7 +1172,7 @@ static void test_eos(IPin *pin, IMemInputPin *input, IFilterGraph2 *graph)
* done rendering. */
hr
=
IMediaControl_Run
(
control
);
todo_wine
ok
(
hr
==
S_FALSE
,
"Got hr %#x.
\n
"
,
hr
);
ok
(
hr
==
S_FALSE
,
"Got hr %#x.
\n
"
,
hr
);
hr
=
join_thread
(
send_frame
(
input
));
ok
(
hr
==
S_OK
,
"Got hr %#x.
\n
"
,
hr
);
hr
=
IMediaControl_GetState
(
control
,
1000
,
&
state
);
...
...
@@ -1195,7 +1195,7 @@ static void test_eos(IPin *pin, IMemInputPin *input, IFilterGraph2 *graph)
/* Test sending EOS while flushing. */
hr
=
IMediaControl_Run
(
control
);
todo_wine
ok
(
hr
==
S_FALSE
,
"Got hr %#x.
\n
"
,
hr
);
ok
(
hr
==
S_FALSE
,
"Got hr %#x.
\n
"
,
hr
);
hr
=
join_thread
(
send_frame
(
input
));
ok
(
hr
==
S_OK
,
"Got hr %#x.
\n
"
,
hr
);
...
...
@@ -1214,7 +1214,7 @@ static void test_eos(IPin *pin, IMemInputPin *input, IFilterGraph2 *graph)
/* Test sending EOS and then flushing or stopping. */
hr
=
IMediaControl_Run
(
control
);
todo_wine
ok
(
hr
==
S_FALSE
,
"Got hr %#x.
\n
"
,
hr
);
ok
(
hr
==
S_FALSE
,
"Got hr %#x.
\n
"
,
hr
);
hr
=
join_thread
(
send_frame
(
input
));
ok
(
hr
==
S_OK
,
"Got hr %#x.
\n
"
,
hr
);
hr
=
IMediaControl_GetState
(
control
,
1000
,
&
state
);
...
...
dlls/quartz/tests/vmr9.c
View file @
11483222
...
...
@@ -1308,7 +1308,7 @@ static void test_eos(IPin *pin, IMemInputPin *input, IMediaControl *control)
commit_allocator
(
input
);
hr
=
IMediaControl_Run
(
control
);
todo_wine
ok
(
hr
==
S_FALSE
,
"Got hr %#x.
\n
"
,
hr
);
ok
(
hr
==
S_FALSE
,
"Got hr %#x.
\n
"
,
hr
);
hr
=
join_thread
(
send_frame
(
input
));
ok
(
hr
==
S_OK
,
"Got hr %#x.
\n
"
,
hr
);
hr
=
IMediaControl_GetState
(
control
,
1000
,
&
state
);
...
...
@@ -1332,7 +1332,7 @@ static void test_eos(IPin *pin, IMemInputPin *input, IMediaControl *control)
commit_allocator
(
input
);
hr
=
IMediaControl_Run
(
control
);
todo_wine
ok
(
hr
==
S_FALSE
,
"Got hr %#x.
\n
"
,
hr
);
ok
(
hr
==
S_FALSE
,
"Got hr %#x.
\n
"
,
hr
);
hr
=
join_thread
(
send_frame
(
input
));
ok
(
hr
==
S_OK
,
"Got hr %#x.
\n
"
,
hr
);
...
...
@@ -1352,7 +1352,7 @@ static void test_eos(IPin *pin, IMemInputPin *input, IMediaControl *control)
commit_allocator
(
input
);
hr
=
IMediaControl_Run
(
control
);
todo_wine
ok
(
hr
==
S_FALSE
,
"Got hr %#x.
\n
"
,
hr
);
ok
(
hr
==
S_FALSE
,
"Got hr %#x.
\n
"
,
hr
);
hr
=
join_thread
(
send_frame
(
input
));
ok
(
hr
==
S_OK
,
"Got hr %#x.
\n
"
,
hr
);
hr
=
IMediaControl_GetState
(
control
,
1000
,
&
state
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment