<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[206518] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/206518">206518</a></dd>
<dt>Author</dt> <dd>jer.noble@apple.com</dd>
<dt>Date</dt> <dd>2016-09-28 07:52:48 -0700 (Wed, 28 Sep 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[MSE][Mac] In SourceBufferPrivateAVFObjC::abort(), support reseting parser to the last appended initialization segment.
https://bugs.webkit.org/show_bug.cgi?id=135164

Reviewed by Eric Carlson.

Source/WebCore:

Test: media/media-source/media-source-abort-resets-parser.html

Use the -[AVStreamDataParser appendStreamData:withFlags:] to implement &quot;resetting&quot; the parser. In this case,
the parser isn't explicitly reset during resetParserState(), but rather a flag is set so that the next append
signals a data discontinuity, and the parser is reset at that point.

Because a previous append operation may be in-flight during this abort(), care must be taken to invalidate any
operations which may have already started on a background thread. So SourceBufferPrivateAVFObjC will use a
separate WeakPtrFactory for its append operations, will invalidate any outstanding WeakPtrs during an abort(),
and will block until the previous append() operation completes.

This will require the WebAVStreamDataParserListener object to occasionally have it's WeakPtr pointing back to the
SourceBufferPrivateAVFObjC to be reset after an abort(), so make that ivar an @property. Rather than passing a
RetainPtr to itself in all the callbacks it handles, the WebAVStreamDataParserListener can just pass in a copy
of its own WeakPtr (which may be invalidated during an abort()).

Break the distinct operations of &quot;abort()&quot; and &quot;resetParserState()&quot; into their own methods in SourceBufferPrivate
and all its subclasses.

* Modules/mediasource/SourceBuffer.cpp:
(WebCore::SourceBuffer::resetParserState):
(WebCore::SourceBuffer::abortIfUpdating):
* platform/graphics/SourceBufferPrivate.h:
* platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h:
* platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
(-[WebAVStreamDataParserListener streamDataParser:didParseStreamDataAsAsset:]):
(-[WebAVStreamDataParserListener streamDataParser:didParseStreamDataAsAsset:withDiscontinuity:]):
(-[WebAVStreamDataParserListener streamDataParser:didFailToParseStreamDataWithError:]):
(-[WebAVStreamDataParserListener streamDataParser:didProvideMediaData:forTrackID:mediaType:flags:]):
(-[WebAVStreamDataParserListener streamDataParser:didReachEndOfTrackWithTrackID:mediaType:]):
(-[WebAVStreamDataParserListener streamDataParserWillProvideContentKeyRequestInitializationData:forTrackID:]):
(-[WebAVStreamDataParserListener streamDataParser:didProvideContentKeyRequestInitializationData:forTrackID:]):
(WebCore::SourceBufferPrivateAVFObjC::SourceBufferPrivateAVFObjC):
(WebCore::SourceBufferPrivateAVFObjC::append):
(WebCore::SourceBufferPrivateAVFObjC::abort):
(WebCore::SourceBufferPrivateAVFObjC::resetParserState):
(-[WebAVStreamDataParserListener initWithParser:parent:]): Deleted.
* platform/graphics/gstreamer/SourceBufferPrivateGStreamer.cpp:
(WebCore::SourceBufferPrivateGStreamer::resetParserState):
* platform/graphics/gstreamer/SourceBufferPrivateGStreamer.h:
* platform/mock/mediasource/MockSourceBufferPrivate.cpp:
(WebCore::MockSourceBufferPrivate::resetParserState):
* platform/mock/mediasource/MockSourceBufferPrivate.h:
* platform/spi/mac/AVFoundationSPI.h:

LayoutTests:

* media/media-source/media-source-abort-resets-parser-expected.txt: Added.
* media/media-source/media-source-abort-resets-parser.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesmediasourceSourceBuffercpp">trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsSourceBufferPrivateh">trunk/Source/WebCore/platform/graphics/SourceBufferPrivate.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCh">trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCmm">trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsgstreamerSourceBufferPrivateGStreamercpp">trunk/Source/WebCore/platform/graphics/gstreamer/SourceBufferPrivateGStreamer.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsgstreamerSourceBufferPrivateGStreamerh">trunk/Source/WebCore/platform/graphics/gstreamer/SourceBufferPrivateGStreamer.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmockmediasourceMockSourceBufferPrivatecpp">trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformmockmediasourceMockSourceBufferPrivateh">trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.h</a></li>
<li><a href="#trunkSourceWebCoreplatformspimacAVFoundationSPIh">trunk/Source/WebCore/platform/spi/mac/AVFoundationSPI.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsmediamediasourcemediasourceabortresetsparserexpectedtxt">trunk/LayoutTests/media/media-source/media-source-abort-resets-parser-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediamediasourcemediasourceabortresetsparserhtml">trunk/LayoutTests/media/media-source/media-source-abort-resets-parser.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (206517 => 206518)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-09-28 14:49:14 UTC (rev 206517)
+++ trunk/LayoutTests/ChangeLog        2016-09-28 14:52:48 UTC (rev 206518)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2016-09-28  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        [MSE][Mac] In SourceBufferPrivateAVFObjC::abort(), support reseting parser to the last appended initialization segment.
+        https://bugs.webkit.org/show_bug.cgi?id=135164
+
+        Reviewed by Eric Carlson.
+
+        * media/media-source/media-source-abort-resets-parser-expected.txt: Added.
+        * media/media-source/media-source-abort-resets-parser.html: Added.
+
</ins><span class="cx"> 2016-09-28  Alejandro G. Castro  &lt;alex@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Add WebIDL special operation support: serializer
</span></span></pre></div>
<a id="trunkLayoutTestsmediamediasourcemediasourceabortresetsparserexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/media-source/media-source-abort-resets-parser-expected.txt (0 => 206518)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/media-source/media-source-abort-resets-parser-expected.txt                                (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-abort-resets-parser-expected.txt        2016-09-28 14:52:48 UTC (rev 206518)
</span><span class="lines">@@ -0,0 +1,24 @@
</span><ins>+This tests the ability of the SourceBuffer to reset the parser after an abort(). A SourceBuffer in this state should be able to accept a new initialization segment or a new media segment.
+
+RUN(video.src = URL.createObjectURL(source))
+EVENT(sourceopen)
+RUN(source.duration = loader.duration())
+RUN(sourceBuffer = source.addSourceBuffer(loader.type()))
+RUN(sourceBuffer.appendBuffer(loader.initSegment()))
+EVENT(update)
+Append a partial media segment.
+RUN(sourceBuffer.appendBuffer(loader.mediaSegment(0).slice(0, loader.mediaSegment(0).byteLength / 2)))
+EVENT(update)
+Abort and append a new initialization segment.
+RUN(sourceBuffer.abort())
+RUN(sourceBuffer.appendBuffer(loader.initSegment()))
+EVENT(update)
+Append a partial media segment.
+RUN(sourceBuffer.appendBuffer(loader.mediaSegment(0).slice(0, loader.mediaSegment(0).byteLength / 2)))
+EVENT(update)
+Abort and append a new media segment.
+RUN(sourceBuffer.abort())
+RUN(sourceBuffer.appendBuffer(loader.mediaSegment(1)))
+EVENT(update)
+END OF TEST
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediamediasourcemediasourceabortresetsparserhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/media-source/media-source-abort-resets-parser.html (0 => 206518)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/media-source/media-source-abort-resets-parser.html                                (rev 0)
+++ trunk/LayoutTests/media/media-source/media-source-abort-resets-parser.html        2016-09-28 14:52:48 UTC (rev 206518)
</span><span class="lines">@@ -0,0 +1,72 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+    &lt;title&gt;media-source-abort-resets-parser&lt;/title&gt;
+    &lt;script src=&quot;media-source-loader.js&quot;&gt;&lt;/script&gt;
+    &lt;script src=&quot;../video-test.js&quot;&gt;&lt;/script&gt;
+    &lt;script&gt;
+    var loader;
+    var source;
+    var sourceBuffer;
+
+    function runTest() {
+        findMediaElement();
+
+        loader = new MediaSourceLoader('content/test-fragmented-manifest.json');
+        loader.onload = mediaDataLoaded;
+        loader.onerror = mediaDataLoadingFailed;
+    }
+
+    function mediaDataLoadingFailed() {
+        failTest('Media data loading failed');
+    }
+
+    function mediaDataLoaded() {
+        source = new MediaSource();
+        waitForEvent('sourceopen', sourceOpen, false, false, source);
+        waitForEventAndFail('error');
+        run('video.src = URL.createObjectURL(source)');
+    }
+
+    function sourceOpen() {
+        run('source.duration = loader.duration()');
+        run('sourceBuffer = source.addSourceBuffer(loader.type())');
+        waitForEventOn(sourceBuffer, 'update', sourceInitialized, false, true);
+        run('sourceBuffer.appendBuffer(loader.initSegment())');
+    }
+
+    function sourceInitialized() {
+        waitForEventOn(sourceBuffer, 'update', partialMediaSegmentAppended1, false, true);
+        consoleWrite('Append a partial media segment.')
+        run('sourceBuffer.appendBuffer(loader.mediaSegment(0).slice(0, loader.mediaSegment(0).byteLength / 2))');
+    }
+
+    function partialMediaSegmentAppended1() {
+        consoleWrite('Abort and append a new initialization segment.')
+        run('sourceBuffer.abort()');
+        run('sourceBuffer.appendBuffer(loader.initSegment())');
+        waitForEventOn(sourceBuffer, 'update', initSegmentAppended, false, true);
+    }
+
+    function initSegmentAppended() {
+        waitForEventOn(sourceBuffer, 'update', partialMediaSegmentAppended2, false, true);
+        consoleWrite('Append a partial media segment.')
+        run('sourceBuffer.appendBuffer(loader.mediaSegment(0).slice(0, loader.mediaSegment(0).byteLength / 2))');
+    }
+
+    function partialMediaSegmentAppended2() {
+        consoleWrite('Abort and append a new media segment.')
+        run('sourceBuffer.abort()');
+        run('sourceBuffer.appendBuffer(loader.mediaSegment(1))');
+        waitForEventOn(sourceBuffer, 'update', endTest, false, true);
+    }
+    &lt;/script&gt;
+&lt;/head&gt;
+&lt;body onload=&quot;runTest()&quot;&gt;
+    &lt;div&gt;
+        This tests the ability of the SourceBuffer to reset the parser after an abort(). A SourceBuffer in this state should be able to accept
+        a new initialization segment or a new media segment.
+    &lt;/div&gt;
+    &lt;video controls&gt;&lt;/video&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (206517 => 206518)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-09-28 14:49:14 UTC (rev 206517)
+++ trunk/Source/WebCore/ChangeLog        2016-09-28 14:52:48 UTC (rev 206518)
</span><span class="lines">@@ -1,3 +1,55 @@
</span><ins>+2016-09-28  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        [MSE][Mac] In SourceBufferPrivateAVFObjC::abort(), support reseting parser to the last appended initialization segment.
+        https://bugs.webkit.org/show_bug.cgi?id=135164
+
+        Reviewed by Eric Carlson.
+
+        Test: media/media-source/media-source-abort-resets-parser.html
+
+        Use the -[AVStreamDataParser appendStreamData:withFlags:] to implement &quot;resetting&quot; the parser. In this case,
+        the parser isn't explicitly reset during resetParserState(), but rather a flag is set so that the next append
+        signals a data discontinuity, and the parser is reset at that point.
+
+        Because a previous append operation may be in-flight during this abort(), care must be taken to invalidate any
+        operations which may have already started on a background thread. So SourceBufferPrivateAVFObjC will use a
+        separate WeakPtrFactory for its append operations, will invalidate any outstanding WeakPtrs during an abort(),
+        and will block until the previous append() operation completes.
+
+        This will require the WebAVStreamDataParserListener object to occasionally have it's WeakPtr pointing back to the
+        SourceBufferPrivateAVFObjC to be reset after an abort(), so make that ivar an @property. Rather than passing a
+        RetainPtr to itself in all the callbacks it handles, the WebAVStreamDataParserListener can just pass in a copy
+        of its own WeakPtr (which may be invalidated during an abort()).
+
+        Break the distinct operations of &quot;abort()&quot; and &quot;resetParserState()&quot; into their own methods in SourceBufferPrivate
+        and all its subclasses.
+
+        * Modules/mediasource/SourceBuffer.cpp:
+        (WebCore::SourceBuffer::resetParserState):
+        (WebCore::SourceBuffer::abortIfUpdating):
+        * platform/graphics/SourceBufferPrivate.h:
+        * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h:
+        * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
+        (-[WebAVStreamDataParserListener streamDataParser:didParseStreamDataAsAsset:]):
+        (-[WebAVStreamDataParserListener streamDataParser:didParseStreamDataAsAsset:withDiscontinuity:]):
+        (-[WebAVStreamDataParserListener streamDataParser:didFailToParseStreamDataWithError:]):
+        (-[WebAVStreamDataParserListener streamDataParser:didProvideMediaData:forTrackID:mediaType:flags:]):
+        (-[WebAVStreamDataParserListener streamDataParser:didReachEndOfTrackWithTrackID:mediaType:]):
+        (-[WebAVStreamDataParserListener streamDataParserWillProvideContentKeyRequestInitializationData:forTrackID:]):
+        (-[WebAVStreamDataParserListener streamDataParser:didProvideContentKeyRequestInitializationData:forTrackID:]):
+        (WebCore::SourceBufferPrivateAVFObjC::SourceBufferPrivateAVFObjC):
+        (WebCore::SourceBufferPrivateAVFObjC::append):
+        (WebCore::SourceBufferPrivateAVFObjC::abort):
+        (WebCore::SourceBufferPrivateAVFObjC::resetParserState):
+        (-[WebAVStreamDataParserListener initWithParser:parent:]): Deleted.
+        * platform/graphics/gstreamer/SourceBufferPrivateGStreamer.cpp:
+        (WebCore::SourceBufferPrivateGStreamer::resetParserState):
+        * platform/graphics/gstreamer/SourceBufferPrivateGStreamer.h:
+        * platform/mock/mediasource/MockSourceBufferPrivate.cpp:
+        (WebCore::MockSourceBufferPrivate::resetParserState):
+        * platform/mock/mediasource/MockSourceBufferPrivate.h:
+        * platform/spi/mac/AVFoundationSPI.h:
+
</ins><span class="cx"> 2016-09-28  Michael Catanzaro  &lt;mcatanzaro@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK] User agent should always claim to be Intel
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSourceBuffercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp (206517 => 206518)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2016-09-28 14:49:14 UTC (rev 206517)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2016-09-28 14:52:48 UTC (rev 206518)
</span><span class="lines">@@ -278,7 +278,7 @@
</span><span class="cx">     // 7. Set append state to WAITING_FOR_SEGMENT.
</span><span class="cx">     m_appendState = WaitingForSegment;
</span><span class="cx"> 
</span><del>-    m_private-&gt;abort();
</del><ins>+    m_private-&gt;resetParserState();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SourceBuffer::abort(ExceptionCode&amp; ec)
</span><span class="lines">@@ -383,6 +383,7 @@
</span><span class="cx">     // 4.1. Abort the buffer append algorithm if it is running.
</span><span class="cx">     m_appendBufferTimer.stop();
</span><span class="cx">     m_pendingAppendData.clear();
</span><ins>+    m_private-&gt;abort();
</ins><span class="cx"> 
</span><span class="cx">     // 4.2. Set the updating attribute to false.
</span><span class="cx">     m_updating = false;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsSourceBufferPrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/SourceBufferPrivate.h (206517 => 206518)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/SourceBufferPrivate.h        2016-09-28 14:49:14 UTC (rev 206517)
+++ trunk/Source/WebCore/platform/graphics/SourceBufferPrivate.h        2016-09-28 14:52:48 UTC (rev 206518)
</span><span class="lines">@@ -52,6 +52,7 @@
</span><span class="cx"> 
</span><span class="cx">     virtual void append(const unsigned char* data, unsigned length) = 0;
</span><span class="cx">     virtual void abort() = 0;
</span><ins>+    virtual void resetParserState() = 0;
</ins><span class="cx">     virtual void removedFromMediaSource() = 0;
</span><span class="cx"> 
</span><span class="cx">     virtual MediaPlayer::ReadyState readyState() const = 0;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h (206517 => 206518)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h        2016-09-28 14:49:14 UTC (rev 206517)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h        2016-09-28 14:52:48 UTC (rev 206518)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #if ENABLE(MEDIA_SOURCE) &amp;&amp; USE(AVFOUNDATION)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;SourceBufferPrivate.h&quot;
</span><ins>+#include &lt;dispatch/group.h&gt;
</ins><span class="cx"> #include &lt;dispatch/semaphore.h&gt;
</span><span class="cx"> #include &lt;wtf/Deque.h&gt;
</span><span class="cx"> #include &lt;wtf/HashMap.h&gt;
</span><span class="lines">@@ -115,6 +116,7 @@
</span><span class="cx">     void setClient(SourceBufferPrivateClient*) override;
</span><span class="cx">     void append(const unsigned char* data, unsigned length) override;
</span><span class="cx">     void abort() override;
</span><ins>+    void resetParserState() override;
</ins><span class="cx">     void removedFromMediaSource() override;
</span><span class="cx">     MediaPlayer::ReadyState readyState() const override;
</span><span class="cx">     void setReadyState(MediaPlayer::ReadyState) override;
</span><span class="lines">@@ -139,6 +141,7 @@
</span><span class="cx">     Vector&lt;SourceBufferPrivateAVFObjCErrorClient*&gt; m_errorClients;
</span><span class="cx"> 
</span><span class="cx">     WeakPtrFactory&lt;SourceBufferPrivateAVFObjC&gt; m_weakFactory;
</span><ins>+    WeakPtrFactory&lt;SourceBufferPrivateAVFObjC&gt; m_appendWeakFactory;
</ins><span class="cx"> 
</span><span class="cx">     RetainPtr&lt;AVStreamDataParser&gt; m_parser;
</span><span class="cx">     RetainPtr&lt;AVAsset&gt; m_asset;
</span><span class="lines">@@ -148,6 +151,7 @@
</span><span class="cx">     RetainPtr&lt;WebAVSampleBufferErrorListener&gt; m_errorListener;
</span><span class="cx">     RetainPtr&lt;NSError&gt; m_hdcpError;
</span><span class="cx">     OSObjectPtr&lt;dispatch_semaphore_t&gt; m_hasSessionSemaphore;
</span><ins>+    OSObjectPtr&lt;dispatch_group_t&gt; m_isAppendingGroup;
</ins><span class="cx"> 
</span><span class="cx">     MediaSourcePrivateAVFObjC* m_mediaSource;
</span><span class="cx">     SourceBufferPrivateClient* m_client;
</span><span class="lines">@@ -156,6 +160,7 @@
</span><span class="cx">     FloatSize m_cachedSize;
</span><span class="cx">     FloatSize m_currentSize;
</span><span class="cx">     bool m_parsingSucceeded;
</span><ins>+    bool m_parserStateWasReset { false };
</ins><span class="cx">     int m_enabledVideoTrackID;
</span><span class="cx">     int m_protectedTrackID;
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm (206517 => 206518)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm        2016-09-28 14:49:14 UTC (rev 206517)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm        2016-09-28 14:52:48 UTC (rev 206518)
</span><span class="lines">@@ -131,6 +131,7 @@
</span><span class="cx">     WeakPtr&lt;WebCore::SourceBufferPrivateAVFObjC&gt; _parent;
</span><span class="cx">     AVStreamDataParser* _parser;
</span><span class="cx"> }
</span><ins>+@property (assign) WeakPtr&lt;WebCore::SourceBufferPrivateAVFObjC&gt; parent;
</ins><span class="cx"> - (id)initWithParser:(AVStreamDataParser*)parser parent:(WeakPtr&lt;WebCore::SourceBufferPrivateAVFObjC&gt;)parent;
</span><span class="cx"> @end
</span><span class="cx"> 
</span><span class="lines">@@ -148,6 +149,8 @@
</span><span class="cx">     return self;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+@synthesize parent=_parent;
+
</ins><span class="cx"> - (void)dealloc
</span><span class="cx"> {
</span><span class="cx">     [_parser setDelegate:nil];
</span><span class="lines">@@ -166,12 +169,11 @@
</span><span class="cx">     UNUSED_PARAM(streamDataParser);
</span><span class="cx"> #endif
</span><span class="cx">     ASSERT(streamDataParser == _parser);
</span><del>-    RetainPtr&lt;WebAVStreamDataParserListener&gt; protectedSelf = self;
</del><span class="cx"> 
</span><span class="cx">     RetainPtr&lt;AVAsset*&gt; protectedAsset = asset;
</span><del>-    callOnMainThread([protectedSelf = WTFMove(protectedSelf), protectedAsset = WTFMove(protectedAsset)] {
-        if (protectedSelf-&gt;_parent)
-            protectedSelf-&gt;_parent-&gt;didParseStreamDataAsAsset(protectedAsset.get());
</del><ins>+    callOnMainThread([parent = _parent, protectedAsset = WTFMove(protectedAsset)] {
+        if (parent)
+            parent-&gt;didParseStreamDataAsAsset(protectedAsset.get());
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -182,12 +184,11 @@
</span><span class="cx">     UNUSED_PARAM(streamDataParser);
</span><span class="cx"> #endif
</span><span class="cx">     ASSERT(streamDataParser == _parser);
</span><del>-    RetainPtr&lt;WebAVStreamDataParserListener&gt; protectedSelf = self;
</del><span class="cx"> 
</span><span class="cx">     RetainPtr&lt;AVAsset*&gt; protectedAsset = asset;
</span><del>-    callOnMainThread([protectedSelf = WTFMove(protectedSelf), protectedAsset = WTFMove(protectedAsset)] {
-        if (protectedSelf-&gt;_parent)
-            protectedSelf-&gt;_parent-&gt;didParseStreamDataAsAsset(protectedAsset.get());
</del><ins>+    callOnMainThread([parent = _parent, protectedAsset = WTFMove(protectedAsset)] {
+        if (parent)
+            parent-&gt;didParseStreamDataAsAsset(protectedAsset.get());
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -197,12 +198,11 @@
</span><span class="cx">     UNUSED_PARAM(streamDataParser);
</span><span class="cx"> #endif
</span><span class="cx">     ASSERT(streamDataParser == _parser);
</span><del>-    RetainPtr&lt;WebAVStreamDataParserListener&gt; protectedSelf = self;
</del><span class="cx"> 
</span><span class="cx">     RetainPtr&lt;NSError&gt; protectedError = error;
</span><del>-    callOnMainThread([protectedSelf = WTFMove(protectedSelf), protectedError = WTFMove(protectedError)] {
-        if (protectedSelf-&gt;_parent)
-            protectedSelf-&gt;_parent-&gt;didFailToParseStreamDataWithError(protectedError.get());
</del><ins>+    callOnMainThread([parent = _parent, protectedError = WTFMove(protectedError)] {
+        if (parent)
+            parent-&gt;didFailToParseStreamDataWithError(protectedError.get());
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -212,13 +212,12 @@
</span><span class="cx">     UNUSED_PARAM(streamDataParser);
</span><span class="cx"> #endif
</span><span class="cx">     ASSERT(streamDataParser == _parser);
</span><del>-    RetainPtr&lt;WebAVStreamDataParserListener&gt; protectedSelf = self;
</del><span class="cx"> 
</span><span class="cx">     RetainPtr&lt;CMSampleBufferRef&gt; protectedSample = sample;
</span><span class="cx">     String mediaType = nsMediaType;
</span><del>-    callOnMainThread([protectedSelf = WTFMove(protectedSelf), protectedSample = WTFMove(protectedSample), trackID, mediaType, flags] {
-        if (protectedSelf-&gt;_parent)
-            protectedSelf-&gt;_parent-&gt;didProvideMediaDataForTrackID(trackID, protectedSample.get(), mediaType, flags);
</del><ins>+    callOnMainThread([parent = _parent, protectedSample = WTFMove(protectedSample), trackID, mediaType, flags] {
+        if (parent)
+            parent-&gt;didProvideMediaDataForTrackID(trackID, protectedSample.get(), mediaType, flags);
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -228,12 +227,11 @@
</span><span class="cx">     UNUSED_PARAM(streamDataParser);
</span><span class="cx"> #endif
</span><span class="cx">     ASSERT(streamDataParser == _parser);
</span><del>-    RetainPtr&lt;WebAVStreamDataParserListener&gt; protectedSelf = self;
</del><span class="cx"> 
</span><span class="cx">     String mediaType = nsMediaType;
</span><del>-    callOnMainThread([protectedSelf = WTFMove(protectedSelf), trackID, mediaType] {
-        if (protectedSelf-&gt;_parent)
-            protectedSelf-&gt;_parent-&gt;didReachEndOfTrackWithTrackID(trackID, mediaType);
</del><ins>+    callOnMainThread([parent = _parent, trackID, mediaType] {
+        if (parent)
+            parent-&gt;didReachEndOfTrackWithTrackID(trackID, mediaType);
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -246,10 +244,9 @@
</span><span class="cx"> 
</span><span class="cx">     // We must call synchronously to the main thread, as the AVStreamSession must be associated
</span><span class="cx">     // with the streamDataParser before the delegate method returns.
</span><del>-    RetainPtr&lt;WebAVStreamDataParserListener&gt; strongSelf = self;
-    dispatch_sync(dispatch_get_main_queue(), [strongSelf, trackID]() {
-        if (strongSelf-&gt;_parent)
-            strongSelf-&gt;_parent-&gt;willProvideContentKeyRequestInitializationDataForTrackID(trackID);
</del><ins>+    dispatch_sync(dispatch_get_main_queue(), [parent = _parent, trackID]() {
+        if (parent)
+            parent-&gt;willProvideContentKeyRequestInitializationDataForTrackID(trackID);
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -259,12 +256,11 @@
</span><span class="cx">     UNUSED_PARAM(streamDataParser);
</span><span class="cx"> #endif
</span><span class="cx">     ASSERT(streamDataParser == _parser);
</span><del>-    RetainPtr&lt;WebAVStreamDataParserListener&gt; protectedSelf = self;
</del><span class="cx"> 
</span><span class="cx">     OSObjectPtr&lt;dispatch_semaphore_t&gt; hasSessionSemaphore = adoptOSObject(dispatch_semaphore_create(0));
</span><del>-    callOnMainThread([protectedSelf = WTFMove(protectedSelf), protectedInitData = RetainPtr&lt;NSData&gt;(initData), trackID, hasSessionSemaphore] {
-        if (protectedSelf-&gt;_parent)
-            protectedSelf-&gt;_parent-&gt;didProvideContentKeyRequestInitializationDataForTrackID(protectedInitData.get(), trackID, hasSessionSemaphore);
</del><ins>+    callOnMainThread([parent = _parent, protectedInitData = RetainPtr&lt;NSData&gt;(initData), trackID, hasSessionSemaphore] {
+        if (parent)
+            parent-&gt;didProvideContentKeyRequestInitializationDataForTrackID(protectedInitData.get(), trackID, hasSessionSemaphore);
</ins><span class="cx">     });
</span><span class="cx">     dispatch_semaphore_wait(hasSessionSemaphore.get(), DISPATCH_TIME_FOREVER);
</span><span class="cx"> }
</span><span class="lines">@@ -461,9 +457,11 @@
</span><span class="cx"> 
</span><span class="cx"> SourceBufferPrivateAVFObjC::SourceBufferPrivateAVFObjC(MediaSourcePrivateAVFObjC* parent)
</span><span class="cx">     : m_weakFactory(this)
</span><ins>+    , m_appendWeakFactory(this)
</ins><span class="cx">     , m_parser(adoptNS([allocAVStreamDataParserInstance() init]))
</span><span class="cx">     , m_delegate(adoptNS([[WebAVStreamDataParserListener alloc] initWithParser:m_parser.get() parent:createWeakPtr()]))
</span><span class="cx">     , m_errorListener(adoptNS([[WebAVSampleBufferErrorListener alloc] initWithParent:this]))
</span><ins>+    , m_isAppendingGroup(adoptOSObject(dispatch_group_create()))
</ins><span class="cx">     , m_mediaSource(parent)
</span><span class="cx">     , m_client(0)
</span><span class="cx">     , m_parsingSucceeded(true)
</span><span class="lines">@@ -641,21 +639,26 @@
</span><span class="cx">     LOG(MediaSource, &quot;SourceBufferPrivateAVFObjC::append(%p) - data:%p, length:%d&quot;, this, data, length);
</span><span class="cx"> 
</span><span class="cx">     RetainPtr&lt;NSData&gt; nsData = adoptNS([[NSData alloc] initWithBytes:data length:length]);
</span><del>-    WeakPtr&lt;SourceBufferPrivateAVFObjC&gt; weakThis = createWeakPtr();
</del><ins>+    WeakPtr&lt;SourceBufferPrivateAVFObjC&gt; weakThis = m_appendWeakFactory.createWeakPtr();
</ins><span class="cx">     RetainPtr&lt;AVStreamDataParser&gt; parser = m_parser;
</span><span class="cx">     RetainPtr&lt;WebAVStreamDataParserListener&gt; delegate = m_delegate;
</span><span class="cx"> 
</span><span class="cx">     m_parsingSucceeded = true;
</span><ins>+    dispatch_group_enter(m_isAppendingGroup.get());
</ins><span class="cx"> 
</span><del>-    dispatch_async(globalDataParserQueue(), [nsData, weakThis, parser, delegate] {
</del><ins>+    dispatch_async(globalDataParserQueue(), [nsData, weakThis, parser, delegate, isAppendingGroup = m_isAppendingGroup, parserStateWasReset = m_parserStateWasReset] {
+        if (parserStateWasReset)
+            [parser appendStreamData:nsData.get() withFlags:AVStreamDataParserStreamDataDiscontinuity];
+        else
+            [parser appendStreamData:nsData.get()];
</ins><span class="cx"> 
</span><del>-        [parser appendStreamData:nsData.get()];
-
</del><span class="cx">         callOnMainThread([weakThis] {
</span><span class="cx">             if (weakThis)
</span><span class="cx">                 weakThis-&gt;appendCompleted();
</span><span class="cx">         });
</span><ins>+        dispatch_group_leave(isAppendingGroup.get());
</ins><span class="cx">     });
</span><ins>+    m_parserStateWasReset = false;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SourceBufferPrivateAVFObjC::appendCompleted()
</span><span class="lines">@@ -669,12 +672,19 @@
</span><span class="cx"> 
</span><span class="cx"> void SourceBufferPrivateAVFObjC::abort()
</span><span class="cx"> {
</span><del>-    // The parser does not have a mechanism for resetting to a clean state, so destroy and re-create it.
-    // FIXME(135164): Support resetting parser to the last appended initialization segment.
-    destroyParser();
</del><ins>+    // The parsing queue may be blocked waiting for the main thread to provide it a AVStreamSession. We
+    // were asked to abort, and that cancels all outstanding append operations. Without cancelling this
+    // semaphore, the m_isAppendingGroup wait operation will deadlock.
+    if (m_hasSessionSemaphore)
+        dispatch_semaphore_signal(m_hasSessionSemaphore.get());
+    dispatch_group_wait(m_isAppendingGroup.get(), DISPATCH_TIME_FOREVER);
+    m_appendWeakFactory.revokeAll();
+    m_delegate.get().parent = m_appendWeakFactory.createWeakPtr();
+}
</ins><span class="cx"> 
</span><del>-    m_parser = adoptNS([allocAVStreamDataParserInstance() init]);
-    m_delegate = adoptNS([[WebAVStreamDataParserListener alloc] initWithParser:m_parser.get() parent:createWeakPtr()]);
</del><ins>+void SourceBufferPrivateAVFObjC::resetParserState()
+{
+    m_parserStateWasReset = true;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SourceBufferPrivateAVFObjC::destroyParser()
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsgstreamerSourceBufferPrivateGStreamercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/gstreamer/SourceBufferPrivateGStreamer.cpp (206517 => 206518)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/gstreamer/SourceBufferPrivateGStreamer.cpp        2016-09-28 14:49:14 UTC (rev 206517)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/SourceBufferPrivateGStreamer.cpp        2016-09-28 14:52:48 UTC (rev 206518)
</span><span class="lines">@@ -75,6 +75,11 @@
</span><span class="cx">     notImplemented();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SourceBufferPrivateGStreamer::resetParserState()
+{
+    notImplemented();
+}
+
</ins><span class="cx"> void SourceBufferPrivateGStreamer::removedFromMediaSource()
</span><span class="cx"> {
</span><span class="cx">     m_client-&gt;removedFromMediaSource(this);
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsgstreamerSourceBufferPrivateGStreamerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/gstreamer/SourceBufferPrivateGStreamer.h (206517 => 206518)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/gstreamer/SourceBufferPrivateGStreamer.h        2016-09-28 14:49:14 UTC (rev 206517)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/SourceBufferPrivateGStreamer.h        2016-09-28 14:52:48 UTC (rev 206518)
</span><span class="lines">@@ -50,6 +50,7 @@
</span><span class="cx"> 
</span><span class="cx">     virtual void append(const unsigned char* data, unsigned length);
</span><span class="cx">     virtual void abort();
</span><ins>+    virtual void resetParserState();
</ins><span class="cx">     virtual void removedFromMediaSource();
</span><span class="cx"> 
</span><span class="cx">     virtual MediaPlayer::ReadyState readyState() const;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmockmediasourceMockSourceBufferPrivatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp (206517 => 206518)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp        2016-09-28 14:49:14 UTC (rev 206517)
+++ trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp        2016-09-28 14:52:48 UTC (rev 206518)
</span><span class="lines">@@ -203,6 +203,10 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void MockSourceBufferPrivate::resetParserState()
+{
+}
+
</ins><span class="cx"> void MockSourceBufferPrivate::removedFromMediaSource()
</span><span class="cx"> {
</span><span class="cx">     if (m_mediaSource)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmockmediasourceMockSourceBufferPrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.h (206517 => 206518)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.h        2016-09-28 14:49:14 UTC (rev 206517)
+++ trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.h        2016-09-28 14:52:48 UTC (rev 206518)
</span><span class="lines">@@ -63,6 +63,7 @@
</span><span class="cx">     void setClient(SourceBufferPrivateClient*) override;
</span><span class="cx">     void append(const unsigned char* data, unsigned length) override;
</span><span class="cx">     void abort() override;
</span><ins>+    void resetParserState() override;
</ins><span class="cx">     void removedFromMediaSource() override;
</span><span class="cx">     MediaPlayer::ReadyState readyState() const override;
</span><span class="cx">     void setReadyState(MediaPlayer::ReadyState) override;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformspimacAVFoundationSPIh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/spi/mac/AVFoundationSPI.h (206517 => 206518)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/spi/mac/AVFoundationSPI.h        2016-09-28 14:49:14 UTC (rev 206517)
+++ trunk/Source/WebCore/platform/spi/mac/AVFoundationSPI.h        2016-09-28 14:52:48 UTC (rev 206518)
</span><span class="lines">@@ -116,9 +116,14 @@
</span><span class="cx">     AVStreamDataParserOutputMediaDataReserved = 1 &lt;&lt; 0
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+typedef NS_ENUM(NSUInteger, AVStreamDataParserStreamDataFlags) {
+    AVStreamDataParserStreamDataDiscontinuity = 1 &lt;&lt; 0,
+};
+
</ins><span class="cx"> @interface AVStreamDataParser : NSObject
</span><span class="cx"> - (void)setDelegate:(nullable id&lt;AVStreamDataParserOutputHandling&gt;)delegate;
</span><span class="cx"> - (void)appendStreamData:(NSData *)data;
</span><ins>+- (void)appendStreamData:(NSData *)data withFlags:(AVStreamDataParserStreamDataFlags)flags;
</ins><span class="cx"> - (void)setShouldProvideMediaData:(BOOL)shouldProvideMediaData forTrackID:(CMPersistentTrackID)trackID;
</span><span class="cx"> - (BOOL)shouldProvideMediaDataForTrackID:(CMPersistentTrackID)trackID;
</span><span class="cx"> - (void)providePendingMediaData;
</span></span></pre>
</div>
</div>

</body>
</html>