<!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>[170976] trunk/Source/WebCore</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/170976">170976</a></dd>
<dt>Author</dt> <dd>jer.noble@apple.com</dd>
<dt>Date</dt> <dd>2014-07-10 14:28:05 -0700 (Thu, 10 Jul 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[MSE] Overlapping appended ranges must cause the decoder to flush and re-enqueue.
https://bugs.webkit.org/show_bug.cgi?id=134805

Reviewed by Eric Carlson.

When appending a range of media data which overlaps with an existing range, SourceBuffer
must cause the decoder to flush and re-enqueue samples. Those samples removed by appending
the overlapping range may have already been enqueued for display, and unless the decode
queue is flushed, corruption or decode errors may occur as the new samples are enqueued for
display.

Add a boolean flag onto TrackBuffer to indicate whether the decoder needs to be flushed and
re-enqueued the next time an append operation completes. Set this flag whenever samples are
removed due to overlapping or an explicit call to removeCodedFrames(). Move the contents of
sourceBufferPrivateSeekToTime() (which previously did flushing and re-enqueueing) into a new
function, reenqueueMediaForTime(), which can be called from sourceBufferPrivateAppendComplete().

Drive-by fix: findSyncSampleAfterDecodeIterator() would return the passed in iterator if that
sample is a sync-sample. Fix this to correctly return the next sync sample.

Drive-by fix: Use a SampleMap, rather than a DecodeOrderSampleMap, to track erased samples
so that the erasedSamples are correctly accounted for in both presentation and decode orders.

* Modules/mediasource/SampleMap.cpp:
(WebCore::SampleMap::empty): Add convenience method.
(WebCore::DecodeOrderSampleMap::findSyncSampleAfterDecodeIterator): Drive-by fix.
* Modules/mediasource/SampleMap.h:
(WebCore::SampleMap::decodeOrder): Added const accessor.
(WebCore::SampleMap::presentationOrder): Ditto.
(WebCore::SampleMap::addRange): Added.
* Modules/mediasource/SourceBuffer.cpp:
(WebCore::SourceBuffer::TrackBuffer::TrackBuffer): Add needsReenqueeing flag.
(WebCore::SourceBuffer::sourceBufferPrivateSeekToTime): Move contents into reenqueueMediaForTime().
(WebCore::SourceBuffer::sourceBufferPrivateAppendComplete): Call reenqueMediaForTime() if necessary.
(WebCore::SourceBuffer::removeCodedFrames): Set needsReenqueing.
(WebCore::SourceBuffer::sourceBufferPrivateDidReceiveSample): Ditto.
(WebCore::SourceBuffer::provideMediaData): Drive-by fix.
(WebCore::SourceBuffer::reenqueueMediaForTime): Moved from sourceBufferPrivateSeekToTime().
* Modules/mediasource/SourceBuffer.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesmediasourceSampleMapcpp">trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesmediasourceSampleMaph">trunk/Source/WebCore/Modules/mediasource/SampleMap.h</a></li>
<li><a href="#trunkSourceWebCoreModulesmediasourceSourceBuffercpp">trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesmediasourceSourceBufferh">trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (170975 => 170976)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-07-10 20:48:44 UTC (rev 170975)
+++ trunk/Source/WebCore/ChangeLog        2014-07-10 21:28:05 UTC (rev 170976)
</span><span class="lines">@@ -1,3 +1,45 @@
</span><ins>+2014-07-10  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        [MSE] Overlapping appended ranges must cause the decoder to flush and re-enqueue.
+        https://bugs.webkit.org/show_bug.cgi?id=134805
+
+        Reviewed by Eric Carlson.
+
+        When appending a range of media data which overlaps with an existing range, SourceBuffer
+        must cause the decoder to flush and re-enqueue samples. Those samples removed by appending
+        the overlapping range may have already been enqueued for display, and unless the decode
+        queue is flushed, corruption or decode errors may occur as the new samples are enqueued for
+        display.
+
+        Add a boolean flag onto TrackBuffer to indicate whether the decoder needs to be flushed and
+        re-enqueued the next time an append operation completes. Set this flag whenever samples are
+        removed due to overlapping or an explicit call to removeCodedFrames(). Move the contents of
+        sourceBufferPrivateSeekToTime() (which previously did flushing and re-enqueueing) into a new
+        function, reenqueueMediaForTime(), which can be called from sourceBufferPrivateAppendComplete().
+
+        Drive-by fix: findSyncSampleAfterDecodeIterator() would return the passed in iterator if that
+        sample is a sync-sample. Fix this to correctly return the next sync sample.
+
+        Drive-by fix: Use a SampleMap, rather than a DecodeOrderSampleMap, to track erased samples
+        so that the erasedSamples are correctly accounted for in both presentation and decode orders.
+
+        * Modules/mediasource/SampleMap.cpp:
+        (WebCore::SampleMap::empty): Add convenience method.
+        (WebCore::DecodeOrderSampleMap::findSyncSampleAfterDecodeIterator): Drive-by fix.
+        * Modules/mediasource/SampleMap.h:
+        (WebCore::SampleMap::decodeOrder): Added const accessor.
+        (WebCore::SampleMap::presentationOrder): Ditto.
+        (WebCore::SampleMap::addRange): Added.
+        * Modules/mediasource/SourceBuffer.cpp:
+        (WebCore::SourceBuffer::TrackBuffer::TrackBuffer): Add needsReenqueeing flag.
+        (WebCore::SourceBuffer::sourceBufferPrivateSeekToTime): Move contents into reenqueueMediaForTime().
+        (WebCore::SourceBuffer::sourceBufferPrivateAppendComplete): Call reenqueMediaForTime() if necessary.
+        (WebCore::SourceBuffer::removeCodedFrames): Set needsReenqueing.
+        (WebCore::SourceBuffer::sourceBufferPrivateDidReceiveSample): Ditto.
+        (WebCore::SourceBuffer::provideMediaData): Drive-by fix.
+        (WebCore::SourceBuffer::reenqueueMediaForTime): Moved from sourceBufferPrivateSeekToTime().
+        * Modules/mediasource/SourceBuffer.h:
+
</ins><span class="cx"> 2014-07-10  Pratik Solanki  &lt;psolanki@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         ASSERT in SharedBuffer::maybeAppendDataArray() on MobileSafari launch
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSampleMapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp (170975 => 170976)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp        2014-07-10 20:48:44 UTC (rev 170975)
+++ trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp        2014-07-10 21:28:05 UTC (rev 170976)
</span><span class="lines">@@ -96,6 +96,11 @@
</span><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+bool SampleMap::empty() const
+{
+    return presentationOrder().m_samples.empty();
+}
+
</ins><span class="cx"> void SampleMap::clear()
</span><span class="cx"> {
</span><span class="cx">     presentationOrder().m_samples.clear();
</span><span class="lines">@@ -209,7 +214,9 @@
</span><span class="cx"> 
</span><span class="cx"> DecodeOrderSampleMap::iterator DecodeOrderSampleMap::findSyncSampleAfterDecodeIterator(iterator currentSampleDTS)
</span><span class="cx"> {
</span><del>-    return std::find_if(currentSampleDTS, end(), SampleIsRandomAccess());
</del><ins>+    if (currentSampleDTS == end())
+        return end();
+    return std::find_if(++currentSampleDTS, end(), SampleIsRandomAccess());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PresentationOrderSampleMap::iterator_range PresentationOrderSampleMap::findSamplesBetweenPresentationTimes(const MediaTime&amp; beginTime, const MediaTime&amp; endTime)
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSampleMaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SampleMap.h (170975 => 170976)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SampleMap.h        2014-07-10 20:48:44 UTC (rev 170975)
+++ trunk/Source/WebCore/Modules/mediasource/SampleMap.h        2014-07-10 21:28:05 UTC (rev 170976)
</span><span class="lines">@@ -95,21 +95,34 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool empty() const;
</ins><span class="cx">     void clear();
</span><span class="cx">     void addSample(PassRefPtr&lt;MediaSample&gt;);
</span><span class="cx">     void removeSample(MediaSample*);
</span><span class="cx">     size_t sizeInBytes() const { return m_totalSize; }
</span><span class="cx"> 
</span><ins>+    template&lt;typename I&gt;
+    void addRange(I begin, I end);
+
</ins><span class="cx">     DecodeOrderSampleMap&amp; decodeOrder() { return m_decodeOrder; }
</span><ins>+    const DecodeOrderSampleMap&amp; decodeOrder() const { return m_decodeOrder; }
</ins><span class="cx">     PresentationOrderSampleMap&amp; presentationOrder() { return m_decodeOrder.m_presentationOrder; }
</span><ins>+    const PresentationOrderSampleMap&amp; presentationOrder() const { return m_decodeOrder.m_presentationOrder; }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     DecodeOrderSampleMap m_decodeOrder;
</span><span class="cx">     size_t m_totalSize;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+template&lt;typename I&gt;
+void SampleMap::addRange(I begin, I end)
+{
+    for (I iter = begin; iter != end; ++iter)
+        addSample(iter-&gt;second);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+}
+
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #endif // SampleMap_h
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSourceBuffercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp (170975 => 170976)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2014-07-10 20:48:44 UTC (rev 170975)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2014-07-10 21:28:05 UTC (rev 170976)
</span><span class="lines">@@ -73,6 +73,7 @@
</span><span class="cx">     MediaTime lastEnqueuedPresentationTime;
</span><span class="cx">     bool needRandomAccessFlag;
</span><span class="cx">     bool enabled;
</span><ins>+    bool needsReenqueueing;
</ins><span class="cx">     SampleMap samples;
</span><span class="cx">     DecodeOrderSampleMap::MapType decodeQueue;
</span><span class="cx">     RefPtr&lt;MediaDescription&gt; description;
</span><span class="lines">@@ -84,6 +85,7 @@
</span><span class="cx">         , lastEnqueuedPresentationTime(MediaTime::invalidTime())
</span><span class="cx">         , needRandomAccessFlag(true)
</span><span class="cx">         , enabled(false)
</span><ins>+        , needsReenqueueing(false)
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> };
</span><span class="lines">@@ -308,46 +310,13 @@
</span><span class="cx"> 
</span><span class="cx"> void SourceBuffer::sourceBufferPrivateSeekToTime(SourceBufferPrivate*, const MediaTime&amp; time)
</span><span class="cx"> {
</span><del>-    LOG(Media, &quot;SourceBuffer::sourceBufferPrivateSeekToTime(%p)&quot;, this);
</del><ins>+    LOG(Media, &quot;SourceBuffer::sourceBufferPrivateSeekToTime(%p) - time(%s)&quot;, this, toString(time).utf8().data());
</ins><span class="cx"> 
</span><span class="cx">     for (auto&amp; trackBufferPair : m_trackBufferMap) {
</span><span class="cx">         TrackBuffer&amp; trackBuffer = trackBufferPair.value;
</span><span class="cx">         const AtomicString&amp; trackID = trackBufferPair.key;
</span><span class="cx"> 
</span><del>-        // Find the sample which contains the current presentation time.
-        auto currentSamplePTSIterator = trackBuffer.samples.presentationOrder().findSampleContainingPresentationTime(time);
-
-        if (currentSamplePTSIterator == trackBuffer.samples.presentationOrder().end()) {
-            trackBuffer.decodeQueue.clear();
-            m_private-&gt;flushAndEnqueueNonDisplayingSamples(Vector&lt;RefPtr&lt;MediaSample&gt;&gt;(), trackID);
-            continue;
-        }
-
-        // Seach backward for the previous sync sample.
-        MediaTime currentSampleDecodeTime = currentSamplePTSIterator-&gt;second-&gt;decodeTime();
-        auto currentSampleDTSIterator = trackBuffer.samples.decodeOrder().findSampleWithDecodeTime(currentSampleDecodeTime);
-        ASSERT(currentSampleDTSIterator != trackBuffer.samples.decodeOrder().end());
-
-        auto reverseCurrentSampleIter = --DecodeOrderSampleMap::reverse_iterator(currentSampleDTSIterator);
-        auto reverseLastSyncSampleIter = trackBuffer.samples.decodeOrder().findSyncSamplePriorToDecodeIterator(reverseCurrentSampleIter);
-        if (reverseLastSyncSampleIter == trackBuffer.samples.decodeOrder().rend()) {
-            trackBuffer.decodeQueue.clear();
-            m_private-&gt;flushAndEnqueueNonDisplayingSamples(Vector&lt;RefPtr&lt;MediaSample&gt;&gt;(), trackID);
-            continue;
-        }
-
-        Vector&lt;RefPtr&lt;MediaSample&gt;&gt; nonDisplayingSamples;
-        for (auto iter = reverseLastSyncSampleIter; iter != reverseCurrentSampleIter; --iter)
-            nonDisplayingSamples.append(iter-&gt;second);
-
-        m_private-&gt;flushAndEnqueueNonDisplayingSamples(nonDisplayingSamples, trackID);
-
-        // Fill the decode queue with the remaining samples.
-        trackBuffer.decodeQueue.clear();
-        for (auto iter = currentSampleDTSIterator; iter != trackBuffer.samples.decodeOrder().end(); ++iter)
-            trackBuffer.decodeQueue.insert(*iter);
-
-        provideMediaData(trackBuffer, trackID);
</del><ins>+        reenqueueMediaForTime(trackBuffer, trackID, time);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     m_source-&gt;monitorSourceBuffers();
</span><span class="lines">@@ -529,9 +498,19 @@
</span><span class="cx"> 
</span><span class="cx">     if (m_source)
</span><span class="cx">         m_source-&gt;monitorSourceBuffers();
</span><del>-    for (auto&amp; trackBufferPair : m_trackBufferMap)
-        provideMediaData(trackBufferPair.value, trackBufferPair.key);
</del><span class="cx"> 
</span><ins>+    MediaTime currentMediaTime = MediaTime::createWithDouble(m_source-&gt;currentTime());
+    for (auto&amp; trackBufferPair : m_trackBufferMap) {
+        TrackBuffer&amp; trackBuffer = trackBufferPair.value;
+        const AtomicString&amp; trackID = trackBufferPair.key;
+
+        if (trackBuffer.needsReenqueueing) {
+            LOG(Media, &quot;SourceBuffer::sourceBufferPrivateAppendComplete(%p) - reenqueuing at time (%s)&quot;, this, toString(currentMediaTime).utf8().data());
+            reenqueueMediaForTime(trackBuffer, trackID, currentMediaTime);
+        } else
+            provideMediaData(trackBuffer, trackID);
+    }
+
</ins><span class="cx">     reportExtraMemoryCost();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -604,6 +583,8 @@
</span><span class="cx">         // the HTMLMediaElement.readyState attribute to HAVE_METADATA and stall playback.
</span><span class="cx">         if (m_active &amp;&amp; currentMediaTime &gt;= start &amp;&amp; currentMediaTime &lt; end &amp;&amp; m_private-&gt;readyState() &gt; MediaPlayer::HaveMetadata)
</span><span class="cx">             m_private-&gt;setReadyState(MediaPlayer::HaveMetadata);
</span><ins>+
+        trackBuffer.needsReenqueueing = true;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // 4. If buffer full flag equals true and this object is ready to accept more bytes, then set the buffer full flag to false.
</span><span class="lines">@@ -1104,7 +1085,7 @@
</span><span class="cx">         // 1.13 Let spliced timed text frame be an unset variable for holding timed text splice information
</span><span class="cx">         // FIXME: Add support for sample splicing.
</span><span class="cx"> 
</span><del>-        DecodeOrderSampleMap::MapType erasedSamples;
</del><ins>+        SampleMap erasedSamples;
</ins><span class="cx">         MediaTime microsecond(1, 1000000);
</span><span class="cx"> 
</span><span class="cx">         // 1.14 If last decode timestamp for track buffer is unset and presentation timestamp falls
</span><span class="lines">@@ -1134,7 +1115,7 @@
</span><span class="cx">                     // 1.14.2.3 If the presentation timestamp is less than the remove window timestamp,
</span><span class="cx">                     // then remove overlapped frame and any coded frames that depend on it from track buffer.
</span><span class="cx">                     if (presentationTimestamp &lt; removeWindowTimestamp)
</span><del>-                        erasedSamples.insert(*iter);
</del><ins>+                        erasedSamples.addSample(iter-&gt;second);
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 // If track buffer contains timed text coded frames:
</span><span class="lines">@@ -1150,7 +1131,7 @@
</span><span class="cx">             // equal to presentation timestamp and less than frame end timestamp.
</span><span class="cx">             auto iter_pair = trackBuffer.samples.presentationOrder().findSamplesBetweenPresentationTimes(presentationTimestamp, frameEndTimestamp);
</span><span class="cx">             if (iter_pair.first != trackBuffer.samples.presentationOrder().end())
</span><del>-                erasedSamples.insert(iter_pair.first, iter_pair.second);
</del><ins>+                erasedSamples.addRange(iter_pair.first, iter_pair.second);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // If highest presentation timestamp for track buffer is set and less than presentation timestamp
</span><span class="lines">@@ -1159,7 +1140,7 @@
</span><span class="cx">             // presentation timestamp and less than or equal to frame end timestamp.
</span><span class="cx">             auto iter_pair = trackBuffer.samples.presentationOrder().findSamplesWithinPresentationRange(trackBuffer.highestPresentationTimestamp, frameEndTimestamp);
</span><span class="cx">             if (iter_pair.first != trackBuffer.samples.presentationOrder().end())
</span><del>-                erasedSamples.insert(iter_pair.first, iter_pair.second);
</del><ins>+                erasedSamples.addRange(iter_pair.first, iter_pair.second);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // 1.16 Remove decoding dependencies of the coded frames removed in the previous step:
</span><span class="lines">@@ -1170,21 +1151,13 @@
</span><span class="cx"> 
</span><span class="cx">             // Otherwise: Remove all coded frames between the coded frames removed in the previous step
</span><span class="cx">             // and the next random access point after those removed frames.
</span><del>-            for (auto&amp; samplePair : erasedSamples) {
-                auto currentDecodeIter = trackBuffer.samples.decodeOrder().findSampleWithDecodeTime(samplePair.second-&gt;decodeTime());
-                auto nextSyncIter = trackBuffer.samples.decodeOrder().findSyncSampleAfterDecodeIterator(currentDecodeIter);
-                dependentSamples.insert(currentDecodeIter, nextSyncIter);
-            }
</del><ins>+            auto firstDecodeIter = trackBuffer.samples.decodeOrder().findSampleWithDecodeTime(erasedSamples.decodeOrder().begin()-&gt;first);
+            auto lastDecodeIter = trackBuffer.samples.decodeOrder().findSampleWithDecodeTime(erasedSamples.decodeOrder().rbegin()-&gt;first);
+            auto nextSyncIter = trackBuffer.samples.decodeOrder().findSyncSampleAfterDecodeIterator(lastDecodeIter);
+            dependentSamples.insert(firstDecodeIter, nextSyncIter);
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">             RefPtr&lt;TimeRanges&gt; erasedRanges = TimeRanges::create();
</span><del>-            for (auto&amp; samplePair : erasedSamples) {
-                MediaTime startTime = samplePair.second-&gt;presentationTime();
-                MediaTime endTime = startTime + samplePair.second-&gt;duration() + microsecond;
-                erasedRanges-&gt;add(startTime.toDouble(), endTime.toDouble());
-                trackBuffer.samples.removeSample(samplePair.second.get());
-            }
-
</del><span class="cx">             for (auto&amp; samplePair : dependentSamples) {
</span><span class="cx">                 MediaTime startTime = samplePair.second-&gt;presentationTime();
</span><span class="cx">                 MediaTime endTime = startTime + samplePair.second-&gt;duration() + microsecond;
</span><span class="lines">@@ -1194,6 +1167,7 @@
</span><span class="cx"> 
</span><span class="cx">             erasedRanges-&gt;invert();
</span><span class="cx">             m_buffered-&gt;intersectWith(*erasedRanges.get());
</span><ins>+            trackBuffer.needsReenqueueing = true;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // 1.17 If spliced audio frame is set:
</span><span class="lines">@@ -1387,6 +1361,46 @@
</span><span class="cx">     LOG(Media, &quot;SourceBuffer::provideMediaData(%p) - Enqueued %u samples&quot;, this, enqueuedSamples);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SourceBuffer::reenqueueMediaForTime(TrackBuffer&amp; trackBuffer, AtomicString trackID, const MediaTime&amp; time)
+{
+    // Find the sample which contains the current presentation time.
+    auto currentSamplePTSIterator = trackBuffer.samples.presentationOrder().findSampleContainingPresentationTime(time);
+
+    if (currentSamplePTSIterator == trackBuffer.samples.presentationOrder().end()) {
+        trackBuffer.decodeQueue.clear();
+        m_private-&gt;flushAndEnqueueNonDisplayingSamples(Vector&lt;RefPtr&lt;MediaSample&gt;&gt;(), trackID);
+        return;
+    }
+
+    // Seach backward for the previous sync sample.
+    MediaTime currentSampleDecodeTime = currentSamplePTSIterator-&gt;second-&gt;decodeTime();
+    auto currentSampleDTSIterator = trackBuffer.samples.decodeOrder().findSampleWithDecodeTime(currentSampleDecodeTime);
+    ASSERT(currentSampleDTSIterator != trackBuffer.samples.decodeOrder().end());
+
+    auto reverseCurrentSampleIter = --DecodeOrderSampleMap::reverse_iterator(currentSampleDTSIterator);
+    auto reverseLastSyncSampleIter = trackBuffer.samples.decodeOrder().findSyncSamplePriorToDecodeIterator(reverseCurrentSampleIter);
+    if (reverseLastSyncSampleIter == trackBuffer.samples.decodeOrder().rend()) {
+        trackBuffer.decodeQueue.clear();
+        m_private-&gt;flushAndEnqueueNonDisplayingSamples(Vector&lt;RefPtr&lt;MediaSample&gt;&gt;(), trackID);
+        return;
+    }
+
+    Vector&lt;RefPtr&lt;MediaSample&gt;&gt; nonDisplayingSamples;
+    for (auto iter = reverseLastSyncSampleIter; iter != reverseCurrentSampleIter; --iter)
+        nonDisplayingSamples.append(iter-&gt;second);
+
+    m_private-&gt;flushAndEnqueueNonDisplayingSamples(nonDisplayingSamples, trackID);
+
+    // Fill the decode queue with the remaining samples.
+    trackBuffer.decodeQueue.clear();
+    for (auto iter = currentSampleDTSIterator; iter != trackBuffer.samples.decodeOrder().end(); ++iter)
+        trackBuffer.decodeQueue.insert(*iter);
+    provideMediaData(trackBuffer, trackID);
+
+    trackBuffer.needsReenqueueing = false;
+}
+
+
</ins><span class="cx"> void SourceBuffer::didDropSample()
</span><span class="cx"> {
</span><span class="cx">     if (!isRemoved())
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSourceBufferh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h (170975 => 170976)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h        2014-07-10 20:48:44 UTC (rev 170975)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h        2014-07-10 21:28:05 UTC (rev 170976)
</span><span class="lines">@@ -149,6 +149,7 @@
</span><span class="cx">     bool validateInitializationSegment(const InitializationSegment&amp;);
</span><span class="cx"> 
</span><span class="cx">     struct TrackBuffer;
</span><ins>+    void reenqueueMediaForTime(TrackBuffer&amp;, AtomicString trackID, const MediaTime&amp;);
</ins><span class="cx">     void provideMediaData(TrackBuffer&amp;, AtomicString trackID);
</span><span class="cx">     void didDropSample();
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>