<!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>[172032] 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/172032">172032</a></dd>
<dt>Author</dt> <dd>jer.noble@apple.com</dd>
<dt>Date</dt> <dd>2014-08-05 09:42:09 -0700 (Tue, 05 Aug 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[MSE] Seeking occasionally causes many frames to be displayed in &quot;fast forward&quot; mode
https://bugs.webkit.org/show_bug.cgi?id=135422

Reviewed by Eric Carlson.

Three related fixes:

In reenqueueMediaForTime(), update TrackBuffer.lastEnqueuedPresentationTime when we flush
samples, so that the next time samples are re-enqueued, the starting point for re-enqueueing
is correct.

In sourceBufferPrivateDidReceiveSample(), do not add samples to the decode queue
if they are before the current media time.

When a seek is pending, but samples for the new time is not yet present in the SourceBuffer,
the SourceBufferPrivate may signal that it's ready for new samples through the
sourceBufferPrivateDidBecomeReadyForMoreSamples() method. In this situation, we should not
continue to provideMediaData(), as that will append samples from the prior-to-seeking media
timeline. Since the timeline may have moved forward due to the seek, a decoder may decide to
display those frames as quickly as possible (the &quot;fast forward&quot; behavior) in order to catch
up to the new current time.

If a re-enqueue is pending, don't provide media data in response to being notified that the
SourceBufferPrivate is ready for more samples. Wait until samples for the new current time
are appended.

Also, don't provide media data if we are waiting for a seek to complete.

* Modules/mediasource/MediaSource.h:
(WebCore::MediaSource::isSeeking): Convenience method.
* Modules/mediasource/SourceBuffer.cpp:
(WebCore::SourceBuffer::sourceBufferPrivateDidReceiveSample):
(WebCore::SourceBuffer::sourceBufferPrivateDidBecomeReadyForMoreSamples):
(WebCore::SourceBuffer::reenqueueMediaForTime):</pre>

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

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (172031 => 172032)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-08-05 16:41:46 UTC (rev 172031)
+++ trunk/Source/WebCore/ChangeLog        2014-08-05 16:42:09 UTC (rev 172032)
</span><span class="lines">@@ -1,3 +1,40 @@
</span><ins>+2014-08-05  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        [MSE] Seeking occasionally causes many frames to be displayed in &quot;fast forward&quot; mode
+        https://bugs.webkit.org/show_bug.cgi?id=135422
+
+        Reviewed by Eric Carlson.
+
+        Three related fixes:
+
+        In reenqueueMediaForTime(), update TrackBuffer.lastEnqueuedPresentationTime when we flush
+        samples, so that the next time samples are re-enqueued, the starting point for re-enqueueing
+        is correct.
+
+        In sourceBufferPrivateDidReceiveSample(), do not add samples to the decode queue
+        if they are before the current media time.
+
+        When a seek is pending, but samples for the new time is not yet present in the SourceBuffer,
+        the SourceBufferPrivate may signal that it's ready for new samples through the
+        sourceBufferPrivateDidBecomeReadyForMoreSamples() method. In this situation, we should not
+        continue to provideMediaData(), as that will append samples from the prior-to-seeking media
+        timeline. Since the timeline may have moved forward due to the seek, a decoder may decide to
+        display those frames as quickly as possible (the &quot;fast forward&quot; behavior) in order to catch
+        up to the new current time.
+
+        If a re-enqueue is pending, don't provide media data in response to being notified that the
+        SourceBufferPrivate is ready for more samples. Wait until samples for the new current time
+        are appended.
+
+        Also, don't provide media data if we are waiting for a seek to complete.
+
+        * Modules/mediasource/MediaSource.h:
+        (WebCore::MediaSource::isSeeking): Convenience method.
+        * Modules/mediasource/SourceBuffer.cpp:
+        (WebCore::SourceBuffer::sourceBufferPrivateDidReceiveSample):
+        (WebCore::SourceBuffer::sourceBufferPrivateDidBecomeReadyForMoreSamples):
+        (WebCore::SourceBuffer::reenqueueMediaForTime):
+
</ins><span class="cx"> 2014-08-05  Chris Fleizach  &lt;cfleizach@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         AX: Select text activity should return replaced text instead of previously selected text
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceMediaSourceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/MediaSource.h (172031 => 172032)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/MediaSource.h        2014-08-05 16:41:46 UTC (rev 172031)
+++ trunk/Source/WebCore/Modules/mediasource/MediaSource.h        2014-08-05 16:42:09 UTC (rev 172032)
</span><span class="lines">@@ -79,6 +79,7 @@
</span><span class="cx">     bool attachToElement(HTMLMediaElement*);
</span><span class="cx">     void close();
</span><span class="cx">     void monitorSourceBuffers();
</span><ins>+    bool isSeeking() const { return m_pendingSeekTime.isValid(); }
</ins><span class="cx">     void completeSeek();
</span><span class="cx"> 
</span><span class="cx">     void setDuration(double, ExceptionCode&amp;);
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSourceBuffercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp (172031 => 172032)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2014-08-05 16:41:46 UTC (rev 172031)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2014-08-05 16:42:09 UTC (rev 172032)
</span><span class="lines">@@ -1208,8 +1208,10 @@
</span><span class="cx">         // Add the coded frame with the presentation timestamp, decode timestamp, and frame duration to the track buffer.
</span><span class="cx">         trackBuffer.samples.addSample(sample);
</span><span class="cx"> 
</span><del>-        DecodeOrderSampleMap::KeyType decodeKey(decodeTimestamp, presentationTimestamp);
-        trackBuffer.decodeQueue.insert(DecodeOrderSampleMap::MapType::value_type(decodeKey, sample));
</del><ins>+        if (trackBuffer.lastEnqueuedPresentationTime.isInvalid() || presentationTimestamp &gt; trackBuffer.lastEnqueuedPresentationTime) {
+            DecodeOrderSampleMap::KeyType decodeKey(decodeTimestamp, presentationTimestamp);
+            trackBuffer.decodeQueue.insert(DecodeOrderSampleMap::MapType::value_type(decodeKey, sample));
+        }
</ins><span class="cx"> 
</span><span class="cx">         // 1.18 Set last decode timestamp for track buffer to decode timestamp.
</span><span class="cx">         trackBuffer.lastDecodeTimestamp = decodeTimestamp;
</span><span class="lines">@@ -1362,7 +1364,9 @@
</span><span class="cx">     if (it == m_trackBufferMap.end())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    provideMediaData(it-&gt;value, trackID);
</del><ins>+    TrackBuffer&amp; trackBuffer = it-&gt;value;
+    if (!trackBuffer.needsReenqueueing &amp;&amp; !m_source-&gt;isSeeking())
+        provideMediaData(trackBuffer, trackID);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SourceBuffer::provideMediaData(TrackBuffer&amp; trackBuffer, AtomicString trackID)
</span><span class="lines">@@ -1421,6 +1425,9 @@
</span><span class="cx"> 
</span><span class="cx">     m_private-&gt;flushAndEnqueueNonDisplayingSamples(nonDisplayingSamples, trackID);
</span><span class="cx"> 
</span><ins>+    if (!nonDisplayingSamples.isEmpty())
+        trackBuffer.lastEnqueuedPresentationTime = nonDisplayingSamples.last()-&gt;presentationTime();
+
</ins><span class="cx">     // Fill the decode queue with the remaining samples.
</span><span class="cx">     trackBuffer.decodeQueue.clear();
</span><span class="cx">     for (auto iter = currentSampleDTSIterator; iter != trackBuffer.samples.decodeOrder().end(); ++iter)
</span></span></pre>
</div>
</div>

</body>
</html>