Skip to content

Commit f70f314

Browse files
committed
[wpe-2.46] Revert of revert of [MSE][GStreamer] Honor MP4 edit lists, bis
https://bugs.webkit.org/show_bug.cgi?id=231019 Reviewed by Xabier Rodriguez-Calvar. (Patch only for wpe-2.38 downstream) (See: #1185) This patch reintroduces https://commits.webkit.org/243426@main with some corrections that avoid the problems detected in https://bugs.webkit.org/show_bug.cgi?id=233861, which motivated the original patch revert. Original author: Alicia Boya Garcia <aboya@igalia.com> Source/WebCore: This patch takes into consideration the GstSegment attached to a sample to offset the PTS and DTS. This ensures accurate timestamps are obtained for MP4 files containing edit lists (commonly necessary for files containing video with B frames to have PTS starting at zero). Before this was implemented, a workaround was in place based on a heuristic (DTS = 0 && PTS > 0 && PTS < 0.1). The workaround is preserved for the sake of content without proper edit lists, but any edit list takes preference. The time fudge factor has been modified from 0.083 seconds up to 0.100 seconds to accomodate the size of the empty edit in test.mp4 used by Web Platform Tests. This test fixes improves expectation results and fixes two subtests in imported/w3c/web-platform-tests/media-source/mediasource-remove.html. This is a reworked version that avoids using gst_sample_set_buffer() which is not available on GStreamer 1.14, and fixes an issue where frames that would get a negative DTS were not being enqueued properly. LayoutTests: Update expectations for mediasource-remove.html in the GStreamer ports, as a couple subtests get fixed. * LayoutTests/platform/glib/imported/w3c/web-platform-tests/media-source/mediasource-remove-expected.txt: * Source/WebCore/Modules/mediasource/MediaSource.cpp: (WebCore::MediaSource::currentTimeFudgeFactor): * Source/WebCore/platform/graphics/SourceBufferPrivate.h: (WebCore::SourceBufferPrivate::timeFudgeFactor const): * Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.h: (WebCore::toGstClockTime): * Source/WebCore/platform/graphics/gstreamer/MediaSampleGStreamer.cpp: (WebCore::MediaSampleGStreamer::MediaSampleGStreamer): * Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp: (WebCore::bufferTimeToStreamTime): (WebCore::AppendPipeline::appsinkNewSample): (WebCore::matroskademuxForceSegmentStartToEqualZero): Now we reset segment.time in addition to segment.start. This avoids the regressions. Canonical link: https://commits.webkit.org/251332@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@295286 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 6743666 commit f70f314

File tree

6 files changed

+47
-28
lines changed

6 files changed

+47
-28
lines changed

LayoutTests/imported/w3c/web-platform-tests/media-source/mediasource-remove-expected.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ PASS Test remove while update pending.
1111
PASS Test aborting a remove operation.
1212
PASS Test remove with a start at the duration.
1313
PASS Test remove transitioning readyState from 'ended' to 'open'.
14-
FAIL Test removing all appended data. assert_equals: Initial buffered range. expected "{ [0.095, 6.548) }" but got "{ [0.000, 6.548) }"
15-
FAIL Test removing beginning of appended data. assert_equals: Initial buffered range. expected "{ [0.095, 6.548) }" but got "{ [0.000, 6.548) }"
16-
FAIL Test removing the middle of appended data. assert_equals: Initial buffered range. expected "{ [0.095, 6.548) }" but got "{ [0.000, 6.548) }"
17-
FAIL Test removing the end of appended data. assert_equals: Initial buffered range. expected "{ [0.095, 6.548) }" but got "{ [0.000, 6.548) }"
14+
PASS Test removing all appended data.
15+
PASS Test removing beginning of appended data.
16+
FAIL Test removing the middle of appended data. assert_equals: Buffered ranges after remove(). expected "{ [0.095, 0.997) [3.298, 6.548) }" but got "{ [0.095, 0.975) [3.298, 6.548) }"
17+
FAIL Test removing the end of appended data. assert_equals: Buffered ranges after remove(). expected "{ [0.095, 1.022) }" but got "{ [0.095, 0.995) }"
1818

Source/WebCore/Modules/mediasource/MediaSource.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,8 @@ ExceptionOr<void> MediaSource::clearLiveSeekableRange()
460460

461461
const MediaTime& MediaSource::currentTimeFudgeFactor()
462462
{
463-
// Allow hasCurrentTime() to be off by as much as the length of two 24fps video frames
464-
static NeverDestroyed<MediaTime> fudgeFactor(2002, 24000);
463+
// Allow hasCurrentTime() to be off by as much as 100ms.
464+
static NeverDestroyed<MediaTime> fudgeFactor(1, 10);
465465
return fudgeFactor;
466466
}
467467

Source/WebCore/platform/graphics/PlatformTimeRanges.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const PlatformTimeRanges& PlatformTimeRanges::emptyRanges()
5959

6060
MediaTime PlatformTimeRanges::timeFudgeFactor()
6161
{
62-
return { 2002, 24000 };
62+
return { 1, 10 };
6363
}
6464

6565
void PlatformTimeRanges::invert()

Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ uint64_t toGstUnsigned64Time(const MediaTime&);
9090

9191
inline GstClockTime toGstClockTime(const MediaTime& mediaTime)
9292
{
93+
if (mediaTime.isInvalid())
94+
return GST_CLOCK_TIME_NONE;
95+
if (mediaTime < MediaTime::zeroTime())
96+
return 0;
9397
return static_cast<GstClockTime>(toGstUnsigned64Time(mediaTime));
9498
}
9599

Source/WebCore/platform/graphics/gstreamer/MediaSampleGStreamer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ MediaSampleGStreamer::MediaSampleGStreamer(GRefPtr<GstSample>&& sample, const Fl
6464
}
6565

6666
m_size = gst_buffer_get_size(buffer);
67+
m_sample = adoptGRef(gst_sample_new(buffer, gst_sample_get_caps(m_sample.get()), nullptr,
68+
gst_sample_get_info(m_sample.get()) ? gst_structure_copy(gst_sample_get_info(m_sample.get())) : nullptr));
6769

6870
if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT))
6971
m_flags = MediaSample::None;

Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,20 @@ void AppendPipeline::handleEndOfAppend()
419419
sourceBufferPrivate().didReceiveAllPendingSamples();
420420
}
421421

422+
static MediaTime bufferTimeToStreamTime(const GstSegment* segment, GstClockTime bufferTime)
423+
{
424+
if (bufferTime == GST_CLOCK_TIME_NONE)
425+
return MediaTime::invalidTime();
426+
427+
guint64 streamTime;
428+
int sign = gst_segment_to_stream_time_full(segment, GST_FORMAT_TIME, bufferTime, &streamTime);
429+
if (!sign) {
430+
GST_ERROR("Couldn't map buffer time %" GST_TIME_FORMAT " to segment %" GST_PTR_FORMAT, GST_TIME_ARGS(bufferTime), segment);
431+
return MediaTime::invalidTime();
432+
}
433+
return MediaTime(sign * streamTime, GST_SECOND);
434+
}
435+
422436
void AppendPipeline::appsinkNewSample(const Track& track, GRefPtr<GstSample>&& sample)
423437
{
424438
ASSERT(isMainThread());
@@ -435,36 +449,34 @@ void AppendPipeline::appsinkNewSample(const Track& track, GRefPtr<GstSample>&& s
435449
return;
436450
}
437451

452+
GstSegment* segment = gst_sample_get_segment(sample.get());
438453
auto mediaSample = MediaSampleGStreamer::create(WTFMove(sample), track.presentationSize, track.trackId);
439454

455+
if (segment && (segment->time || segment->start)) {
456+
// MP4 has the concept of edit lists, where some buffer time needs to be offsetted, often very slightly,
457+
// to get exact timestamps.
458+
MediaTime pts = bufferTimeToStreamTime(segment, GST_BUFFER_PTS(buffer));
459+
MediaTime dts = bufferTimeToStreamTime(segment, GST_BUFFER_DTS(buffer));
460+
GST_TRACE_OBJECT(track.appsinkPad.get(), "Mapped buffer to segment, PTS %" GST_TIME_FORMAT " -> %s DTS %" GST_TIME_FORMAT " -> %s",
461+
GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), pts.toString().utf8().data(), GST_TIME_ARGS(GST_BUFFER_DTS(buffer)), dts.toString().utf8().data());
462+
mediaSample->setTimestamps(pts, dts);
463+
} else if (!GST_BUFFER_DTS(buffer) && GST_BUFFER_PTS(buffer) > 0 && GST_BUFFER_PTS(buffer) <= 100'000'000) {
464+
// Because a track presentation time starting at some close to zero, but not exactly zero time can cause unexpected
465+
// results for applications, we extend the duration of this first sample to the left so that it starts at zero.
466+
// This is relevant for files that should have an edit list but don't, or when using GStreamer < 1.16, where
467+
// edit lists are not parsed in push-mode.
468+
469+
GST_DEBUG("Extending first sample of track '%" PRIu64 "' to make it start at PTS=0 %" GST_PTR_FORMAT, track.trackId, buffer);
470+
mediaSample->extendToTheBeginning();
471+
}
472+
440473
GST_TRACE_OBJECT(pipeline(), "append: trackId=%" PRIu64 " PTS=%s DTS=%s DUR=%s presentationSize=%.0fx%.0f",
441474
mediaSample->trackID(),
442475
mediaSample->presentationTime().toString().utf8().data(),
443476
mediaSample->decodeTime().toString().utf8().data(),
444477
mediaSample->duration().toString().utf8().data(),
445478
mediaSample->presentationSize().width(), mediaSample->presentationSize().height());
446479

447-
// Hack, rework when GStreamer >= 1.16 becomes a requirement:
448-
// We're not applying edit lists. GStreamer < 1.16 doesn't emit the correct segments to do so.
449-
// GStreamer fix in https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/commit/c2a0da8096009f0f99943f78dc18066965be60f9
450-
// Also, in order to apply them we would need to convert the timestamps to stream time, which we're not currently
451-
// doing for consistency between GStreamer versions.
452-
//
453-
// In consequence, the timestamps we're handling here are unedited track time. In track time, the first sample is
454-
// guaranteed to have DTS == 0, but in the case of streams with B-frames, often PTS > 0. Edit lists fix this by
455-
// offsetting all timestamps by that amount in movie time, but we can't do that if we don't have access to them.
456-
// (We could assume the track PTS of the sample with track DTS = 0 is the offset, but we don't have any guarantee
457-
// we will get appended that sample first, or ever).
458-
//
459-
// Because a track presentation time starting at some close to zero, but not exactly zero time can cause unexpected
460-
// results for applications, we extend the duration of this first sample to the left so that it starts at zero.
461-
if (mediaSample->decodeTime() == MediaTime::zeroTime() && mediaSample->presentationTime() > MediaTime::zeroTime()
462-
&& mediaSample->presentationTime() <= MediaTime(1, 10)
463-
&& mediaSample->isSync()) {
464-
GST_DEBUG_OBJECT(pipeline(), "Extending first sample to make it start at PTS=0");
465-
mediaSample->extendToTheBeginning();
466-
}
467-
468480
m_sourceBufferPrivate.didReceiveSample(mediaSample.get());
469481
}
470482

@@ -1170,6 +1182,7 @@ static GstPadProbeReturn matroskademuxForceSegmentStartToEqualZero(GstPad*, GstP
11701182
gst_event_copy_segment(event, &segment);
11711183

11721184
segment.start = 0;
1185+
segment.time = 0;
11731186

11741187
GRefPtr<GstEvent> newEvent = adoptGRef(gst_event_new_segment(&segment));
11751188
gst_event_replace(reinterpret_cast<GstEvent**>(&info->data), newEvent.get());

0 commit comments

Comments
 (0)