2010-12-07 Philippe Normand <pnormand@igalia.com>
authorphiln@webkit.org <philn@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Dec 2010 20:47:00 +0000 (20:47 +0000)
committerphiln@webkit.org <philn@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Dec 2010 20:47:00 +0000 (20:47 +0000)
        Reviewed by Gustavo Noronha Silva.

        [GStreamer] ::buffered() should return multiple ranges in some cases
        https://bugs.webkit.org/show_bug.cgi?id=45101

        Improved the ::buffered() method thanks to the new buffering query
        support that landed in GStreamer 0.10.31. The method now
        queries the media buffered-ranges on the pipeline and queue2
        handles it if it's buffering the media to disk.

        The webkitwebsrc element also gained BYTES duration query
        support. This is needed in the rare cases where uridecodebin
        configures its queue before the HTTP server returns the media
        Content-Length.

        Test: http/tests/media/video-buffered.html

        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
        (WebCore::MediaPlayerPrivateGStreamer::buffered):
        * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp:
        (webkit_web_src_init):
        (webKitWebSrcQuery): Make webkitwebsrc handle the duration queries
        if it's aware of the media content-length.
        * platform/gtk/RenderThemeGtk.cpp:
        (WebCore::RenderThemeGtk::paintMediaSliderTrack): Fix position of
        the second and next buffered ranges.

LayoutTests:

        Reviewed by Gustavo Noronha Silva.

        [GStreamer] ::buffered() should return multiple ranges in some cases
        https://bugs.webkit.org/show_bug.cgi?id=45101

        New test for video.buffered attribute. The test is skipped for
        ports not returning multiple timeranges for video.buffered.

        * http/tests/media/video-buffered-expected.txt: Added.
        * http/tests/media/video-buffered.html: Added.
        * http/tests/resources/counting-captioned.mov: Added.
        * http/tests/media/video-throttled-load.cgi: added Range
        requests/responses support.
        * platform/chromium/test_expectations.txt:
        * platform/mac-leopard/Skipped:
        * platform/mac-snowleopard/Skipped:
        * platform/mac-tiger/Skipped:
        * platform/mac-wk2/Skipped:
        * platform/mac/Skipped:
        * platform/qt-mac/Skipped:
        * platform/qt-win/Skipped:
        * platform/qt-wk2/Skipped:
        * platform/qt/Skipped:
        * platform/win-wk2/Skipped:
        * platform/win/Skipped:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@73454 268f45cc-cd09-0410-ab3c-d52691b4dbfc

21 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/media/resources/counting-captioned.mov [new file with mode: 0644]
LayoutTests/http/tests/media/video-buffered-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/media/video-buffered.html [new file with mode: 0644]
LayoutTests/http/tests/media/video-throttled-load.cgi
LayoutTests/platform/chromium/test_expectations.txt
LayoutTests/platform/mac-leopard/Skipped
LayoutTests/platform/mac-snowleopard/Skipped
LayoutTests/platform/mac-tiger/Skipped
LayoutTests/platform/mac-wk2/Skipped
LayoutTests/platform/mac/Skipped
LayoutTests/platform/qt-mac/Skipped
LayoutTests/platform/qt-win/Skipped
LayoutTests/platform/qt-wk2/Skipped
LayoutTests/platform/qt/Skipped
LayoutTests/platform/win-wk2/Skipped
LayoutTests/platform/win/Skipped
WebCore/ChangeLog
WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp
WebCore/platform/gtk/RenderThemeGtk.cpp

index ab20c87..a059b26 100644 (file)
@@ -1,3 +1,31 @@
+2010-12-07  Philippe Normand  <pnormand@igalia.com>
+
+        Reviewed by Gustavo Noronha Silva.
+
+        [GStreamer] ::buffered() should return multiple ranges in some cases
+        https://bugs.webkit.org/show_bug.cgi?id=45101
+
+        New test for video.buffered attribute. The test is skipped for
+        ports not returning multiple timeranges for video.buffered.
+
+        * http/tests/media/video-buffered-expected.txt: Added.
+        * http/tests/media/video-buffered.html: Added.
+        * http/tests/resources/counting-captioned.mov: Added.
+        * http/tests/media/video-throttled-load.cgi: added Range
+        requests/responses support.
+        * platform/chromium/test_expectations.txt:
+        * platform/mac-leopard/Skipped:
+        * platform/mac-snowleopard/Skipped:
+        * platform/mac-tiger/Skipped:
+        * platform/mac-wk2/Skipped:
+        * platform/mac/Skipped:
+        * platform/qt-mac/Skipped:
+        * platform/qt-win/Skipped:
+        * platform/qt-wk2/Skipped:
+        * platform/qt/Skipped:
+        * platform/win-wk2/Skipped:
+        * platform/win/Skipped:
+
 2010-12-07  Yael Aharon  <yael.aharon@nokia.com>
 
         Reviewed by Antonio Gomes.
diff --git a/LayoutTests/http/tests/media/resources/counting-captioned.mov b/LayoutTests/http/tests/media/resources/counting-captioned.mov
new file mode 100644 (file)
index 0000000..92c4b13
Binary files /dev/null and b/LayoutTests/http/tests/media/resources/counting-captioned.mov differ
diff --git a/LayoutTests/http/tests/media/video-buffered-expected.txt b/LayoutTests/http/tests/media/video-buffered-expected.txt
new file mode 100644 (file)
index 0000000..fffeb04
--- /dev/null
@@ -0,0 +1,8 @@
+Start playing a video with preloading enabled, do a seek near the end and check multiple buffered timeranges have been created.
+
+EXPECTED (video.buffered.length == '1') OK
+RUN(video.currentTime = video.duration - 0.5)
+EVENT(ended)
+EXPECTED (video.buffered.length == '2') OK
+END OF TEST
+
diff --git a/LayoutTests/http/tests/media/video-buffered.html b/LayoutTests/http/tests/media/video-buffered.html
new file mode 100644 (file)
index 0000000..e958edf
--- /dev/null
@@ -0,0 +1,31 @@
+<html>
+<head>
+</head>
+<body onload="start()">
+<p>Start playing a video with preloading enabled, do a seek near the
+  end and check multiple buffered timeranges have been created.</p>
+<video id="video" preload="auto" autobuffer></video>
+<script src=../../../media/video-test.js></script>
+<script src=../../../media/media-file.js></script>
+<script>
+    function delayedSeek() {
+        testExpected("video.buffered.length", 1, "==");
+        run("video.currentTime = video.duration - 0.5");
+        waitForEvent("ended", ended);
+    }
+
+    function ended() {
+        testExpected("video.buffered.length", 2, "==");
+        endTest();
+    }
+
+    function start () {
+        video = document.getElementById('video');
+        video.src = "http://127.0.0.1:8000/media/video-throttled-load.cgi?nph=1&name=resources/counting-captioned.mov&throttle=20&type=video/quicktime";
+
+        video.play();
+        setTimeout(delayedSeek, 1000);
+     }
+</script>
+</body>
+</html>
index 9e8058c..e298bcb 100755 (executable)
@@ -19,21 +19,62 @@ my $chunkPerSec = $kbPerSec * 1024 / CHUNK_SIZE_BYTES;
 # Get MIME type if provided.  Default to video/mp4.
 my $type = $query->param('type') || "video/mp4";
 
-# Print HTTP Header, disabling cache.
-print "Content-type: " . $type . "\n"; 
-print "Content-Length: " . $filesize . "\n";
-print "Cache-Control: no-cache\n";
+my $nph = $query->param('nph') || 0;
+CGI->nph($nph);
+
+my $contentRange = $ENV{'HTTP_RANGE'};
+
+my $rangeEnd = $filesize - 1;
+my @parsedRange = (0, $rangeEnd);
+
+if ($nph) {
+    # Handle HTTP Range requests.
+    my $httpContentRange;
+    my $httpStatus;
+
+    if ($contentRange) {
+        my @values = split('=', $contentRange);
+        my $rangeType = $values[0];
+        @parsedRange = split("-", $values[1]);
+
+        if (!$parsedRange[1]) {
+            $parsedRange[1] = $rangeEnd;
+        }
+        $httpStatus = "206 Partial Content";
+        $httpContentRange = "bytes " . $parsedRange[0] . "-" . $parsedRange[1] . "/" . $filesize;
+    } else {
+        $httpStatus = "200 OK";
+    }
+
+    print "Status: " . $httpStatus . "\n";
+    print "Connection: close\n";
+    print "Content-Length: " . $filesize . "\n";
+    print "Content-Type: " . $type . "\n";
+    print "Accept-Ranges: bytes\n";
+    if ($httpContentRange) {
+        print "Content-Range: " . $httpContentRange . "\n";
+    }
+} else {
+    # Print HTTP Header, disabling cache.
+    print "Cache-Control: no-cache\n";
+    print "Content-Length: " . $filesize . "\n";
+    print "Content-Type: " . $type . "\n";
+}
+
 print "\n";
 
 open FILE, $name or die;
 binmode FILE;
 my ($data, $n);
 my $total = 0;
+
+seek(FILE, $parsedRange[0], 0);
+
 while (($n = read FILE, $data, 1024) != 0) {
     print $data;
 
     $total += $n;
-    if ($total >= $filesize) {
+    if (($total >= $filesize) || ($total > $parsedRange[1])) {
         last;
     }
 
index 232fc74..507d902 100644 (file)
@@ -786,6 +786,9 @@ BUG13907 BUG60355 : http/tests/security/local-video-src-from-remote.html = PASS
 // KNOWNISSUE : * we don't have test-par-16-9.ogv generated in WebKit * we don't handle aspect ratio correctly.
 BUG59635 : media/video-display-aspect-ratio.html = PASS FAIL TIMEOUT
 
+// video.buffered multiple TimeRanges support.
+BUG49165 SKIP : http/tests/media/video-buffered.html = PASS
+
 // These tests need to be changed to not rely on setTimeout().
 BUG13907 BUG60740 SLOW WIN DEBUG : media/video-played-collapse.html = PASS FAIL
 BUG13907 BUG60740 SLOW WIN DEBUG : media/video-seek-past-end-playing.html = PASS FAIL
index 6429471..c466413 100644 (file)
@@ -50,6 +50,9 @@ media/video-controls-zoomed.html
 media/video-zoom-controls.html
 media/video-volume.html
 
+# requires video.buffered to be able to return multiple timeranges
+http/tests/media/video-buffered.html
+
 # Disable flakey webgl test to make the bots green again.
 # https://bugs.webkit.org/show_bug.cgi?id=33924
 fast/canvas/webgl/texImage2DImageDataTest.html
index 55d2d59..35949b4 100644 (file)
@@ -73,6 +73,9 @@ media/unsupported-tracks.html
 # https://bugs.webkit.org/show_bug.cgi?id=33434
 media/video-error-does-not-exist.html
 
+# requires video.buffered to be able to return multiple timeranges
+http/tests/media/video-buffered.html
+
 #  Test times out due to CoreGraphics bug
 # <rdar://problem/7499927>
 fast/images/size-failure.html
index a496878..a41f415 100644 (file)
@@ -99,6 +99,9 @@ http/tests/navigation/parsed-iframe-dynamic-form-back-entry.html
 # https://bugs.webkit.org/show_bug.cgi?id=33323 - http/tests/media/video-error-abort.html times out
 http/tests/media/video-error-abort.html
 
+# requires video.buffered to be able to return multiple timeranges
+http/tests/media/video-buffered.html
+
 # Fails on all mac variants
 # https://bugs.webkit.org/show_bug.cgi?id=34933
 media/video-display-aspect-ratio.html
index 7dc0a6c..5a1c33e 100644 (file)
@@ -2290,3 +2290,6 @@ platform/mac/fast/events/objc-keyboard-event-creation.html
 # WebKit2 does not (should not?) support setting WebKitUsePreHTML5ParserQuirks
 # in its WebPreferences implementation.
 fast/parser/pre-html5-parser-quirks.html
+
+# requires video.buffered to be able to return multiple timeranges
+http/tests/media/video-buffered.html
index 2f8899c..f8c6d37 100644 (file)
@@ -252,6 +252,9 @@ fast/viewport
 # see also https://bugs.webkit.org/show_bug.cgi?id=45021
 media/context-menu-actions.html
 
+# requires video.buffered to be able to return multiple timeranges
+http/tests/media/video-buffered.html
+
 # FileSystem API is not supported.
 fast/filesystem
 
index 4148f87..5853f40 100644 (file)
@@ -1,3 +1,6 @@
 
 # This test requires ogg codecs
 media/media-can-play-ogg.html
+
+# requires video.buffered to be able to return multiple timeranges
+http/tests/media/video-buffered.html
index 4148f87..5853f40 100644 (file)
@@ -1,3 +1,6 @@
 
 # This test requires ogg codecs
 media/media-can-play-ogg.html
+
+# requires video.buffered to be able to return multiple timeranges
+http/tests/media/video-buffered.html
index 8db6cd2..45c0d01 100644 (file)
@@ -2460,3 +2460,5 @@ http/tests/security/aboutBlank/security-context-grandchildren-writeln-lexical.ht
 # https://bugs.webkit.org/show_bug.cgi?id=49321
 http/tests/history/popstate-fires-with-pending-requests.html
 
+# requires video.buffered to be able to return multiple timeranges
+http/tests/media/video-buffered.html
index 88a5c18..bcaf236 100644 (file)
@@ -661,6 +661,9 @@ media/media-can-play-mpeg4-video.html
 # https://bugs.webkit.org/show_bug.cgi?id=48617
 media/video-seek-by-small-increment.html
 
+# requires video.buffered to be able to return multiple timeranges
+http/tests/media/video-buffered.html
+
 # ============================================================================= #
 # Crashing tests due to re-enabled Phonon support in Buildbot's Qt              #
 # Skip these until a proper solution for the Phonon related crashes found.      #
index 532526e..6d874cb 100644 (file)
@@ -147,3 +147,6 @@ http/tests/xmlhttprequest/cross-origin-cookie-storage.html
 
 # Unexplained test timeouts.
 fast/js/exceptions-thrown-in-callbacks.html
+
+# requires video.buffered to be able to return multiple timeranges
+http/tests/media/video-buffered.html
index 3116fa3..04c2cc8 100644 (file)
@@ -299,6 +299,9 @@ editing/selection/context-menu-on-text.html
 # and https://bugs.webkit.org/show_bug.cgi?id=45021
 media/context-menu-actions.html
 
+# requires video.buffered to be able to return multiple timeranges
+http/tests/media/video-buffered.html
+
 # Assertion failure in replaySavedEvents http://webkit.org/b/21796
 editing/pasteboard/drop-text-events.html
 editing/selection/drag-in-iframe.html
index 3a2feb8..27a4a63 100644 (file)
@@ -1,3 +1,32 @@
+2010-12-07  Philippe Normand  <pnormand@igalia.com>
+
+        Reviewed by Gustavo Noronha Silva.
+
+        [GStreamer] ::buffered() should return multiple ranges in some cases
+        https://bugs.webkit.org/show_bug.cgi?id=45101
+
+        Improved the ::buffered() method thanks to the new buffering query
+        support that landed in GStreamer 0.10.31. The method now
+        queries the media buffered-ranges on the pipeline and queue2
+        handles it if it's buffering the media to disk.
+
+        The webkitwebsrc element also gained BYTES duration query
+        support. This is needed in the rare cases where uridecodebin
+        configures its queue before the HTTP server returns the media
+        Content-Length.
+
+        Test: http/tests/media/video-buffered.html
+
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+        (WebCore::MediaPlayerPrivateGStreamer::buffered):
+        * platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp:
+        (webkit_web_src_init):
+        (webKitWebSrcQuery): Make webkitwebsrc handle the duration queries
+        if it's aware of the media content-length.
+        * platform/gtk/RenderThemeGtk.cpp:
+        (WebCore::RenderThemeGtk::paintMediaSliderTrack): Fix position of
+        the second and next buffered ranges.
+
 2010-12-07  Yael Aharon  <yael.aharon@nokia.com>
 
         Reviewed by Antonio Gomes.
index e583096..38f8906 100644 (file)
@@ -747,9 +747,40 @@ MediaPlayer::ReadyState MediaPlayerPrivateGStreamer::readyState() const
 PassRefPtr<TimeRanges> MediaPlayerPrivateGStreamer::buffered() const
 {
     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
+    if (m_errorOccured || m_isStreaming)
+        return timeRanges.release();
+
+#if GST_CHECK_VERSION(0, 10, 31)
+    float mediaDuration(duration());
+    if (!mediaDuration || isinf(mediaDuration))
+        return timeRanges.release();
+
+    GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
+
+    if (!gst_element_query(m_playBin, query)) {
+        gst_query_unref(query);
+        return timeRanges.release();
+    }
+
+    gint64 rangeStart = 0, rangeStop = 0;
+    for (guint index = 0; index < gst_query_get_n_buffering_ranges(query); index++) {
+        if (gst_query_parse_nth_buffering_range(query, index, &rangeStart, &rangeStop))
+            timeRanges->add(static_cast<float>((rangeStart * mediaDuration) / 100),
+                            static_cast<float>((rangeStop * mediaDuration) / 100));
+    }
+
+    // Fallback to the more general maxTimeLoaded() if no range has
+    // been found.
+    if (!timeRanges->length())
+        if (float loaded = maxTimeLoaded())
+            timeRanges->add(0, loaded);
+
+    gst_query_unref(query);
+#else
     float loaded = maxTimeLoaded();
     if (!m_errorOccured && !m_isStreaming && loaded > 0)
         timeRanges->add(0, loaded);
+#endif
     return timeRanges.release();
 }
 
index 246dea0..e10e61f 100644 (file)
@@ -110,6 +110,7 @@ static void webKitWebSrcFinalize(GObject* object);
 static void webKitWebSrcSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* pspec);
 static void webKitWebSrcGetProperty(GObject* object, guint propID, GValue* value, GParamSpec* pspec);
 static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStateChange transition);
+static gboolean webKitWebSrcQuery(GstPad* pad, GstQuery* query);
 
 static void webKitWebSrcNeedDataCb(GstAppSrc* appsrc, guint length, gpointer userData);
 static void webKitWebSrcEnoughDataCb(GstAppSrc* appsrc, gpointer userData);
@@ -221,6 +222,7 @@ static void webkit_web_src_init(WebKitWebSrc* src,
                                                              padTemplate);
 
     gst_element_add_pad(GST_ELEMENT(src), priv->srcpad);
+    gst_pad_set_query_function(priv->srcpad, webKitWebSrcQuery);
 
     priv->appsrc = GST_APP_SRC(gst_element_factory_make("appsrc", 0));
     if (!priv->appsrc) {
@@ -476,6 +478,36 @@ static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStat
     return ret;
 }
 
+static gboolean webKitWebSrcQuery(GstPad* pad, GstQuery* query)
+{
+    WebKitWebSrc* src = WEBKIT_WEB_SRC(gst_pad_get_parent(pad));
+    gboolean result = FALSE;
+
+    switch (GST_QUERY_TYPE(query)) {
+    case GST_QUERY_DURATION:
+    {
+        GstFormat format;
+
+        gst_query_parse_duration(query, &format, NULL);
+
+        GST_DEBUG_OBJECT(src, "duration query in format %s", gst_format_get_name(format));
+        if ((format == GST_FORMAT_BYTES) && (src->priv->size > 0)) {
+            gst_query_set_duration(query, format, src->priv->size);
+            result = TRUE;
+        }
+        break;
+    }
+    default:
+        break;
+    }
+
+    if (!result)
+        result = gst_pad_query_default(pad, query);
+
+    gst_object_unref(src);
+    return result;
+}
+
 // uri handler interface
 
 static GstURIType webKitWebSrcUriGetType(void)
index c9e4243..7b25cd9 100644 (file)
@@ -853,7 +853,7 @@ bool RenderThemeGtk::paintMediaSliderTrack(RenderObject* o, const PaintInfo& pai
             rangeRect = trackRect;
             rangeRect.setWidth(width);
         } else {
-            rangeRect.setLocation(IntPoint((start * totalWidth) / mediaDuration, trackRect.y()));
+            rangeRect.setLocation(IntPoint(trackRect.x() + start / mediaDuration* totalWidth, trackRect.y()));
             rangeRect.setSize(IntSize(width, trackRect.height()));
         }