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
95897b68
Commit
95897b68
authored
Nov 09, 2010
by
Maarten Lankhorst
Committed by
Alexandre Julliard
Nov 10, 2010
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
strmbase: Add support for rendering algorithms to quality control.
parent
46f4011e
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
250 additions
and
1 deletion
+250
-1
qualitycontrol.c
dlls/strmbase/qualitycontrol.c
+235
-1
strmbase.h
include/wine/strmbase.h
+15
-0
No files found.
dlls/strmbase/qualitycontrol.c
View file @
95897b68
...
...
@@ -3,6 +3,11 @@
*
* Copyright 2010 Maarten Lankhorst for Codeweavers
*
* rendering qos functions based on, the original can be found at
* gstreamer/libs/gst/base/gstbasesink.c which has copyright notice:
*
* Copyright (C) 2005-2007 Wim Taymans <wim.taymans@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
...
...
@@ -28,12 +33,13 @@
#include <assert.h>
WINE_DEFAULT_DEBUG_CHANNEL
(
strmbase
);
WINE_DEFAULT_DEBUG_CHANNEL
(
strmbase
_qc
);
void
QualityControlImpl_init
(
QualityControlImpl
*
This
,
IPin
*
input
,
IBaseFilter
*
self
)
{
This
->
input
=
input
;
This
->
self
=
self
;
This
->
tonotify
=
NULL
;
This
->
clock
=
NULL
;
}
HRESULT
WINAPI
QualityControlImpl_QueryInterface
(
IQualityControl
*
iface
,
REFIID
riid
,
void
**
ppv
)
{
...
...
@@ -77,3 +83,231 @@ HRESULT WINAPI QualityControlImpl_SetSink(IQualityControl *iface, IQualityContro
This
->
tonotify
=
tonotify
;
return
S_OK
;
}
/* Macros copied from gstreamer, weighted average between old average and new ones */
#define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size))
/* generic running average, this has a neutral window size */
#define UPDATE_RUNNING_AVG(avg,val) DO_RUNNING_AVG(avg,val,8)
/* the windows for these running averages are experimentally obtained.
* possitive values get averaged more while negative values use a small
* window so we can react faster to badness. */
#define UPDATE_RUNNING_AVG_P(avg,val) DO_RUNNING_AVG(avg,val,16)
#define UPDATE_RUNNING_AVG_N(avg,val) DO_RUNNING_AVG(avg,val,4)
void
QualityControlRender_Start
(
QualityControlImpl
*
This
,
REFERENCE_TIME
tStart
)
{
This
->
avg_render
=
This
->
last_in_time
=
This
->
last_left
=
This
->
avg_duration
=
This
->
avg_pt
=
-
1
;
This
->
clockstart
=
tStart
;
This
->
avg_rate
=
-
1
.
0
;
This
->
rendered
=
This
->
dropped
=
This
->
is_dropped
=
0
;
This
->
qos_handled
=
1
;
/* Lie that will be corrected on first adjustment */
}
void
QualityControlRender_SetClock
(
QualityControlImpl
*
This
,
IReferenceClock
*
clock
)
{
This
->
clock
=
clock
;
}
static
BOOL
QualityControlRender_IsLate
(
QualityControlImpl
*
This
,
REFERENCE_TIME
jitter
,
REFERENCE_TIME
start
,
REFERENCE_TIME
stop
)
{
REFERENCE_TIME
max_lateness
=
200000
;
/* we can add a valid stop time */
if
(
stop
>=
start
)
max_lateness
+=
stop
;
else
max_lateness
+=
start
;
/* if the jitter bigger than duration and lateness we are too late */
if
(
start
+
jitter
>
max_lateness
)
{
WARN
(
"buffer is too late %i > %i
\n
"
,
(
int
)((
start
+
jitter
)
/
10000
),
(
int
)(
max_lateness
/
10000
));
/* !!emergency!!, if we did not receive anything valid for more than a
* second, render it anyway so the user sees something */
if
(
This
->
last_in_time
<
0
||
start
-
This
->
last_in_time
<
10000000
)
return
TRUE
;
FIXME
(
"A lot of buffers are being dropped.
\n
"
);
FIXME
(
"There may be a timestamping problem, or this computer is too slow.
\n
"
);
}
This
->
last_in_time
=
start
;
return
FALSE
;
}
HRESULT
QualityControlRender_WaitFor
(
QualityControlImpl
*
This
,
IMediaSample
*
sample
,
HANDLE
ev
)
{
REFERENCE_TIME
start
=
-
1
,
stop
=
-
1
,
jitter
=
0
;
This
->
current_rstart
=
This
->
current_rstop
=
-
1
;
This
->
current_jitter
=
0
;
if
(
!
This
->
clock
||
FAILED
(
IMediaSample_GetTime
(
sample
,
&
start
,
&
stop
)))
return
S_OK
;
if
(
start
>=
0
)
{
REFERENCE_TIME
now
;
IReferenceClock_GetTime
(
This
->
clock
,
&
now
);
now
-=
This
->
clockstart
;
jitter
=
now
-
start
;
#if 0
/* AdviseTime is bugged, so don't use it at all */
if (jitter < -200000) {
DWORD_PTR cookie;
IReferenceClock_AdviseTime(This->clock, clockstart, start, ev, &cookie);
WaitForSingleObject(ev, INFINITE);
IReferenceClock_Unadvise(This->clock, cookie);
} else
#endif
if
(
jitter
<
0
)
{
TRACE
(
"Sleeping for %i ms
\n
"
,
(
int
)
-
jitter
/
10000
);
WaitForSingleObject
(
ev
,
-
jitter
/
10000
);
}
}
else
start
=
stop
=
-
1
;
This
->
current_rstart
=
start
;
This
->
current_rstop
=
stop
>
start
?
stop
:
start
;
This
->
current_jitter
=
jitter
;
This
->
is_dropped
=
QualityControlRender_IsLate
(
This
,
jitter
,
start
,
stop
);
TRACE
(
"Dropped: %i %i %i %i
\n
"
,
This
->
is_dropped
,
(
int
)(
start
/
10000
),
(
int
)(
stop
/
10000
),
(
int
)(
jitter
/
10000
));
if
(
This
->
is_dropped
)
{
This
->
dropped
++
;
if
(
!
This
->
qos_handled
)
return
S_FALSE
;
}
else
This
->
rendered
++
;
return
S_OK
;
}
void
QualityControlRender_DoQOS
(
QualityControlImpl
*
priv
)
{
REFERENCE_TIME
start
,
stop
,
jitter
,
pt
,
entered
,
left
,
duration
;
double
rate
;
if
(
!
priv
->
clock
)
return
;
start
=
priv
->
current_rstart
;
stop
=
priv
->
current_rstop
;
jitter
=
priv
->
current_jitter
;
if
(
jitter
<
0
)
{
/* this is the time the buffer entered the sink */
if
(
start
<
-
jitter
)
entered
=
0
;
else
entered
=
start
+
jitter
;
left
=
start
;
}
else
{
/* this is the time the buffer entered the sink */
entered
=
start
+
jitter
;
/* this is the time the buffer left the sink */
left
=
start
+
jitter
;
}
/* calculate duration of the buffer */
if
(
stop
>=
start
)
duration
=
stop
-
start
;
else
duration
=
0
;
/* if we have the time when the last buffer left us, calculate
* processing time */
if
(
priv
->
last_left
>=
0
)
{
if
(
entered
>
priv
->
last_left
)
{
pt
=
entered
-
priv
->
last_left
;
}
else
{
pt
=
0
;
}
}
else
{
pt
=
priv
->
avg_pt
;
}
#define XTIME(u) (int)(u/10000000), (int)((u / 10000)%1000)
TRACE
(
"start: %u.%03u, entered %u.%03u, left %u.%03u, pt: %u.%03u, "
"duration %u.%03u, jitter %u.%03u
\n
"
,
XTIME
(
start
),
XTIME
(
entered
),
XTIME
(
left
),
XTIME
(
pt
),
XTIME
(
duration
),
XTIME
(
jitter
));
TRACE
(
"avg_duration: %u.%03u, avg_pt: %u.%03u, avg_rate: %g
\n
"
,
XTIME
(
priv
->
avg_duration
),
XTIME
(
priv
->
avg_pt
),
priv
->
avg_rate
);
#undef XTIME
/* collect running averages. for first observations, we copy the
* values */
if
(
priv
->
avg_duration
<
0
)
priv
->
avg_duration
=
duration
;
else
priv
->
avg_duration
=
UPDATE_RUNNING_AVG
(
priv
->
avg_duration
,
duration
);
if
(
priv
->
avg_pt
<
0
)
priv
->
avg_pt
=
pt
;
else
priv
->
avg_pt
=
UPDATE_RUNNING_AVG
(
priv
->
avg_pt
,
pt
);
if
(
priv
->
avg_duration
!=
0
)
rate
=
(
double
)
priv
->
avg_pt
/
(
double
)
priv
->
avg_duration
;
else
rate
=
0
.
0
;
if
(
priv
->
last_left
>=
0
)
{
if
(
priv
->
is_dropped
||
priv
->
avg_rate
<
0
.
0
)
{
priv
->
avg_rate
=
rate
;
}
else
{
if
(
rate
>
1
.
0
)
priv
->
avg_rate
=
UPDATE_RUNNING_AVG_N
(
priv
->
avg_rate
,
rate
);
else
priv
->
avg_rate
=
UPDATE_RUNNING_AVG_P
(
priv
->
avg_rate
,
rate
);
}
}
if
(
priv
->
avg_rate
>=
0
.
0
)
{
HRESULT
hr
;
Quality
q
;
/* if we have a valid rate, start sending QoS messages */
if
(
priv
->
current_jitter
<
0
)
{
/* make sure we never go below 0 when adding the jitter to the
* timestamp. */
if
(
priv
->
current_rstart
<
-
priv
->
current_jitter
)
priv
->
current_jitter
=
-
priv
->
current_rstart
;
}
else
priv
->
current_jitter
+=
(
priv
->
current_rstop
-
priv
->
current_rstart
);
q
.
Type
=
(
jitter
>
0
?
Famine
:
Flood
);
q
.
Proportion
=
(
LONG
)(
1000
.
/
priv
->
avg_rate
);
if
(
q
.
Proportion
<
500
)
q
.
Proportion
=
500
;
else
if
(
q
.
Proportion
>
2000
)
q
.
Proportion
=
2000
;
q
.
Late
=
priv
->
current_jitter
;
q
.
TimeStamp
=
priv
->
current_rstart
;
TRACE
(
"Late: %i from %i, rate: %g
\n
"
,
(
int
)(
q
.
Late
/
10000
),
(
int
)(
q
.
TimeStamp
/
10000
),
1
.
/
priv
->
avg_rate
);
hr
=
IQualityControl_Notify
((
IQualityControl
*
)
priv
,
priv
->
self
,
q
);
priv
->
qos_handled
=
hr
==
S_OK
;
}
/* record when this buffer will leave us */
priv
->
last_left
=
left
;
}
void
QualityControlRender_BeginRender
(
QualityControlImpl
*
This
)
{
This
->
start
=
-
1
;
if
(
!
This
->
clock
)
return
;
IReferenceClock_GetTime
(
This
->
clock
,
&
This
->
start
);
}
void
QualityControlRender_EndRender
(
QualityControlImpl
*
This
)
{
REFERENCE_TIME
elapsed
;
if
(
!
This
->
clock
||
This
->
start
<
0
||
FAILED
(
IReferenceClock_GetTime
(
This
->
clock
,
&
This
->
stop
)))
return
;
elapsed
=
This
->
start
-
This
->
stop
;
if
(
elapsed
<
0
)
return
;
if
(
This
->
avg_render
<
0
)
This
->
avg_render
=
elapsed
;
else
This
->
avg_render
=
UPDATE_RUNNING_AVG
(
This
->
avg_render
,
elapsed
);
}
include/wine/strmbase.h
View file @
95897b68
...
...
@@ -200,6 +200,14 @@ typedef struct QualityControlImpl {
IPin
*
input
;
IBaseFilter
*
self
;
IQualityControl
*
tonotify
;
/* Render stuff */
IReferenceClock
*
clock
;
REFERENCE_TIME
last_in_time
,
last_left
,
avg_duration
,
avg_pt
,
avg_render
,
start
,
stop
;
REFERENCE_TIME
current_jitter
,
current_rstart
,
current_rstop
,
clockstart
;
double
avg_rate
;
LONG64
rendered
,
dropped
;
BOOL
qos_handled
,
is_dropped
;
}
QualityControlImpl
;
void
QualityControlImpl_init
(
QualityControlImpl
*
This
,
IPin
*
input
,
IBaseFilter
*
self
);
...
...
@@ -209,6 +217,13 @@ ULONG WINAPI QualityControlImpl_Release(IQualityControl *iface);
HRESULT
WINAPI
QualityControlImpl_Notify
(
IQualityControl
*
iface
,
IBaseFilter
*
sender
,
Quality
qm
);
HRESULT
WINAPI
QualityControlImpl_SetSink
(
IQualityControl
*
iface
,
IQualityControl
*
tonotify
);
void
QualityControlRender_Start
(
QualityControlImpl
*
This
,
REFERENCE_TIME
tStart
);
void
QualityControlRender_SetClock
(
QualityControlImpl
*
This
,
IReferenceClock
*
clock
);
HRESULT
QualityControlRender_WaitFor
(
QualityControlImpl
*
This
,
IMediaSample
*
sample
,
HANDLE
ev
);
void
QualityControlRender_DoQOS
(
QualityControlImpl
*
priv
);
void
QualityControlRender_BeginRender
(
QualityControlImpl
*
This
);
void
QualityControlRender_EndRender
(
QualityControlImpl
*
This
);
/* Transform Filter */
typedef
struct
TransformFilter
{
...
...
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