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
b9e8a742
Commit
b9e8a742
authored
Dec 02, 2023
by
Anton Baskanov
Committed by
Alexandre Julliard
Dec 05, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
winegstreamer: Handle quality control messages in CMpegVideoCodec.
Based on the code from quartz_parser and wg_parser.
parent
1fd2958f
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
139 additions
and
20 deletions
+139
-20
mpegvideo.c
dlls/quartz/tests/mpegvideo.c
+4
-4
gst_private.h
dlls/winegstreamer/gst_private.h
+2
-0
main.c
dlls/winegstreamer/main.c
+18
-0
quartz_transform.c
dlls/winegstreamer/quartz_transform.c
+72
-16
unix_private.h
dlls/winegstreamer/unix_private.h
+1
-0
unixlib.h
dlls/winegstreamer/unixlib.h
+10
-0
wg_parser.c
dlls/winegstreamer/wg_parser.c
+2
-0
wg_transform.c
dlls/winegstreamer/wg_transform.c
+30
-0
No files found.
dlls/quartz/tests/mpegvideo.c
View file @
b9e8a742
...
...
@@ -1170,14 +1170,14 @@ static void test_quality_control(IFilterGraph2 *graph, IBaseFilter *filter,
ok
(
hr
==
S_OK
,
"Got hr %#lx.
\n
"
,
hr
);
hr
=
IQualityControl_Notify
(
source_qc
,
&
testsink
->
filter
.
IBaseFilter_iface
,
quality
);
todo_wine
ok
(
hr
==
S_OK
,
"Got hr %#lx.
\n
"
,
hr
);
ok
(
hr
==
S_OK
,
"Got hr %#lx.
\n
"
,
hr
);
hr
=
IFilterGraph2_ConnectDirect
(
graph
,
&
testsource
->
source
.
pin
.
IPin_iface
,
sink
,
&
mpeg_mt
);
ok
(
hr
==
S_OK
,
"Got hr %#lx.
\n
"
,
hr
);
testsource_qc
.
notify_sender
=
(
IBaseFilter
*
)
0xdeadbeef
;
hr
=
IQualityControl_Notify
(
source_qc
,
&
testsink
->
filter
.
IBaseFilter_iface
,
quality
);
todo_wine
ok
(
hr
==
S_OK
,
"Got hr %#lx.
\n
"
,
hr
);
ok
(
hr
==
S_OK
,
"Got hr %#lx.
\n
"
,
hr
);
ok
(
testsource_qc
.
notify_sender
==
(
IBaseFilter
*
)
0xdeadbeef
,
"Got sender %p.
\n
"
,
testsource_qc
.
notify_sender
);
...
...
@@ -1186,11 +1186,11 @@ static void test_quality_control(IFilterGraph2 *graph, IBaseFilter *filter,
qc
.
notify_sender
=
(
IBaseFilter
*
)
0xdeadbeef
;
hr
=
IQualityControl_Notify
(
source_qc
,
&
testsink
->
filter
.
IBaseFilter_iface
,
quality
);
ok
(
hr
==
S_OK
,
"Got hr %#lx.
\n
"
,
hr
);
todo_wine
ok
(
qc
.
notify_sender
==
(
IBaseFilter
*
)
0xdeadbeef
,
"Got sender %p.
\n
"
,
qc
.
notify_sender
);
ok
(
qc
.
notify_sender
==
(
IBaseFilter
*
)
0xdeadbeef
,
"Got sender %p.
\n
"
,
qc
.
notify_sender
);
qc
.
notify_hr
=
E_FAIL
;
hr
=
IQualityControl_Notify
(
source_qc
,
&
testsink
->
filter
.
IBaseFilter_iface
,
quality
);
todo_wine
ok
(
hr
==
S_OK
,
"Got hr %#lx.
\n
"
,
hr
);
ok
(
hr
==
S_OK
,
"Got hr %#lx.
\n
"
,
hr
);
qc
.
notify_hr
=
S_OK
;
IFilterGraph2_Disconnect
(
graph
,
sink
);
...
...
dlls/winegstreamer/gst_private.h
View file @
b9e8a742
...
...
@@ -109,6 +109,8 @@ bool wg_transform_set_output_format(wg_transform_t transform, struct wg_format *
bool
wg_transform_get_status
(
wg_transform_t
transform
,
bool
*
accepts_input
);
HRESULT
wg_transform_drain
(
wg_transform_t
transform
);
HRESULT
wg_transform_flush
(
wg_transform_t
transform
);
void
wg_transform_notify_qos
(
wg_transform_t
transform
,
bool
underflow
,
double
proportion
,
int64_t
diff
,
uint64_t
timestamp
);
HRESULT
wg_muxer_create
(
const
char
*
format
,
wg_muxer_t
*
muxer
);
void
wg_muxer_destroy
(
wg_muxer_t
muxer
);
...
...
dlls/winegstreamer/main.c
View file @
b9e8a742
...
...
@@ -457,6 +457,24 @@ HRESULT wg_transform_flush(wg_transform_t transform)
return
S_OK
;
}
void
wg_transform_notify_qos
(
wg_transform_t
transform
,
bool
underflow
,
double
proportion
,
int64_t
diff
,
uint64_t
timestamp
)
{
struct
wg_transform_notify_qos_params
params
=
{
.
transform
=
transform
,
.
underflow
=
underflow
,
.
proportion
=
proportion
,
.
diff
=
diff
,
.
timestamp
=
timestamp
,
};
TRACE
(
"transform %#I64x, underflow %d, proportion %.16e, diff %I64d, timestamp %I64u.
\n
"
,
transform
,
underflow
,
proportion
,
diff
,
timestamp
);
WINE_UNIX_CALL
(
unix_wg_transform_notify_qos
,
&
params
);
}
HRESULT
wg_muxer_create
(
const
char
*
format
,
wg_muxer_t
*
muxer
)
{
struct
wg_muxer_create_params
params
=
...
...
dlls/winegstreamer/quartz_transform.c
View file @
b9e8a742
...
...
@@ -52,6 +52,7 @@ struct transform_ops
HRESULT
(
*
source_query_accept
)(
struct
transform
*
filter
,
const
AM_MEDIA_TYPE
*
mt
);
HRESULT
(
*
source_get_media_type
)(
struct
transform
*
filter
,
unsigned
int
index
,
AM_MEDIA_TYPE
*
mt
);
HRESULT
(
*
source_decide_buffer_size
)(
struct
transform
*
filter
,
IMemAllocator
*
allocator
,
ALLOCATOR_PROPERTIES
*
props
);
HRESULT
(
*
source_qc_notify
)(
struct
transform
*
filter
,
IBaseFilter
*
sender
,
Quality
q
);
};
static
inline
struct
transform
*
impl_from_strmbase_filter
(
struct
strmbase_filter
*
iface
)
...
...
@@ -505,23 +506,8 @@ static ULONG WINAPI source_quality_control_Release(IQualityControl *iface)
static
HRESULT
WINAPI
source_quality_control_Notify
(
IQualityControl
*
iface
,
IBaseFilter
*
sender
,
Quality
q
)
{
struct
transform
*
filter
=
impl_from_source_IQualityControl
(
iface
);
IQualityControl
*
peer
;
HRESULT
hr
=
VFW_E_NOT_FOUND
;
TRACE
(
"filter %p, sender %p, type %#x, proportion %ld, late %s, timestamp %s.
\n
"
,
filter
,
sender
,
q
.
Type
,
q
.
Proportion
,
debugstr_time
(
q
.
Late
),
debugstr_time
(
q
.
TimeStamp
));
if
(
filter
->
qc_sink
)
return
IQualityControl_Notify
(
filter
->
qc_sink
,
&
filter
->
filter
.
IBaseFilter_iface
,
q
);
if
(
filter
->
sink
.
pin
.
peer
&&
SUCCEEDED
(
IPin_QueryInterface
(
filter
->
sink
.
pin
.
peer
,
&
IID_IQualityControl
,
(
void
**
)
&
peer
)))
{
hr
=
IQualityControl_Notify
(
peer
,
&
filter
->
filter
.
IBaseFilter_iface
,
q
);
IQualityControl_Release
(
peer
);
}
return
hr
;
return
filter
->
ops
->
source_qc_notify
(
filter
,
sender
,
q
);
}
static
HRESULT
WINAPI
source_quality_control_SetSink
(
IQualityControl
*
iface
,
IQualityControl
*
sink
)
...
...
@@ -567,6 +553,73 @@ static HRESULT transform_create(IUnknown *outer, const CLSID *clsid, const struc
return
S_OK
;
}
static
HRESULT
passthrough_source_qc_notify
(
struct
transform
*
filter
,
IBaseFilter
*
sender
,
Quality
q
)
{
IQualityControl
*
peer
;
HRESULT
hr
=
VFW_E_NOT_FOUND
;
TRACE
(
"filter %p, sender %p, type %s, proportion %ld, late %s, timestamp %s.
\n
"
,
filter
,
sender
,
q
.
Type
==
Famine
?
"Famine"
:
"Flood"
,
q
.
Proportion
,
debugstr_time
(
q
.
Late
),
debugstr_time
(
q
.
TimeStamp
));
if
(
filter
->
qc_sink
)
return
IQualityControl_Notify
(
filter
->
qc_sink
,
&
filter
->
filter
.
IBaseFilter_iface
,
q
);
if
(
filter
->
sink
.
pin
.
peer
&&
SUCCEEDED
(
IPin_QueryInterface
(
filter
->
sink
.
pin
.
peer
,
&
IID_IQualityControl
,
(
void
**
)
&
peer
)))
{
hr
=
IQualityControl_Notify
(
peer
,
&
filter
->
filter
.
IBaseFilter_iface
,
q
);
IQualityControl_Release
(
peer
);
}
return
hr
;
}
static
HRESULT
handle_source_qc_notify
(
struct
transform
*
filter
,
IBaseFilter
*
sender
,
Quality
q
)
{
uint64_t
timestamp
;
int64_t
diff
;
TRACE
(
"filter %p, sender %p, type %s, proportion %ld, late %s, timestamp %s.
\n
"
,
filter
,
sender
,
q
.
Type
==
Famine
?
"Famine"
:
"Flood"
,
q
.
Proportion
,
debugstr_time
(
q
.
Late
),
debugstr_time
(
q
.
TimeStamp
));
/* DirectShow filters sometimes pass negative timestamps (Audiosurf uses the
* current time instead of the time of the last buffer). GstClockTime is
* unsigned, so clamp it to 0. */
timestamp
=
max
(
q
.
TimeStamp
,
0
);
/* The documentation specifies that timestamp + diff must be nonnegative. */
diff
=
q
.
Late
;
if
(
diff
<
0
&&
timestamp
<
(
uint64_t
)
-
diff
)
diff
=
-
timestamp
;
/* DirectShow "Proportion" describes what percentage of buffers the upstream
* filter should keep (i.e. dropping the rest). If frames are late, the
* proportion will be less than 1. For example, a proportion of 500 means
* that the element should drop half of its frames, essentially because
* frames are taking twice as long as they should to arrive.
*
* GStreamer "proportion" is the inverse of this; it describes how much
* faster the upstream element should produce frames. I.e. if frames are
* taking twice as long as they should to arrive, we want the frames to be
* decoded twice as fast, and so we pass 2.0 to GStreamer. */
if
(
!
q
.
Proportion
)
{
WARN
(
"Ignoring quality message with zero proportion.
\n
"
);
return
S_OK
;
}
/* GST_QOS_TYPE_OVERFLOW is also used for buffers that arrive on time, but
* DirectShow filters might use Famine, so check that there actually is an
* underrun. */
wg_transform_notify_qos
(
filter
->
transform
,
q
.
Type
==
Famine
&&
q
.
Proportion
<
1000
,
1000
.
0
/
q
.
Proportion
,
diff
,
timestamp
);
return
S_OK
;
}
static
HRESULT
mpeg_audio_codec_sink_query_accept
(
struct
transform
*
filter
,
const
AM_MEDIA_TYPE
*
mt
)
{
const
MPEG1WAVEFORMAT
*
format
;
...
...
@@ -686,6 +739,7 @@ static const struct transform_ops mpeg_audio_codec_transform_ops =
mpeg_audio_codec_source_query_accept
,
mpeg_audio_codec_source_get_media_type
,
mpeg_audio_codec_source_decide_buffer_size
,
passthrough_source_qc_notify
,
};
HRESULT
mpeg_audio_codec_create
(
IUnknown
*
outer
,
IUnknown
**
out
)
...
...
@@ -837,6 +891,7 @@ static const struct transform_ops mpeg_video_codec_transform_ops =
mpeg_video_codec_source_query_accept
,
mpeg_video_codec_source_get_media_type
,
mpeg_video_codec_source_decide_buffer_size
,
handle_source_qc_notify
,
};
HRESULT
mpeg_video_codec_create
(
IUnknown
*
outer
,
IUnknown
**
out
)
...
...
@@ -962,6 +1017,7 @@ static const struct transform_ops mpeg_layer3_decoder_transform_ops =
mpeg_layer3_decoder_source_query_accept
,
mpeg_layer3_decoder_source_get_media_type
,
mpeg_layer3_decoder_source_decide_buffer_size
,
passthrough_source_qc_notify
,
};
HRESULT
mpeg_layer3_decoder_create
(
IUnknown
*
outer
,
IUnknown
**
out
)
...
...
dlls/winegstreamer/unix_private.h
View file @
b9e8a742
...
...
@@ -62,6 +62,7 @@ extern NTSTATUS wg_transform_read_data(void *args);
extern
NTSTATUS
wg_transform_get_status
(
void
*
args
);
extern
NTSTATUS
wg_transform_drain
(
void
*
args
);
extern
NTSTATUS
wg_transform_flush
(
void
*
args
);
extern
NTSTATUS
wg_transform_notify_qos
(
void
*
args
);
/* wg_muxer.c */
...
...
dlls/winegstreamer/unixlib.h
View file @
b9e8a742
...
...
@@ -372,6 +372,15 @@ struct wg_transform_get_status_params
UINT32
accepts_input
;
};
struct
wg_transform_notify_qos_params
{
wg_transform_t
transform
;
UINT8
underflow
;
DOUBLE
proportion
;
INT64
diff
;
UINT64
timestamp
;
};
struct
wg_muxer_create_params
{
wg_muxer_t
muxer
;
...
...
@@ -439,6 +448,7 @@ enum unix_funcs
unix_wg_transform_get_status
,
unix_wg_transform_drain
,
unix_wg_transform_flush
,
unix_wg_transform_notify_qos
,
unix_wg_muxer_create
,
unix_wg_muxer_destroy
,
...
...
dlls/winegstreamer/wg_parser.c
View file @
b9e8a742
...
...
@@ -1921,6 +1921,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
X
(
wg_transform_get_status
),
X
(
wg_transform_drain
),
X
(
wg_transform_flush
),
X
(
wg_transform_notify_qos
),
X
(
wg_muxer_create
),
X
(
wg_muxer_destroy
),
...
...
@@ -2253,6 +2254,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
X
(
wg_transform_get_status
),
X
(
wg_transform_drain
),
X
(
wg_transform_flush
),
X
(
wg_transform_notify_qos
),
X64
(
wg_muxer_create
),
X
(
wg_muxer_destroy
),
...
...
dlls/winegstreamer/wg_transform.c
View file @
b9e8a742
...
...
@@ -930,3 +930,33 @@ NTSTATUS wg_transform_flush(void *args)
return
STATUS_SUCCESS
;
}
NTSTATUS
wg_transform_notify_qos
(
void
*
args
)
{
const
struct
wg_transform_notify_qos_params
*
params
=
args
;
struct
wg_transform
*
transform
=
get_transform
(
params
->
transform
);
GstClockTimeDiff
diff
=
params
->
diff
*
100
;
GstClockTime
stream_time
;
GstEvent
*
event
;
/* We return timestamps in stream time, i.e. relative to the start of the
* file (or other medium), but gst_event_new_qos() expects the timestamp in
* running time. */
stream_time
=
gst_segment_to_running_time
(
&
transform
->
segment
,
GST_FORMAT_TIME
,
params
->
timestamp
*
100
);
if
(
diff
<
(
GstClockTimeDiff
)
-
stream_time
)
diff
=
-
stream_time
;
if
(
stream_time
==
-
1
)
{
/* This can happen legitimately if the sample falls outside of the
* segment bounds. GStreamer elements shouldn't present the sample in
* that case, but DirectShow doesn't care. */
GST_LOG
(
"Ignoring QoS event."
);
return
S_OK
;
}
if
(
!
(
event
=
gst_event_new_qos
(
params
->
underflow
?
GST_QOS_TYPE_UNDERFLOW
:
GST_QOS_TYPE_OVERFLOW
,
params
->
proportion
,
diff
,
stream_time
)))
GST_ERROR
(
"Failed to create QOS event."
);
push_event
(
transform
->
my_sink
,
event
);
return
S_OK
;
}
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