<!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>[172657] 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/172657">172657</a></dd>
<dt>Author</dt> <dd>eric.carlson@apple.com</dd>
<dt>Date</dt> <dd>2014-08-15 16:09:19 -0700 (Fri, 15 Aug 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[MSE] Implement a maximum buffer size for SourceBuffer
https://bugs.webkit.org/show_bug.cgi?id=135614

Reviewed by Jer Noble.

Implement the MSE coded frame eviction algorithm: when new buffers are appended attempt
to keep the amount of data buffered below a maximum size (which is determined by the media
session manager) by freeing coded frames as follows:
    1 - Free frames in 30 second chunks from 0 to 30 seconds before the current time.
    2 - If there are time ranges after the range with the current time, free frames in
        30 second chunks from duration back to the beginning of the time range after
        current time.

For now we DO NOT throw a QUOTA_EXCEEDED_ERR when we are not able to free up enough
space to remain below the prescribed quota, because some big name, widely deployed, 
code bases ignore the error and continue appending data as though the failed append
succeeded, leading to a corrupted bitstream and failure to play.

* Modules/mediasource/SampleMap.cpp:
(WebCore::SampleMap::addSample): Drive-by performance optimization: sample-&gt;presentationTime()
    is used more than once, stash it in a local variable.
(WebCore::SampleMap::removeSample): Ditto.

* Modules/mediasource/SourceBuffer.cpp:
(WebCore::logRanges): Debug-only function to log TimeRanges.
(WebCore::SourceBuffer::SourceBuffer):
(WebCore::SourceBuffer::remove): Optimize logging. Buffer full and coded frame eviction logic
    is in SourceBuffer instead of SourceBufferPrivate.
(WebCore::SourceBuffer::appendBufferInternal): Ditto.
(WebCore::SourceBuffer::sourceBufferPrivateAppendComplete): Set m_bufferFull when more data
    has been buffered than allowed.
(WebCore::removeSamplesFromTrackBuffer): Add logging.
(WebCore::SourceBuffer::removeCodedFrames): Improve logging. Avoid debug build assert when
    current time is after last enqueued presentation time.
(WebCore::SourceBuffer::evictCodedFrames): The coded frame eviction algorithm.
(WebCore::SourceBuffer::maximumBufferSize): Return the maximum amount of data that can 
    be buffered.
(WebCore::SourceBuffer::sourceBufferPrivateDidReceiveSample): Improve logging. Don't attempt
    to create a PlatformTimeRanges with inverted start and end to avoid an assert in debug.
(WebCore::SourceBuffer::hasAudio): New, return true if there are any audio tracks.
(WebCore::SourceBuffer::hasVideo): New, return true if there are any video tracks.
(WebCore::SourceBuffer::sourceBufferPrivateHasAudio): Call hasAudio.
(WebCore::SourceBuffer::sourceBufferPrivateHasVideo): Call hasVideo.
(WebCore::SourceBuffer::hasCurrentTime): Return true if currentTime is greater than duration.
(WebCore::SourceBuffer::hasFutureTime): Ditto.
(WebCore::SourceBuffer::extraMemoryCost): Return the amount of data buffered: the size of
    the input buffer plus the size of all track samples.
(WebCore::SourceBuffer::reportExtraMemoryCost): Move buffered size calculation to extraMemoryCost.
(WebCore::SourceBuffer::document): Document accessor.
* Modules/mediasource/SourceBuffer.h: Drive-by size optimization by moving all bool member
    variables to the end of class.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::refreshCachedTime): Drive-by removal of overly chatty logging.
(WebCore::HTMLMediaElement::maximumSourceBufferSize): New, maximum source buffer size.
* html/HTMLMediaElement.h:

* html/HTMLMediaSession.cpp:
(WebCore::HTMLMediaSession::maximumMediaSourceBufferSize): New, get maximum source buffer 
    size from settings, return full amount for an SourceBuffer with video and audio, return 5%
    of the maximum for an audio-only SourceBuffer.
* html/HTMLMediaSession.h:

* page/Settings.in: Add maximumSourceBufferSize. Default value is enough for approximately
    five minutes of 1080p video and stereo audio.

* platform/graphics/PlatformTimeRanges.cpp:
(WebCore::PlatformTimeRanges::totalDuration): Drive-by optimization.
(WebCore::PlatformTimeRanges::dump): New, allow a PlatformTimeRanges to be printed.
* platform/graphics/PlatformTimeRanges.h:

* platform/graphics/SourceBufferPrivate.h: Delete evictCodedFrames and isFull, that logic
    is not in SourceBuffer.
* platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h:
* platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
(WebCore::SourceBufferPrivateAVFObjC::processCodedFrame): Drive-by logging fix.
(WebCore::SourceBufferPrivateAVFObjC::evictCodedFrames): Deleted.
(WebCore::SourceBufferPrivateAVFObjC::isFull): Deleted.

* platform/mock/mediasource/MockSourceBufferPrivate.cpp:
(WebCore::MockSourceBufferPrivate::evictCodedFrames): Deleted.
(WebCore::MockSourceBufferPrivate::isFull): Deleted.
* platform/mock/mediasource/MockSourceBufferPrivate.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="#trunkSourceWebCoreModulesmediasourceSourceBuffercpp">trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesmediasourceSourceBufferh">trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaElementcpp">trunk/Source/WebCore/html/HTMLMediaElement.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaElementh">trunk/Source/WebCore/html/HTMLMediaElement.h</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaSessioncpp">trunk/Source/WebCore/html/HTMLMediaSession.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaSessionh">trunk/Source/WebCore/html/HTMLMediaSession.h</a></li>
<li><a href="#trunkSourceWebCorepageSettingsin">trunk/Source/WebCore/page/Settings.in</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsPlatformTimeRangescpp">trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsPlatformTimeRangesh">trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.h</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="#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>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/ChangeLog        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -1,3 +1,89 @@
</span><ins>+2014-08-15  Eric Carlson  &lt;eric.carlson@apple.com&gt;
+
+        [MSE] Implement a maximum buffer size for SourceBuffer
+        https://bugs.webkit.org/show_bug.cgi?id=135614
+
+        Reviewed by Jer Noble.
+
+        Implement the MSE coded frame eviction algorithm: when new buffers are appended attempt
+        to keep the amount of data buffered below a maximum size (which is determined by the media
+        session manager) by freeing coded frames as follows:
+            1 - Free frames in 30 second chunks from 0 to 30 seconds before the current time.
+            2 - If there are time ranges after the range with the current time, free frames in
+                30 second chunks from duration back to the beginning of the time range after
+                current time.
+
+        For now we DO NOT throw a QUOTA_EXCEEDED_ERR when we are not able to free up enough
+        space to remain below the prescribed quota, because some big name, widely deployed, 
+        code bases ignore the error and continue appending data as though the failed append
+        succeeded, leading to a corrupted bitstream and failure to play.
+
+        * Modules/mediasource/SampleMap.cpp:
+        (WebCore::SampleMap::addSample): Drive-by performance optimization: sample-&gt;presentationTime()
+            is used more than once, stash it in a local variable.
+        (WebCore::SampleMap::removeSample): Ditto.
+
+        * Modules/mediasource/SourceBuffer.cpp:
+        (WebCore::logRanges): Debug-only function to log TimeRanges.
+        (WebCore::SourceBuffer::SourceBuffer):
+        (WebCore::SourceBuffer::remove): Optimize logging. Buffer full and coded frame eviction logic
+            is in SourceBuffer instead of SourceBufferPrivate.
+        (WebCore::SourceBuffer::appendBufferInternal): Ditto.
+        (WebCore::SourceBuffer::sourceBufferPrivateAppendComplete): Set m_bufferFull when more data
+            has been buffered than allowed.
+        (WebCore::removeSamplesFromTrackBuffer): Add logging.
+        (WebCore::SourceBuffer::removeCodedFrames): Improve logging. Avoid debug build assert when
+            current time is after last enqueued presentation time.
+        (WebCore::SourceBuffer::evictCodedFrames): The coded frame eviction algorithm.
+        (WebCore::SourceBuffer::maximumBufferSize): Return the maximum amount of data that can 
+            be buffered.
+        (WebCore::SourceBuffer::sourceBufferPrivateDidReceiveSample): Improve logging. Don't attempt
+            to create a PlatformTimeRanges with inverted start and end to avoid an assert in debug.
+        (WebCore::SourceBuffer::hasAudio): New, return true if there are any audio tracks.
+        (WebCore::SourceBuffer::hasVideo): New, return true if there are any video tracks.
+        (WebCore::SourceBuffer::sourceBufferPrivateHasAudio): Call hasAudio.
+        (WebCore::SourceBuffer::sourceBufferPrivateHasVideo): Call hasVideo.
+        (WebCore::SourceBuffer::hasCurrentTime): Return true if currentTime is greater than duration.
+        (WebCore::SourceBuffer::hasFutureTime): Ditto.
+        (WebCore::SourceBuffer::extraMemoryCost): Return the amount of data buffered: the size of
+            the input buffer plus the size of all track samples.
+        (WebCore::SourceBuffer::reportExtraMemoryCost): Move buffered size calculation to extraMemoryCost.
+        (WebCore::SourceBuffer::document): Document accessor.
+        * Modules/mediasource/SourceBuffer.h: Drive-by size optimization by moving all bool member
+            variables to the end of class.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::refreshCachedTime): Drive-by removal of overly chatty logging.
+        (WebCore::HTMLMediaElement::maximumSourceBufferSize): New, maximum source buffer size.
+        * html/HTMLMediaElement.h:
+
+        * html/HTMLMediaSession.cpp:
+        (WebCore::HTMLMediaSession::maximumMediaSourceBufferSize): New, get maximum source buffer 
+            size from settings, return full amount for an SourceBuffer with video and audio, return 5%
+            of the maximum for an audio-only SourceBuffer.
+        * html/HTMLMediaSession.h:
+
+        * page/Settings.in: Add maximumSourceBufferSize. Default value is enough for approximately
+            five minutes of 1080p video and stereo audio.
+
+        * platform/graphics/PlatformTimeRanges.cpp:
+        (WebCore::PlatformTimeRanges::totalDuration): Drive-by optimization.
+        (WebCore::PlatformTimeRanges::dump): New, allow a PlatformTimeRanges to be printed.
+        * platform/graphics/PlatformTimeRanges.h:
+
+        * platform/graphics/SourceBufferPrivate.h: Delete evictCodedFrames and isFull, that logic
+            is not in SourceBuffer.
+        * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h:
+        * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
+        (WebCore::SourceBufferPrivateAVFObjC::processCodedFrame): Drive-by logging fix.
+        (WebCore::SourceBufferPrivateAVFObjC::evictCodedFrames): Deleted.
+        (WebCore::SourceBufferPrivateAVFObjC::isFull): Deleted.
+
+        * platform/mock/mediasource/MockSourceBufferPrivate.cpp:
+        (WebCore::MockSourceBufferPrivate::evictCodedFrames): Deleted.
+        (WebCore::MockSourceBufferPrivate::isFull): Deleted.
+        * platform/mock/mediasource/MockSourceBufferPrivate.h:
+
</ins><span class="cx"> 2014-08-15  Zalan Bujtas  &lt;zalan@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION: Parts of the route/route options windows are invisible at maps.google.com
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSampleMapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -113,9 +113,11 @@
</span><span class="cx">     RefPtr&lt;MediaSample&gt; sample = prpSample;
</span><span class="cx">     ASSERT(sample);
</span><span class="cx"> 
</span><del>-    presentationOrder().m_samples.insert(PresentationOrderSampleMap::MapType::value_type(sample-&gt;presentationTime(), sample));
</del><ins>+    MediaTime presentationTime = sample-&gt;presentationTime();
</ins><span class="cx"> 
</span><del>-    auto decodeKey = DecodeOrderSampleMap::KeyType(sample-&gt;decodeTime(), sample-&gt;presentationTime());
</del><ins>+    presentationOrder().m_samples.insert(PresentationOrderSampleMap::MapType::value_type(presentationTime, sample));
+
+    auto decodeKey = DecodeOrderSampleMap::KeyType(sample-&gt;decodeTime(), presentationTime);
</ins><span class="cx">     decodeOrder().m_samples.insert(DecodeOrderSampleMap::MapType::value_type(decodeKey, sample));
</span><span class="cx"> 
</span><span class="cx">     m_totalSize += sample-&gt;sizeInBytes();
</span><span class="lines">@@ -124,9 +126,11 @@
</span><span class="cx"> void SampleMap::removeSample(MediaSample* sample)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(sample);
</span><del>-    presentationOrder().m_samples.erase(sample-&gt;presentationTime());
</del><ins>+    MediaTime presentationTime = sample-&gt;presentationTime();
</ins><span class="cx"> 
</span><del>-    auto decodeKey = DecodeOrderSampleMap::KeyType(sample-&gt;decodeTime(), sample-&gt;presentationTime());
</del><ins>+    presentationOrder().m_samples.erase(presentationTime);
+
+    auto decodeKey = DecodeOrderSampleMap::KeyType(sample-&gt;decodeTime(), presentationTime);
</ins><span class="cx">     decodeOrder().m_samples.erase(decodeKey);
</span><span class="cx"> 
</span><span class="cx">     m_totalSize -= sample-&gt;sizeInBytes();
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSourceBuffercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -1,5 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2013 Google Inc. All rights reserved.
</span><ins>+ * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions are
</span><span class="lines">@@ -48,12 +49,16 @@
</span><span class="cx"> #include &quot;TextTrackList.h&quot;
</span><span class="cx"> #include &quot;TimeRanges.h&quot;
</span><span class="cx"> #include &quot;VideoTrackList.h&quot;
</span><ins>+#include &lt;limits&gt;
</ins><span class="cx"> #include &lt;map&gt;
</span><span class="cx"> #include &lt;runtime/JSCInlines.h&gt;
</span><span class="cx"> #include &lt;runtime/JSLock.h&gt;
</span><span class="cx"> #include &lt;runtime/VM.h&gt;
</span><span class="cx"> #include &lt;wtf/CurrentTime.h&gt;
</span><span class="cx"> #include &lt;wtf/NeverDestroyed.h&gt;
</span><ins>+#if !LOG_DISABLED
+#include &lt;wtf/text/StringBuilder.h&gt;
+#endif
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -104,12 +109,9 @@
</span><span class="cx">     , m_private(WTF::move(sourceBufferPrivate))
</span><span class="cx">     , m_source(source)
</span><span class="cx">     , m_asyncEventQueue(*this)
</span><del>-    , m_updating(false)
</del><span class="cx">     , m_appendBufferTimer(this, &amp;SourceBuffer::appendBufferTimerFired)
</span><span class="cx">     , m_highestPresentationEndTimestamp(MediaTime::invalidTime())
</span><del>-    , m_receivedFirstInitializationSegment(false)
</del><span class="cx">     , m_buffered(TimeRanges::create())
</span><del>-    , m_active(false)
</del><span class="cx">     , m_appendState(WaitingForSegment)
</span><span class="cx">     , m_timeOfBufferingMonitor(monotonicallyIncreasingTime())
</span><span class="cx">     , m_bufferedSinceLastMonitor(0)
</span><span class="lines">@@ -118,6 +120,10 @@
</span><span class="cx">     , m_pendingRemoveStart(MediaTime::invalidTime())
</span><span class="cx">     , m_pendingRemoveEnd(MediaTime::invalidTime())
</span><span class="cx">     , m_removeTimer(this, &amp;SourceBuffer::removeTimerFired)
</span><ins>+    , m_updating(false)
+    , m_receivedFirstInitializationSegment(false)
+    , m_active(false)
+    , m_bufferFull(false)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(m_source);
</span><span class="cx"> 
</span><span class="lines">@@ -235,7 +241,8 @@
</span><span class="cx"> 
</span><span class="cx"> void SourceBuffer::remove(double start, double end, ExceptionCode&amp; ec)
</span><span class="cx"> {
</span><del>-    LOG(MediaSource, &quot;SourceBuffer::remove(%p) - start(%s), end(%s)&quot;, this, toString(start).utf8().data(), toString(end).utf8().data());
</del><ins>+    LOG(MediaSource, &quot;SourceBuffer::remove(%p) - start(%lf), end(%lf)&quot;, this, start, end);
+
</ins><span class="cx">     // Section 3.2 remove() method steps.
</span><span class="cx">     // 1. If start is negative or greater than duration, then throw an InvalidAccessError exception and abort these steps.
</span><span class="cx">     // 2. If end is less than or equal to start, then throw an InvalidAccessError exception and abort these steps.
</span><span class="lines">@@ -407,13 +414,17 @@
</span><span class="cx">     m_source-&gt;openIfInEndedState();
</span><span class="cx"> 
</span><span class="cx">     // 4. Run the coded frame eviction algorithm.
</span><del>-    m_private-&gt;evictCodedFrames();
</del><ins>+    evictCodedFrames(size);
</ins><span class="cx"> 
</span><ins>+    // FIXME: enable this code when MSE libraries have been updated to support it.
+#if 0
</ins><span class="cx">     // 5. If the buffer full flag equals true, then throw a QUOTA_EXCEEDED_ERR exception and abort these step.
</span><del>-    if (m_private-&gt;isFull()) {
</del><ins>+    if (m_bufferFull) {
+        LOG(MediaSource, &quot;SourceBuffer::appendBufferInternal(%p) -  buffer full, failing with QUOTA_EXCEEDED_ERR error&quot;, this);
</ins><span class="cx">         ec = QUOTA_EXCEEDED_ERR;
</span><span class="cx">         return;
</span><span class="cx">     }
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx">     // NOTE: Return to 3.2 appendBuffer()
</span><span class="cx">     // 3. Add data to the end of the input buffer.
</span><span class="lines">@@ -514,6 +525,10 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     reportExtraMemoryCost();
</span><ins>+    if (extraMemoryCost() &gt; this-&gt;maximumBufferSize())
+        m_bufferFull = true;
+
+    LOG(Media, &quot;SourceBuffer::sourceBufferPrivateAppendComplete(%p) - buffered = %s&quot;, this, toString(m_buffered-&gt;ranges()).utf8().data());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SourceBuffer::sourceBufferPrivateDidReceiveRenderingError(SourceBufferPrivate*, int)
</span><span class="lines">@@ -527,13 +542,27 @@
</span><span class="cx">     return a.second-&gt;decodeTime() &lt; b.second-&gt;decodeTime();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static PassRefPtr&lt;TimeRanges&gt; removeSamplesFromTrackBuffer(const DecodeOrderSampleMap::MapType&amp; samples, SourceBuffer::TrackBuffer&amp; trackBuffer)
</del><ins>+static PassRefPtr&lt;TimeRanges&gt; removeSamplesFromTrackBuffer(const DecodeOrderSampleMap::MapType&amp; samples, SourceBuffer::TrackBuffer&amp; trackBuffer, const SourceBuffer* buffer, const char* logPrefix)
</ins><span class="cx"> {
</span><ins>+#if !LOG_DISABLED
+    double earliestSample = std::numeric_limits&lt;double&gt;::infinity();
+    double latestSample = 0;
+    size_t bytesRemoved = 0;
+#else
+    UNUSED_PARAM(logPrefix);
+    UNUSED_PARAM(buffer);
+#endif
+
</ins><span class="cx">     RefPtr&lt;TimeRanges&gt; erasedRanges = TimeRanges::create();
</span><span class="cx">     MediaTime microsecond(1, 1000000);
</span><span class="cx">     for (auto sampleIt : samples) {
</span><span class="cx">         const DecodeOrderSampleMap::KeyType&amp; decodeKey = sampleIt.first;
</span><ins>+#if !LOG_DISABLED
+        size_t startBufferSize = trackBuffer.samples.sizeInBytes();
+#endif
+
</ins><span class="cx">         RefPtr&lt;MediaSample&gt;&amp; sample = sampleIt.second;
</span><ins>+        LOG(MediaSource, &quot;SourceBuffer::%s(%p) - removing sample(%s)&quot;, logPrefix, buffer, toString(*sampleIt.second).utf8().data());
</ins><span class="cx"> 
</span><span class="cx">         // Remove the erased samples from the TrackBuffer sample map.
</span><span class="cx">         trackBuffer.samples.removeSample(sample.get());
</span><span class="lines">@@ -544,7 +573,21 @@
</span><span class="cx">         double startTime = sample-&gt;presentationTime().toDouble();
</span><span class="cx">         double endTime = startTime + (sample-&gt;duration() + microsecond).toDouble();
</span><span class="cx">         erasedRanges-&gt;add(startTime, endTime);
</span><ins>+
+#if !LOG_DISABLED
+        bytesRemoved += startBufferSize - trackBuffer.samples.sizeInBytes();
+        if (startTime &lt; earliestSample)
+            earliestSample = startTime;
+        if (endTime &gt; latestSample)
+            latestSample = endTime;
+#endif
</ins><span class="cx">     }
</span><ins>+
+#if !LOG_DISABLED
+    if (bytesRemoved)
+        LOG(MediaSource, &quot;SourceBuffer::%s(%p) removed %zu bytes, start(%lf), end(%lf)&quot;, logPrefix, buffer, bytesRemoved, earliestSample, latestSample);
+#endif
+
</ins><span class="cx">     return erasedRanges.release();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -590,14 +633,16 @@
</span><span class="cx">         DecodeOrderSampleMap::iterator removeDecodeStart = trackBuffer.samples.decodeOrder().findSampleWithDecodeKey(decodeKey);
</span><span class="cx"> 
</span><span class="cx">         DecodeOrderSampleMap::MapType erasedSamples(removeDecodeStart, removeDecodeEnd);
</span><del>-        RefPtr&lt;TimeRanges&gt; erasedRanges = removeSamplesFromTrackBuffer(erasedSamples, trackBuffer);
</del><ins>+        RefPtr&lt;TimeRanges&gt; erasedRanges = removeSamplesFromTrackBuffer(erasedSamples, trackBuffer, this, &quot;removeCodedFrames&quot;);
</ins><span class="cx"> 
</span><span class="cx">         // Only force the TrackBuffer to re-enqueue if the removed ranges overlap with enqueued and possibly
</span><span class="cx">         // not yet displayed samples.
</span><del>-        PlatformTimeRanges possiblyEnqueuedRanges(currentMediaTime, trackBuffer.lastEnqueuedPresentationTime);
-        possiblyEnqueuedRanges.intersectWith(erasedRanges-&gt;ranges());
-        if (possiblyEnqueuedRanges.length())
-            trackBuffer.needsReenqueueing = true;
</del><ins>+        if (currentMediaTime &lt; trackBuffer.lastEnqueuedPresentationTime) {
+            PlatformTimeRanges possiblyEnqueuedRanges(currentMediaTime, trackBuffer.lastEnqueuedPresentationTime);
+            possiblyEnqueuedRanges.intersectWith(erasedRanges-&gt;ranges());
+            if (possiblyEnqueuedRanges.length())
+                trackBuffer.needsReenqueueing = true;
+        }
</ins><span class="cx"> 
</span><span class="cx">         erasedRanges-&gt;invert();
</span><span class="cx">         m_buffered-&gt;intersectWith(*erasedRanges);
</span><span class="lines">@@ -611,6 +656,8 @@
</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="cx">     // No-op
</span><ins>+
+    LOG(Media, &quot;SourceBuffer::removeCodedFrames(%p) - buffered = %s&quot;, this, toString(m_buffered-&gt;ranges()).utf8().data());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SourceBuffer::removeTimerFired(Timer&lt;SourceBuffer&gt;*)
</span><span class="lines">@@ -637,6 +684,109 @@
</span><span class="cx">     scheduleEvent(eventNames().updateendEvent);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SourceBuffer::evictCodedFrames(size_t newDataSize)
+{
+    // 3.5.13 Coded Frame Eviction Algorithm
+    // http://www.w3.org/TR/media-source/#sourcebuffer-coded-frame-eviction
+
+    if (isRemoved())
+        return;
+
+    // This algorithm is run to free up space in this source buffer when new data is appended.
+    // 1. Let new data equal the data that is about to be appended to this SourceBuffer.
+    // 2. If the buffer full flag equals false, then abort these steps.
+    if (!m_bufferFull)
+        return;
+
+    size_t maximumBufferSize = this-&gt;maximumBufferSize();
+
+    // 3. Let removal ranges equal a list of presentation time ranges that can be evicted from
+    // the presentation to make room for the new data.
+
+    // NOTE: begin by removing data from the beginning of the buffered ranges, 30 seconds at
+    // a time, up to 30 seconds before currentTime.
+    MediaTime thirtySeconds = MediaTime(30, 1);
+    MediaTime currentTime = MediaTime::createWithDouble(m_source-&gt;currentTime());
+    MediaTime maximumRangeEnd = currentTime - thirtySeconds;
+
+#if !LOG_DISABLED
+    LOG(MediaSource, &quot;SourceBuffer::evictCodedFrames(%p) - currentTime = %lf, require %zu bytes, maximum buffer size is %zu&quot;, this, m_source-&gt;currentTime(), extraMemoryCost() + newDataSize, maximumBufferSize);
+    size_t initialBufferedSize = extraMemoryCost();
+#endif
+
+    MediaTime rangeStart = MediaTime::zeroTime();
+    MediaTime rangeEnd = rangeStart + thirtySeconds;
+    while (rangeStart &lt; maximumRangeEnd) {
+        // 4. For each range in removal ranges, run the coded frame removal algorithm with start and
+        // end equal to the removal range start and end timestamp respectively.
+        removeCodedFrames(rangeStart, std::min(rangeEnd, maximumRangeEnd));
+        if (extraMemoryCost() + newDataSize &lt; maximumBufferSize) {
+            m_bufferFull = false;
+            break;
+        }
+
+        rangeStart += thirtySeconds;
+        rangeEnd += thirtySeconds;
+    }
+
+    if (!m_bufferFull) {
+        LOG(MediaSource, &quot;SourceBuffer::evictCodedFrames(%p) - evicted %zu bytes&quot;, this, initialBufferedSize - extraMemoryCost());
+        return;
+    }
+
+    // If there still isn't enough free space and there buffers in time ranges after the current range (ie. there is a gap after
+    // the current buffered range), delete 30 seconds at a time from duration back to the current time range or 30 seconds after
+    // currenTime whichever we hit first.
+    auto buffered = m_buffered-&gt;ranges();
+    size_t currentTimeRange = buffered.find(currentTime);
+    if (currentTimeRange == notFound || currentTimeRange == buffered.length() - 1) {
+        LOG(MediaSource, &quot;SourceBuffer::evictCodedFrames(%p) - evicted %zu bytes but FAILED to free enough&quot;, this, initialBufferedSize - extraMemoryCost());
+        return;
+    }
+
+    MediaTime minimumRangeStart = currentTime + thirtySeconds;
+
+    rangeEnd = MediaTime::createWithDouble(m_source-&gt;duration());
+    rangeStart = rangeEnd - thirtySeconds;
+    while (rangeStart &gt; minimumRangeStart) {
+
+        // Do not evict data from the time range that contains currentTime.
+        size_t startTimeRange = buffered.find(rangeStart);
+        if (startTimeRange == currentTimeRange) {
+            size_t endTimeRange = buffered.find(rangeEnd);
+            if (endTimeRange == currentTimeRange)
+                break;
+
+            rangeEnd = buffered.start(endTimeRange);
+        }
+
+        // 4. For each range in removal ranges, run the coded frame removal algorithm with start and
+        // end equal to the removal range start and end timestamp respectively.
+        removeCodedFrames(std::max(minimumRangeStart, rangeStart), rangeEnd);
+        if (extraMemoryCost() + newDataSize &lt; maximumBufferSize) {
+            m_bufferFull = false;
+            break;
+        }
+
+        rangeStart -= thirtySeconds;
+        rangeEnd -= thirtySeconds;
+    }
+
+    LOG(MediaSource, &quot;SourceBuffer::evictCodedFrames(%p) - evicted %zu bytes%s&quot;, this, initialBufferedSize - extraMemoryCost(), m_bufferFull ? &quot;&quot; : &quot; but FAILED to free enough&quot;);
+}
+
+size_t SourceBuffer::maximumBufferSize() const
+{
+    if (isRemoved())
+        return 0;
+
+    HTMLMediaElement* element = m_source-&gt;mediaElement();
+    if (!element)
+        return 0;
+
+    return element-&gt;maximumSourceBufferSize(*this);
+}
+
</ins><span class="cx"> const AtomicString&amp; SourceBuffer::decodeError()
</span><span class="cx"> {
</span><span class="cx">     static NeverDestroyed&lt;AtomicString&gt; decode(&quot;decode&quot;, AtomicString::ConstructFromLiteral);
</span><span class="lines">@@ -1198,19 +1348,17 @@
</span><span class="cx">             auto nextSyncIter = trackBuffer.samples.decodeOrder().findSyncSampleAfterDecodeIterator(lastDecodeIter);
</span><span class="cx">             dependentSamples.insert(firstDecodeIter, nextSyncIter);
</span><span class="cx"> 
</span><del>-            RefPtr&lt;TimeRanges&gt; erasedRanges = removeSamplesFromTrackBuffer(dependentSamples, trackBuffer);
-#if !LOG_DISABLED
-            for (auto&amp; samplePair : dependentSamples)
-                LOG(MediaSource, &quot;SourceBuffer::sourceBufferPrivateDidReceiveSample(%p) - removing sample(%s)&quot;, this, toString(*samplePair.second).utf8().data());
-#endif
</del><ins>+            RefPtr&lt;TimeRanges&gt; erasedRanges = removeSamplesFromTrackBuffer(dependentSamples, trackBuffer, this, &quot;sourceBufferPrivateDidReceiveSample&quot;);
</ins><span class="cx"> 
</span><span class="cx">             // Only force the TrackBuffer to re-enqueue if the removed ranges overlap with enqueued and possibly
</span><span class="cx">             // not yet displayed samples.
</span><span class="cx">             MediaTime currentMediaTime = MediaTime::createWithDouble(m_source-&gt;currentTime());
</span><del>-            PlatformTimeRanges possiblyEnqueuedRanges(currentMediaTime, trackBuffer.lastEnqueuedPresentationTime);
-            possiblyEnqueuedRanges.intersectWith(erasedRanges-&gt;ranges());
-            if (possiblyEnqueuedRanges.length())
-                trackBuffer.needsReenqueueing = true;
</del><ins>+            if (currentMediaTime &lt; trackBuffer.lastEnqueuedPresentationTime) {
+                PlatformTimeRanges possiblyEnqueuedRanges(currentMediaTime, trackBuffer.lastEnqueuedPresentationTime);
+                possiblyEnqueuedRanges.intersectWith(erasedRanges-&gt;ranges());
+                if (possiblyEnqueuedRanges.length())
+                    trackBuffer.needsReenqueueing = true;
+            }
</ins><span class="cx"> 
</span><span class="cx">             erasedRanges-&gt;invert();
</span><span class="cx">             m_buffered-&gt;intersectWith(*erasedRanges.get());
</span><span class="lines">@@ -1262,16 +1410,26 @@
</span><span class="cx">         m_source-&gt;setDurationInternal(highestPresentationEndTimestamp().toDouble());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool SourceBuffer::sourceBufferPrivateHasAudio(const SourceBufferPrivate*) const
</del><ins>+bool SourceBuffer::hasAudio() const
</ins><span class="cx"> {
</span><span class="cx">     return m_audioTracks &amp;&amp; m_audioTracks-&gt;length();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool SourceBuffer::sourceBufferPrivateHasVideo(const SourceBufferPrivate*) const
</del><ins>+bool SourceBuffer::hasVideo() const
</ins><span class="cx"> {
</span><span class="cx">     return m_videoTracks &amp;&amp; m_videoTracks-&gt;length();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool SourceBuffer::sourceBufferPrivateHasAudio(const SourceBufferPrivate*) const
+{
+    return hasAudio();
+}
+
+bool SourceBuffer::sourceBufferPrivateHasVideo(const SourceBufferPrivate*) const
+{
+    return hasVideo();
+}
+
</ins><span class="cx"> void SourceBuffer::videoTrackSelectedChanged(VideoTrack* track)
</span><span class="cx"> {
</span><span class="cx">     // 2.4.5 Changes to selected/enabled track state
</span><span class="lines">@@ -1515,6 +1673,10 @@
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     MediaTime currentTime = MediaTime::createWithDouble(m_source-&gt;currentTime());
</span><ins>+    MediaTime duration = MediaTime::createWithDouble(m_source-&gt;duration());
+    if (currentTime &gt;= duration)
+        return true;
+
</ins><span class="cx">     std::unique_ptr&lt;PlatformTimeRanges&gt; ranges = bufferedAccountingForEndOfStream();
</span><span class="cx">     return abs(ranges-&gt;nearest(currentTime) - currentTime) &lt;= currentTimeFudgeFactor();
</span><span class="cx"> }
</span><span class="lines">@@ -1529,6 +1691,10 @@
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     MediaTime currentTime = MediaTime::createWithDouble(m_source-&gt;currentTime());
</span><ins>+    MediaTime duration = MediaTime::createWithDouble(m_source-&gt;duration());
+    if (currentTime &gt;= duration)
+        return true;
+
</ins><span class="cx">     MediaTime nearest = ranges-&gt;nearest(currentTime);
</span><span class="cx">     if (abs(nearest - currentTime) &gt; currentTimeFudgeFactor())
</span><span class="cx">         return false;
</span><span class="lines">@@ -1538,7 +1704,6 @@
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     MediaTime localEnd = ranges-&gt;end(found);
</span><del>-    MediaTime duration = MediaTime::createWithDouble(m_source-&gt;duration());
</del><span class="cx">     if (localEnd == duration)
</span><span class="cx">         return true;
</span><span class="cx"> 
</span><span class="lines">@@ -1572,12 +1737,18 @@
</span><span class="cx">     return unbufferedTime.toDouble() / m_averageBufferRate &lt; timeRemaining.toDouble();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SourceBuffer::reportExtraMemoryCost()
</del><ins>+size_t SourceBuffer::extraMemoryCost() const
</ins><span class="cx"> {
</span><span class="cx">     size_t extraMemoryCost = m_pendingAppendData.capacity();
</span><span class="cx">     for (auto&amp; trackBuffer : m_trackBufferMap.values())
</span><span class="cx">         extraMemoryCost += trackBuffer.samples.sizeInBytes();
</span><span class="cx"> 
</span><ins>+    return extraMemoryCost;
+}
+
+void SourceBuffer::reportExtraMemoryCost()
+{
+    size_t extraMemoryCost = this-&gt;extraMemoryCost();
</ins><span class="cx">     if (extraMemoryCost &lt; m_reportedExtraMemoryCost)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="lines">@@ -1603,6 +1774,12 @@
</span><span class="cx">     return sampleDescriptions;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Document&amp; SourceBuffer::document() const
+{
+    ASSERT(scriptExecutionContext()-&gt;isDocument());
+    return *static_cast&lt;Document*&gt;(scriptExecutionContext());
+}
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx"> 
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSourceBufferh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.h        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -1,5 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2013 Google Inc. All rights reserved.
</span><ins>+ * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions are
</span><span class="lines">@@ -90,6 +91,9 @@
</span><span class="cx">     bool hasFutureTime() const;
</span><span class="cx">     bool canPlayThrough();
</span><span class="cx"> 
</span><ins>+    bool hasVideo() const;
+    bool hasAudio() const;
+
</ins><span class="cx">     bool active() const { return m_active; }
</span><span class="cx"> 
</span><span class="cx">     // ActiveDOMObject interface
</span><span class="lines">@@ -105,6 +109,8 @@
</span><span class="cx"> 
</span><span class="cx">     struct TrackBuffer;
</span><span class="cx"> 
</span><ins>+    Document&amp; document() const;
+
</ins><span class="cx"> protected:
</span><span class="cx">     // EventTarget interface
</span><span class="cx">     virtual void refEventTarget() override { ref(); }
</span><span class="lines">@@ -154,12 +160,15 @@
</span><span class="cx">     void reenqueueMediaForTime(TrackBuffer&amp;, AtomicString trackID, const MediaTime&amp;);
</span><span class="cx">     void provideMediaData(TrackBuffer&amp;, AtomicString trackID);
</span><span class="cx">     void didDropSample();
</span><ins>+    void evictCodedFrames(size_t newDataSize);
+    size_t maximumBufferSize() const;
</ins><span class="cx"> 
</span><span class="cx">     void monitorBufferingRate();
</span><span class="cx"> 
</span><span class="cx">     void removeTimerFired(Timer&lt;SourceBuffer&gt;*);
</span><span class="cx">     void removeCodedFrames(const MediaTime&amp; start, const MediaTime&amp; end);
</span><span class="cx"> 
</span><ins>+    size_t extraMemoryCost() const;
</ins><span class="cx">     void reportExtraMemoryCost();
</span><span class="cx"> 
</span><span class="cx">     std::unique_ptr&lt;PlatformTimeRanges&gt; bufferedAccountingForEndOfStream() const;
</span><span class="lines">@@ -172,8 +181,6 @@
</span><span class="cx">     MediaSource* m_source;
</span><span class="cx">     GenericEventQueue m_asyncEventQueue;
</span><span class="cx"> 
</span><del>-    bool m_updating;
-
</del><span class="cx">     Vector&lt;unsigned char&gt; m_pendingAppendData;
</span><span class="cx">     Timer&lt;SourceBuffer&gt; m_appendBufferTimer;
</span><span class="cx"> 
</span><span class="lines">@@ -189,9 +196,7 @@
</span><span class="cx">     MediaTime m_highestPresentationEndTimestamp;
</span><span class="cx"> 
</span><span class="cx">     HashMap&lt;AtomicString, TrackBuffer&gt; m_trackBufferMap;
</span><del>-    bool m_receivedFirstInitializationSegment;
</del><span class="cx">     RefPtr&lt;TimeRanges&gt; m_buffered;
</span><del>-    bool m_active;
</del><span class="cx"> 
</span><span class="cx">     enum AppendStateType { WaitingForSegment, ParsingInitSegment, ParsingMediaSegment };
</span><span class="cx">     AppendStateType m_appendState;
</span><span class="lines">@@ -205,6 +210,11 @@
</span><span class="cx">     MediaTime m_pendingRemoveStart;
</span><span class="cx">     MediaTime m_pendingRemoveEnd;
</span><span class="cx">     Timer&lt;SourceBuffer&gt; m_removeTimer;
</span><ins>+
+    bool m_updating;
+    bool m_receivedFirstInitializationSegment;
+    bool m_active;
+    bool m_bufferFull;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.cpp        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -2518,7 +2518,6 @@
</span><span class="cx">         return; 
</span><span class="cx">     } 
</span><span class="cx"> 
</span><del>-    LOG(Media, &quot;HTMLMediaElement::refreshCachedTime - caching time %f&quot;, m_cachedTime); 
</del><span class="cx">     m_clockTimeAtLastCachedTimeUpdate = monotonicallyIncreasingTime();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -5972,6 +5971,13 @@
</span><span class="cx">     return MediaSession::Audio;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if ENABLE(MEDIA_SOURCE)
+size_t HTMLMediaElement::maximumSourceBufferSize(const SourceBuffer&amp; buffer) const
+{
+    return m_mediaSession-&gt;maximumMediaSourceBufferSize(buffer);
+}
+#endif
+
</ins><span class="cx"> void HTMLMediaElement::pausePlayback()
</span><span class="cx"> {
</span><span class="cx">     LOG(Media, &quot;HTMLMediaElement::pausePlayback - paused = %s&quot;, boolString(paused()));
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.h        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -72,6 +72,7 @@
</span><span class="cx"> #endif
</span><span class="cx"> #if ENABLE(MEDIA_SOURCE)
</span><span class="cx"> class MediaSource;
</span><ins>+class SourceBuffer;
</ins><span class="cx"> class VideoPlaybackQuality;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="lines">@@ -208,6 +209,7 @@
</span><span class="cx"> //  Media Source.
</span><span class="cx">     void closeMediaSource();
</span><span class="cx">     void incrementDroppedFrameCount() { ++m_droppedVideoFrames; }
</span><ins>+    size_t maximumSourceBufferSize(const SourceBuffer&amp;) const;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(ENCRYPTED_MEDIA)
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaSessioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaSession.cpp (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaSession.cpp        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/html/HTMLMediaSession.cpp        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx"> #include &quot;MediaSessionManager.h&quot;
</span><span class="cx"> #include &quot;Page.h&quot;
</span><span class="cx"> #include &quot;ScriptController.h&quot;
</span><ins>+#include &quot;SourceBuffer.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx"> #include &quot;AudioSession.h&quot;
</span><span class="lines">@@ -301,6 +302,38 @@
</span><span class="cx">     
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if ENABLE(MEDIA_SOURCE)
+const unsigned fiveMinutesOf1080PVideo = 290 * 1024 * 1024; // 290 MB is approximately 5 minutes of 8Mbps (1080p) content.
+const unsigned fiveMinutesStereoAudio = 14 * 1024 * 1024; // 14 MB is approximately 5 minutes of 384kbps content.
+
+size_t HTMLMediaSession::maximumMediaSourceBufferSize(const SourceBuffer&amp; buffer) const
+{
+    // A good quality 1080p video uses 8,000 kbps and stereo audio uses 384 kbps, so assume 95% for video and 5% for audio.
+    const float bufferBudgetPercentageForVideo = .95;
+    const float bufferBudgetPercentageForAudio = .05;
+
+    size_t maximum;
+    Settings* settings = buffer.document().settings();
+    if (settings)
+        maximum = settings-&gt;maximumSourceBufferSize();
+    else
+        maximum = fiveMinutesOf1080PVideo + fiveMinutesStereoAudio;
+
+    // Allow a SourceBuffer to buffer as though it is audio-only even if it doesn't have any active tracks (yet).
+    size_t bufferSize = static_cast&lt;size_t&gt;(maximum * bufferBudgetPercentageForAudio);
+    if (buffer.hasVideo())
+        bufferSize += static_cast&lt;size_t&gt;(maximum * bufferBudgetPercentageForVideo);
+
+    // FIXME: we might want to modify this algorithm to:
+    // - decrease the maximum size for background tabs
+    // - decrease the maximum size allowed for inactive elements when a process has more than one
+    //   element, eg. so a page with many elements which are played one at a time doesn't keep
+    //   everything buffered after an element has finished playing.
+
+    return bufferSize;
</ins><span class="cx"> }
</span><ins>+#endif
</ins><span class="cx"> 
</span><ins>+}
+
</ins><span class="cx"> #endif // ENABLE(VIDEO)
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaSessionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaSession.h (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaSession.h        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/html/HTMLMediaSession.h        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> class HTMLMediaElement;
</span><ins>+class SourceBuffer;
</ins><span class="cx"> 
</span><span class="cx"> class HTMLMediaSession : public MediaSession {
</span><span class="cx"> public:
</span><span class="lines">@@ -82,6 +83,10 @@
</span><span class="cx">     void addBehaviorRestriction(BehaviorRestrictions);
</span><span class="cx">     void removeBehaviorRestriction(BehaviorRestrictions);
</span><span class="cx"> 
</span><ins>+#if ENABLE(MEDIA_SOURCE)
+    size_t maximumMediaSourceBufferSize(const SourceBuffer&amp;) const;
+#endif
+
</ins><span class="cx"> private:
</span><span class="cx">     BehaviorRestrictions m_restrictions;
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebCorepageSettingsin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/Settings.in (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/Settings.in        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/page/Settings.in        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -230,4 +230,8 @@
</span><span class="cx"> # as a means to pass data from the web-portion of their app to the native portion.
</span><span class="cx"> allowNavigationToInvalidURL initial=false
</span><span class="cx"> 
</span><ins>+# Allow SourceBuffers to store up to 304MB each, enough for approximately five minutes
+# of 1080p video and stereo audio.
+maximumSourceBufferSize type=int, initial=318767104, conditional=MEDIA_SOURCE
+
</ins><span class="cx"> longMousePressEnabled initial=false
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsPlatformTimeRangescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> #include &quot;PlatformTimeRanges.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #include &lt;math.h&gt;
</span><ins>+#include &lt;wtf/PrintStream.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -252,11 +253,19 @@
</span><span class="cx"> MediaTime PlatformTimeRanges::totalDuration() const
</span><span class="cx"> {
</span><span class="cx">     MediaTime total = MediaTime::zeroTime();
</span><del>-    bool ignoreInvalid;
</del><span class="cx"> 
</span><span class="cx">     for (unsigned n = 0; n &lt; length(); n++)
</span><del>-        total += abs(end(n, ignoreInvalid) - start(n, ignoreInvalid));
</del><ins>+        total += abs(end(n) - start(n));
</ins><span class="cx">     return total;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void PlatformTimeRanges::dump(PrintStream&amp; out) const
+{
+    if (!length())
+        return;
+
+    for (size_t i = 0; i &lt; length(); ++i)
+        out.print(&quot;[&quot;, start(i), &quot;..&quot;, end(i), &quot;] &quot;);
</ins><span class="cx"> }
</span><ins>+
+}
</ins></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsPlatformTimeRangesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.h (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.h        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/platform/graphics/PlatformTimeRanges.h        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -32,6 +32,10 @@
</span><span class="cx"> #include &lt;wtf/RefCounted.h&gt;
</span><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><span class="cx"> 
</span><ins>+namespace WTF {
+class PrintStream;
+}
+
</ins><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> class PlatformTimeRanges {
</span><span class="lines">@@ -69,6 +73,8 @@
</span><span class="cx"> 
</span><span class="cx">     MediaTime totalDuration() const;
</span><span class="cx"> 
</span><ins>+    void dump(WTF::PrintStream&amp;) const;
+
</ins><span class="cx"> private:
</span><span class="cx">     PlatformTimeRanges&amp; copy(const PlatformTimeRanges&amp;);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsSourceBufferPrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/SourceBufferPrivate.h (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/SourceBufferPrivate.h        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/platform/graphics/SourceBufferPrivate.h        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -1,5 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2013 Google Inc. All rights reserved.
</span><ins>+ * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions are
</span><span class="lines">@@ -55,8 +56,6 @@
</span><span class="cx"> 
</span><span class="cx">     virtual MediaPlayer::ReadyState readyState() const = 0;
</span><span class="cx">     virtual void setReadyState(MediaPlayer::ReadyState) = 0;
</span><del>-    virtual void evictCodedFrames() = 0;
-    virtual bool isFull() = 0;
</del><span class="cx"> 
</span><span class="cx">     virtual void flushAndEnqueueNonDisplayingSamples(Vector&lt;RefPtr&lt;MediaSample&gt;&gt;, AtomicString) { }
</span><span class="cx">     virtual void enqueueSample(PassRefPtr&lt;MediaSample&gt;, AtomicString) { }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -112,8 +112,6 @@
</span><span class="cx">     virtual void removedFromMediaSource() override;
</span><span class="cx">     virtual MediaPlayer::ReadyState readyState() const override;
</span><span class="cx">     virtual void setReadyState(MediaPlayer::ReadyState) override;
</span><del>-    virtual void evictCodedFrames() override;
-    virtual bool isFull() override;
</del><span class="cx">     virtual void flushAndEnqueueNonDisplayingSamples(Vector&lt;RefPtr&lt;MediaSample&gt;&gt;, AtomicString trackID) override;
</span><span class="cx">     virtual void enqueueSample(PassRefPtr&lt;MediaSample&gt;, AtomicString trackID) override;
</span><span class="cx">     virtual bool isReadyForMoreSamples(AtomicString trackID) override;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -632,7 +632,7 @@
</span><span class="cx">         CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
</span><span class="cx">         FloatSize formatSize = FloatSize(CMVideoFormatDescriptionGetPresentationDimensions(formatDescription, true, true));
</span><span class="cx">         if (formatSize != m_cachedSize) {
</span><del>-            LOG(MediaSource, &quot;SourceBufferPrivateAVFObjC::processCodedFrame(%p) - size change detected: {width=%lf, height=%lf&quot;, formatSize.width(), formatSize.height());
</del><ins>+            LOG(MediaSource, &quot;SourceBufferPrivateAVFObjC::processCodedFrame(%p) - size change detected: {width=%lf, height=%lf}&quot;, formatSize.width(), formatSize.height());
</ins><span class="cx">             m_cachedSize = formatSize;
</span><span class="cx">             if (m_mediaSource)
</span><span class="cx">                 m_mediaSource-&gt;player()-&gt;sizeChanged();
</span><span class="lines">@@ -779,18 +779,6 @@
</span><span class="cx">         m_mediaSource-&gt;player()-&gt;setReadyState(readyState);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SourceBufferPrivateAVFObjC::evictCodedFrames()
-{
-    notImplemented();
-}
-
-bool SourceBufferPrivateAVFObjC::isFull()
-{
-    notImplemented();
-    return false;
-}
-
-
</del><span class="cx"> bool SourceBufferPrivateAVFObjC::hasVideo() const
</span><span class="cx"> {
</span><span class="cx">     if (!m_client)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmockmediasourceMockSourceBufferPrivatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -213,16 +213,6 @@
</span><span class="cx">         m_mediaSource-&gt;player()-&gt;setReadyState(readyState);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MockSourceBufferPrivate::evictCodedFrames()
-{
-    // No-op.
-}
-
-bool MockSourceBufferPrivate::isFull()
-{
-    return false;
-}
-
</del><span class="cx"> void MockSourceBufferPrivate::setActive(bool isActive)
</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 (172656 => 172657)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.h        2014-08-15 22:43:50 UTC (rev 172656)
+++ trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.h        2014-08-15 23:09:19 UTC (rev 172657)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -68,8 +68,6 @@
</span><span class="cx">     virtual void removedFromMediaSource() override;
</span><span class="cx">     virtual MediaPlayer::ReadyState readyState() const override;
</span><span class="cx">     virtual void setReadyState(MediaPlayer::ReadyState) override;
</span><del>-    virtual void evictCodedFrames() override;
-    virtual bool isFull() override;
</del><span class="cx"> 
</span><span class="cx">     virtual void flushAndEnqueueNonDisplayingSamples(Vector&lt;RefPtr&lt;MediaSample&gt;&gt;, AtomicString) override { }
</span><span class="cx">     virtual void enqueueSample(PassRefPtr&lt;MediaSample&gt;, AtomicString) override;
</span></span></pre>
</div>
</div>

</body>
</html>