Title: [179762] trunk
Revision
179762
Author
[email protected]
Date
2015-02-06 14:14:20 -0800 (Fri, 06 Feb 2015)

Log Message

[MSE] Implement Append Error algorithm.
https://bugs.webkit.org/show_bug.cgi?id=139439

Patch by Bartlomiej Gajda <[email protected]> on 2015-02-06
Reviewed by Jer Noble.

If Source Buffer has not received first init segment, then it shall call endOfStream after receiving
Media Segment, as per Media Source spec. (from 17 July 2014) in paragraph 3.5.1 point 6.1.
Source/WebCore:

Based this change on Editor's Draft 12 December 2014, as it clarifies order of events.

Test: media/media-source/media-source-append-media-segment-without-init.html

* Modules/mediasource/MediaSource.cpp:
(WebCore::MediaSource::streamEndedWithError):
* Modules/mediasource/MediaSource.h:
* Modules/mediasource/SourceBuffer.cpp:
(WebCore::SourceBuffer::sourceBufferPrivateAppendComplete):
(WebCore::SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment):
(WebCore::SourceBuffer::validateInitializationSegment):
(WebCore::SourceBuffer::appendError):
* Modules/mediasource/SourceBuffer.h:

LayoutTests:

Added test which after creating SourceBuffer sends media sample, without any init segments.
Updated existing tests, so they correctly expect updateend and error as per Append Error algorithm.

* media/media-source/media-source-append-failed-expected.txt:
* media/media-source/media-source-append-failed.html:
* media/media-source/media-source-append-media-segment-without-init-expected.txt: Added.
* media/media-source/media-source-append-media-segment-without-init.html: Added.
* media/media-source/media-source-multiple-initialization-segments-expected.txt:
* media/media-source/media-source-multiple-initialization-segments.html:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (179761 => 179762)


--- trunk/LayoutTests/ChangeLog	2015-02-06 22:08:05 UTC (rev 179761)
+++ trunk/LayoutTests/ChangeLog	2015-02-06 22:14:20 UTC (rev 179762)
@@ -1,3 +1,22 @@
+2015-02-06  Bartlomiej Gajda  <[email protected]>
+
+        [MSE] Implement Append Error algorithm.
+        https://bugs.webkit.org/show_bug.cgi?id=139439
+
+        Reviewed by Jer Noble.
+
+        If Source Buffer has not received first init segment, then it shall call endOfStream after receiving
+        Media Segment, as per Media Source spec. (from 17 July 2014) in paragraph 3.5.1 point 6.1.
+        Added test which after creating SourceBuffer sends media sample, without any init segments.
+        Updated existing tests, so they correctly expect updateend and error as per Append Error algorithm.
+
+        * media/media-source/media-source-append-failed-expected.txt:
+        * media/media-source/media-source-append-failed.html:
+        * media/media-source/media-source-append-media-segment-without-init-expected.txt: Added.
+        * media/media-source/media-source-append-media-segment-without-init.html: Added.
+        * media/media-source/media-source-multiple-initialization-segments-expected.txt:
+        * media/media-source/media-source-multiple-initialization-segments.html:
+
 2015-02-06  Alexey Proskuryakov  <[email protected]>
 
         Correct expectations for inspector/css/selector-dynamic-specificity.html.

Modified: trunk/LayoutTests/media/media-source/media-source-append-failed-expected.txt (179761 => 179762)


--- trunk/LayoutTests/media/media-source/media-source-append-failed-expected.txt	2015-02-06 22:08:05 UTC (rev 179761)
+++ trunk/LayoutTests/media/media-source/media-source-append-failed-expected.txt	2015-02-06 22:14:20 UTC (rev 179762)
@@ -4,6 +4,8 @@
 RUN(sourceBuffer = source.addSourceBuffer("video/mock; codecs=mock"))
 RUN(sourceBuffer.appendBuffer(initSegment))
 EVENT(updatestart)
+EVENT(error)
+EVENT(updateend)
 EVENT(sourceended)
 END OF TEST
 

Modified: trunk/LayoutTests/media/media-source/media-source-append-failed.html (179761 => 179762)


--- trunk/LayoutTests/media/media-source/media-source-append-failed.html	2015-02-06 22:08:05 UTC (rev 179761)
+++ trunk/LayoutTests/media/media-source/media-source-append-failed.html	2015-02-06 22:14:20 UTC (rev 179762)
@@ -25,6 +25,7 @@
 
         waitForEventOn(sourceBuffer, 'updatestart');
         waitForEventOn(sourceBuffer, 'update');
+        waitForEventOn(sourceBuffer, 'error');
         waitForEventOn(sourceBuffer, 'updateend');
         waitForEventOn(source, 'sourceended', endTest);
         initSegment = makeAnInvalidBox();

Copied: trunk/LayoutTests/media/media-source/media-source-append-media-segment-without-init-expected.txt (from rev 179758, trunk/LayoutTests/media/media-source/media-source-append-failed-expected.txt) (0 => 179762)


--- trunk/LayoutTests/media/media-source/media-source-append-media-segment-without-init-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-append-media-segment-without-init-expected.txt	2015-02-06 22:14:20 UTC (rev 179762)
@@ -0,0 +1,8 @@
+
+RUN(video.src = ""
+EVENT(sourceopen)
+RUN(sourceBuffer = source.addSourceBuffer("video/mock; codecs=mock"))
+RUN(sourceBuffer.appendBuffer(samples))
+EVENT(error)
+END OF TEST
+

Added: trunk/LayoutTests/media/media-source/media-source-append-media-segment-without-init.html (0 => 179762)


--- trunk/LayoutTests/media/media-source/media-source-append-media-segment-without-init.html	                        (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-append-media-segment-without-init.html	2015-02-06 22:14:20 UTC (rev 179762)
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <title>mock-media-source</title>
+    <script src=""
+    <script src=""
+    <script>
+    var source;
+    var sourceBuffer;
+    var initSegment;
+    var wasError = false;
+
+    if (window.internals)
+        internals.initializeMockMediaSource();
+
+    function runTest() {
+        findMediaElement();
+
+        source = new MediaSource();
+        waitForEventOn(source, 'sourceopen', sourceOpen, false, true);
+        run('video.src = ""
+    }
+
+    function sourceOpen() {
+        run('sourceBuffer = source.addSourceBuffer("video/mock; codecs=mock")');
+
+        // Note: In normal usage we should send this line, but this checks what happens if we don't.
+        // initSegment = makeAInit(0, [makeATrack(1, 'mock', TRACK_KIND.VIDEO)]);
+
+        samples = concatenateSamples([
+            makeASample(0, 0, 1, 1, SAMPLE_FLAG.SYNC),
+            makeASample(1, 1, 1, 1, SAMPLE_FLAG.NONE),
+        ]);
+
+        // Note: if code correctly handles sample without init, it will go through Segment Parser Loop
+        // if not, we will receive update event as part of Coded Frame Processing
+        waitForEventOn(sourceBuffer, 'error', null, true, true);
+        failTestIn(2000);
+
+        run('sourceBuffer.appendBuffer(samples)');
+    }
+
+    </script>
+</head>
+<body _onload_="runTest()">
+    <video></video>
+</body>
+</html>

Modified: trunk/LayoutTests/media/media-source/media-source-multiple-initialization-segments-expected.txt (179761 => 179762)


--- trunk/LayoutTests/media/media-source/media-source-multiple-initialization-segments-expected.txt	2015-02-06 22:08:05 UTC (rev 179761)
+++ trunk/LayoutTests/media/media-source/media-source-multiple-initialization-segments-expected.txt	2015-02-06 22:14:20 UTC (rev 179762)
@@ -9,6 +9,8 @@
 EVENT(updateend)
 Test that a replacement initialization segment containing a track with a different codec but the same trackID fails.
 RUN(sourceBuffer.appendBuffer(initSegment))
+EVENT(error)
+EVENT(updateend)
 EVENT(sourceended)
 END OF TEST
 

Modified: trunk/LayoutTests/media/media-source/media-source-multiple-initialization-segments.html (179761 => 179762)


--- trunk/LayoutTests/media/media-source/media-source-multiple-initialization-segments.html	2015-02-06 22:08:05 UTC (rev 179761)
+++ trunk/LayoutTests/media/media-source/media-source-multiple-initialization-segments.html	2015-02-06 22:14:20 UTC (rev 179762)
@@ -48,7 +48,8 @@
 
     function secondUpdate() {
         consoleWrite('Test that a replacement initialization segment containing a track with a different codec but the same trackID fails.')
-        waitForEventOn(sourceBuffer, 'updateend', endTest, false, true);
+        waitForEventOn(sourceBuffer, 'error');
+        waitForEventOn(sourceBuffer, 'updateend');
         expected = true;
         initSegment = makeAInit(100, [
             makeATrack(2, '!moc', TRACK_KIND.VIDEO),

Modified: trunk/Source/WebCore/ChangeLog (179761 => 179762)


--- trunk/Source/WebCore/ChangeLog	2015-02-06 22:08:05 UTC (rev 179761)
+++ trunk/Source/WebCore/ChangeLog	2015-02-06 22:14:20 UTC (rev 179762)
@@ -1,3 +1,27 @@
+2015-02-06  Bartlomiej Gajda  <[email protected]>
+
+        [MSE] Implement Append Error algorithm.
+        https://bugs.webkit.org/show_bug.cgi?id=139439
+
+        Reviewed by Jer Noble.
+
+        If Source Buffer has not received first init segment, then it shall call endOfStream after receiving
+        Media Segment, as per Media Source spec. (from 17 July 2014) in paragraph 3.5.1 point 6.1.
+
+        Based this change on Editor's Draft 12 December 2014, as it clarifies order of events.
+
+        Test: media/media-source/media-source-append-media-segment-without-init.html
+
+        * Modules/mediasource/MediaSource.cpp:
+        (WebCore::MediaSource::streamEndedWithError):
+        * Modules/mediasource/MediaSource.h:
+        * Modules/mediasource/SourceBuffer.cpp:
+        (WebCore::SourceBuffer::sourceBufferPrivateAppendComplete):
+        (WebCore::SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment):
+        (WebCore::SourceBuffer::validateInitializationSegment):
+        (WebCore::SourceBuffer::appendError):
+        * Modules/mediasource/SourceBuffer.h:
+
 2015-02-06  Timothy Horton  <[email protected]>
 
         REGRESSION: Lookup doesn't work in RTL

Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp (179761 => 179762)


--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp	2015-02-06 22:08:05 UTC (rev 179761)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp	2015-02-06 22:14:20 UTC (rev 179762)
@@ -616,10 +616,10 @@
     // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-buffer-append
 
     // 2. If the input buffer contains bytes that violate the SourceBuffer byte stream format specification,
-    // then run the end of stream algorithm with the error parameter set to "decode" and abort this algorithm.
+    // then run the append error algorithm with the decode error parameter set to true and abort this algorithm.
     if (result == ParsingFailed) {
         LOG(MediaSource, "SourceBuffer::sourceBufferPrivateAppendComplete(%p) - result = ParsingFailed", this);
-        m_source->streamEndedWithError(decodeError(), IgnorableExceptionCode());
+        appendError(true);
         return;
     }
 
@@ -997,8 +997,9 @@
 
     LOG(MediaSource, "SourceBuffer::sourceBufferPrivateDidReceiveInitializationSegment(%p)", this);
 
-    // 3.5.7 Initialization Segment Received
-    // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-init-segment-received
+    // 3.5.8 Initialization Segment Received (ctd)
+    // https://rawgit.com/w3c/media-source/c3ad59c7a370d04430969ba73d18dc9bcde57a33/index.html#sourcebuffer-init-segment-received [Editor's Draft 09 January 2015]
+
     // 1. Update the duration attribute if it currently equals NaN:
     if (m_source->duration().isInvalid()) {
         // ↳ If the initialization segment contains a duration:
@@ -1009,16 +1010,18 @@
         m_source->setDurationInternal(newDuration);
     }
 
-    // 2. If the initialization segment has no audio, video, or text tracks, then run the end of stream
-    // algorithm with the error parameter set to "decode" and abort these steps.
+    // 2. If the initialization segment has no audio, video, or text tracks, then run the append error algorithm
+    // with the decode error parameter set to true and abort these steps.
     if (!segment.audioTracks.size() && !segment.videoTracks.size() && !segment.textTracks.size())
-        m_source->streamEndedWithError(decodeError(), IgnorableExceptionCode());
+        appendError(true);
 
-
     // 3. If the first initialization segment flag is true, then run the following steps:
     if (m_receivedFirstInitializationSegment) {
+
+        // 3.1. Verify the following properties. If any of the checks fail then run the append error algorithm
+        // with the decode error parameter set to true and abort these steps.
         if (!validateInitializationSegment(segment)) {
-            m_source->streamEndedWithError(decodeError(), IgnorableExceptionCode());
+            appendError(true);
             return;
         }
         // 3.2 Add the appropriate track descriptions from this initialization segment to each of the track buffers.
@@ -1058,6 +1061,7 @@
             downcast<InbandTextTrack>(*textTrack).setPrivate(textTrackInfo.track);
         }
 
+        // 3.3 Set the need random access point flag on all track buffers to true.
         for (auto& trackBuffer : m_trackBufferMap.values())
             trackBuffer.needRandomAccessFlag = true;
     }
@@ -1068,13 +1072,14 @@
     // 5. If the first initialization segment flag is false, then run the following steps:
     if (!m_receivedFirstInitializationSegment) {
         // 5.1 If the initialization segment contains tracks with codecs the user agent does not support,
-        // then run the end of stream algorithm with the error parameter set to "decode" and abort these steps.
+        // then run the append error algorithm with the decode error parameter set to true and abort these steps.
         // NOTE: This check is the responsibility of the SourceBufferPrivate.
 
         // 5.2 For each audio track in the initialization segment, run following steps:
         for (auto& audioTrackInfo : segment.audioTracks) {
             AudioTrackPrivate* audioTrackPrivate = audioTrackInfo.track.get();
 
+            // FIXME: Implement steps 5.2.1-5.2.8.1 as per Editor's Draft 09 January 2015, and reorder this
             // 5.2.1 Let new audio track be a new AudioTrack object.
             // 5.2.2 Generate a unique ID and assign it to the id property on new video track.
             RefPtr<AudioTrack> newAudioTrack = AudioTrack::create(this, audioTrackPrivate);
@@ -1115,6 +1120,7 @@
         for (auto& videoTrackInfo : segment.videoTracks) {
             VideoTrackPrivate* videoTrackPrivate = videoTrackInfo.track.get();
 
+            // FIXME: Implement steps 5.3.1-5.3.8.1 as per Editor's Draft 09 January 2015, and reorder this
             // 5.3.1 Let new video track be a new VideoTrack object.
             // 5.3.2 Generate a unique ID and assign it to the id property on new video track.
             RefPtr<VideoTrack> newVideoTrack = VideoTrack::create(this, videoTrackPrivate);
@@ -1155,6 +1161,7 @@
         for (auto& textTrackInfo : segment.textTracks) {
             InbandTextTrackPrivate* textTrackPrivate = textTrackInfo.track.get();
 
+            // FIXME: Implement steps 5.4.1-5.4.8.1 as per Editor's Draft 09 January 2015, and reorder this
             // 5.4.1 Let new text track be a new TextTrack object with its properties populated with the
             // appropriate information from the initialization segment.
             RefPtr<InbandTextTrack> newTextTrack = InbandTextTrack::create(scriptExecutionContext(), this, textTrackPrivate);
@@ -1189,6 +1196,7 @@
         // 5.5 If active track flag equals true, then run the following steps:
         if (activeTrackFlag) {
             // 5.5.1 Add this SourceBuffer to activeSourceBuffers.
+            // 5.5.2 Queue a task to fire a simple event named addsourcebuffer at activeSourceBuffers
             setActive(true);
         }
 
@@ -1218,11 +1226,11 @@
 
 bool SourceBuffer::validateInitializationSegment(const InitializationSegment& segment)
 {
-    // 3.5.7 Initialization Segment Received (ctd)
-    // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-init-segment-received
+    // FIXME: ordering of all 3.5.X (X>=7) functions needs to be updated to post-[24 July 2014 Editor's Draft] version
+    // 3.5.8 Initialization Segment Received (ctd)
+    // https://rawgit.com/w3c/media-source/c3ad59c7a370d04430969ba73d18dc9bcde57a33/index.html#sourcebuffer-init-segment-received [Editor's Draft 09 January 2015]
 
-    // 3.1. Verify the following properties. If any of the checks fail then run the end of stream
-    // algorithm with the error parameter set to "decode" and abort these steps.
+    // Note: those are checks from step 3.1
     //   * The number of audio, video, and text tracks match what was in the first initialization segment.
     if (segment.audioTracks.size() != audioTracks()->length()
         || segment.videoTracks.size() != videoTracks()->length()
@@ -1289,11 +1297,45 @@
     }
 };
 
+void SourceBuffer::appendError(bool decodeErrorParam)
+{
+    // 3.5.3 Append Error Algorithm
+    // https://rawgit.com/w3c/media-source/c3ad59c7a370d04430969ba73d18dc9bcde57a33/index.html#sourcebuffer-append-error [Editor's Draft 09 January 2015]
+
+    ASSERT(m_updating);
+    // 1. Run the reset parser state algorithm.
+    resetParserState();
+
+    // 2. Set the updating attribute to false.
+    m_updating = false;
+
+    // 3. Queue a task to fire a simple event named error at this SourceBuffer object.
+    scheduleEvent(eventNames().errorEvent);
+
+    // 4. Queue a task to fire a simple event named updateend at this SourceBuffer object.
+    scheduleEvent(eventNames().updateendEvent);
+
+    // 5. If decode error is true, then run the end of stream algorithm with the error parameter set to "decode".
+    if (decodeErrorParam)
+        m_source->streamEndedWithError(decodeError(), IgnorableExceptionCode());
+}
+
 void SourceBuffer::sourceBufferPrivateDidReceiveSample(SourceBufferPrivate*, PassRefPtr<MediaSample> prpSample)
 {
     if (isRemoved())
         return;
 
+    // 3.5.1 Segment Parser Loop
+    // 6.1 If the first initialization segment received flag is false, then run the append error algorithm
+    //     with the decode error parameter set to true and abort this algorithm.
+    // Note: current design makes SourceBuffer somehow ignorant of append state - it's more a thing
+    //  of SourceBufferPrivate. That's why this check can't really be done in appendInternal.
+    //  unless we force some kind of design with state machine switching.
+    if (!m_receivedFirstInitializationSegment) {
+        appendError(true);
+        return;
+    }
+
     RefPtr<MediaSample> sample = prpSample;
 
     // 3.5.8 Coded Frame Processing

Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h (179761 => 179762)


--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h	2015-02-06 22:08:05 UTC (rev 179761)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h	2015-02-06 22:14:20 UTC (rev 179762)
@@ -92,6 +92,7 @@
     void remove(double start, double end, ExceptionCode&);
     void remove(const MediaTime&, const MediaTime&, ExceptionCode&);
 
+    void appendError(bool);
     void abortIfUpdating();
     void removedFromMediaSource();
     void seekToTime(const MediaTime&);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to