From: Akihiro Sagawa <sagawa.aki@gmail.com> mpegpsdemux uses raw PTS values from the stream, which often start at a non-zero timestamp. To avoid an initial delay, we rebase the PTS by subtracting the first raw value so that the buffer timeline begins at zero for the MPEG-I Splitter in DirectShow. Without this adjustment, the first sample would not be presented until its original (non-zero) timestamp in MPEG-1 system stream. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59565 --- dlls/quartz/tests/mpegsplit.c | 2 +- dlls/winegstreamer/quartz_parser.c | 3 ++- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_parser.c | 27 +++++++++++++++++++++++++-- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/dlls/quartz/tests/mpegsplit.c b/dlls/quartz/tests/mpegsplit.c index 32d33b1fbef..06e32828e86 100644 --- a/dlls/quartz/tests/mpegsplit.c +++ b/dlls/quartz/tests/mpegsplit.c @@ -2107,7 +2107,7 @@ static void test_video_file(void) ok(testsink_audio.byte_count == 8777, "Audio sink got %u bytes.\n", testsink_audio.byte_count); /* Native uses 55 for the first sample timestamp, but there's no need to copy the exact value. */ - todo_wine ok(min(testsink_video.sample_start, testsink_audio.sample_start) < 100, + ok(min(testsink_video.sample_start, testsink_audio.sample_start) < 100, "The first sample timestamp is off by more 100, video %I64d and audio %I64d.\n", testsink_video.sample_start, testsink_audio.sample_start); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 9a26c863aa9..a1910202767 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -2752,7 +2752,8 @@ HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out) struct parser *object; HRESULT hr; - if (FAILED(hr = parser_create(WG_PARSER_CREATE_FLAG_OUTPUT_COMPRESSED, &object))) + if (FAILED(hr = parser_create(WG_PARSER_CREATE_FLAG_OUTPUT_COMPRESSED | + WG_PARSER_CREATE_FLAG_PTS_REBASED, &object))) return hr; strmbase_filter_init(&object->filter, outer, &CLSID_MPEG1Splitter, &mpeg_splitter_ops); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index c4b6043684b..d274d6f7457 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -222,6 +222,7 @@ enum wg_parser_create_flag { WG_PARSER_CREATE_FLAG_NONE = 0, WG_PARSER_CREATE_FLAG_OUTPUT_COMPRESSED = 1, + WG_PARSER_CREATE_FLAG_PTS_REBASED = 2, }; struct wg_parser_create_params diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index d63a329a9e1..c4b96d95d43 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -68,6 +68,7 @@ struct wg_parser GstPad *my_src; guint64 file_size, start_offset, next_offset, stop_offset; + GstClockTime base_pts; guint64 next_pull_offset; gchar *uri; @@ -76,7 +77,7 @@ struct wg_parser pthread_mutex_t mutex; pthread_cond_t init_cond; - bool output_compressed; + bool output_compressed, pts_rebased; bool no_more_pads, has_duration, error; bool err_on, warn_on; @@ -366,8 +367,17 @@ static NTSTATUS wg_parser_stream_get_buffer(void *args) * that this will need modification to wg_parser_stream_notify_qos() as * well. */ + /* Because mpegpsdemux reports a non-zero PTS for the earliest buffer among + * all streams, we rebase the PTS by subtracting base_pts so that our + * stream starts at zero for the MPEG-I Splitter in quartz. */ + if ((wg_buffer->has_pts = GST_BUFFER_PTS_IS_VALID(buffer))) - wg_buffer->pts = GST_BUFFER_PTS(buffer) / 100; + { + if (parser->pts_rebased && GST_CLOCK_TIME_IS_VALID(parser->base_pts)) + wg_buffer->pts = (GST_BUFFER_PTS(buffer) - parser->base_pts) / 100; + else + wg_buffer->pts = GST_BUFFER_PTS(buffer) / 100; + } if ((wg_buffer->has_duration = GST_BUFFER_DURATION_IS_VALID(buffer))) wg_buffer->duration = GST_BUFFER_DURATION(buffer) / 100; wg_buffer->discontinuity = GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT); @@ -734,6 +744,17 @@ static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *bu if (!stream->has_buffer) { stream->has_buffer = true; + + /* Keep the earliest PTS for adjusting. */ + if (!stream->has_initial_gap && + GST_BUFFER_PTS_IS_VALID(buffer) && + (GST_BUFFER_PTS(buffer) < parser->base_pts)) + { + parser->base_pts = GST_BUFFER_PTS(buffer); + GST_LOG("Updated base PTS to %" GST_TIME_FORMAT ".", + GST_TIME_ARGS(parser->base_pts)); + } + pthread_cond_signal(&parser->init_cond); } @@ -1890,8 +1911,10 @@ static NTSTATUS wg_parser_create(void *args) pthread_cond_init(&parser->read_cond, NULL); pthread_cond_init(&parser->read_done_cond, NULL); parser->output_compressed = params->flags & WG_PARSER_CREATE_FLAG_OUTPUT_COMPRESSED; + parser->pts_rebased = params->flags & WG_PARSER_CREATE_FLAG_PTS_REBASED; parser->err_on = params->err_on; parser->warn_on = params->warn_on; + parser->base_pts = GST_CLOCK_TIME_NONE; GST_DEBUG("Created winegstreamer parser %p.", parser); params->parser = (wg_parser_t)(ULONG_PTR)parser; return S_OK; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10864