<!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>[172778] branches/safari-600.1-branch/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/172778">172778</a></dd>
<dt>Author</dt> <dd>dburkart@apple.com</dd>
<dt>Date</dt> <dd>2014-08-19 16:26:50 -0700 (Tue, 19 Aug 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Merge <a href="http://trac.webkit.org/projects/webkit/changeset/172657">r172657</a>. <rdar://problem/17896828></pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#branchessafari6001branchSourceWebCoreChangeLog">branches/safari-600.1-branch/Source/WebCore/ChangeLog</a></li>
<li><a href="#branchessafari6001branchSourceWebCoreModulesmediasourceSampleMapcpp">branches/safari-600.1-branch/Source/WebCore/Modules/mediasource/SampleMap.cpp</a></li>
<li><a href="#branchessafari6001branchSourceWebCoreModulesmediasourceSourceBuffercpp">branches/safari-600.1-branch/Source/WebCore/Modules/mediasource/SourceBuffer.cpp</a></li>
<li><a href="#branchessafari6001branchSourceWebCoreModulesmediasourceSourceBufferh">branches/safari-600.1-branch/Source/WebCore/Modules/mediasource/SourceBuffer.h</a></li>
<li><a href="#branchessafari6001branchSourceWebCorehtmlHTMLMediaElementcpp">branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaElement.cpp</a></li>
<li><a href="#branchessafari6001branchSourceWebCorehtmlHTMLMediaElementh">branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaElement.h</a></li>
<li><a href="#branchessafari6001branchSourceWebCorehtmlHTMLMediaSessioncpp">branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaSession.cpp</a></li>
<li><a href="#branchessafari6001branchSourceWebCorehtmlHTMLMediaSessionh">branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaSession.h</a></li>
<li><a href="#branchessafari6001branchSourceWebCorepageSettingsin">branches/safari-600.1-branch/Source/WebCore/page/Settings.in</a></li>
<li><a href="#branchessafari6001branchSourceWebCoreplatformgraphicsPlatformTimeRangescpp">branches/safari-600.1-branch/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp</a></li>
<li><a href="#branchessafari6001branchSourceWebCoreplatformgraphicsPlatformTimeRangesh">branches/safari-600.1-branch/Source/WebCore/platform/graphics/PlatformTimeRanges.h</a></li>
<li><a href="#branchessafari6001branchSourceWebCoreplatformgraphicsSourceBufferPrivateh">branches/safari-600.1-branch/Source/WebCore/platform/graphics/SourceBufferPrivate.h</a></li>
<li><a href="#branchessafari6001branchSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCh">branches/safari-600.1-branch/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h</a></li>
<li><a href="#branchessafari6001branchSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCmm">branches/safari-600.1-branch/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm</a></li>
<li><a href="#branchessafari6001branchSourceWebCoreplatformmockmediasourceMockSourceBufferPrivatecpp">branches/safari-600.1-branch/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp</a></li>
<li><a href="#branchessafari6001branchSourceWebCoreplatformmockmediasourceMockSourceBufferPrivateh">branches/safari-600.1-branch/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.h</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchessafari6001branchSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/ChangeLog (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/ChangeLog        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/ChangeLog        2014-08-19 23:26:50 UTC (rev 172778)
</span><span class="lines">@@ -1,5 +1,95 @@
</span><span class="cx"> 2014-08-19 Dana Burkart <dburkart@apple.com>
</span><span class="cx">
</span><ins>+ Merge r172657. <rdar://problem/17896828>
+
+ 2014-08-15 Eric Carlson <eric.carlson@apple.com>
+
+ [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->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:
+
+2014-08-19 Dana Burkart <dburkart@apple.com>
+
</ins><span class="cx"> Merge r172656. <rdar://problem/17961698>
</span><span class="cx">
</span><span class="cx"> 2014-08-15 Zalan Bujtas <zalan@apple.com>
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebCoreModulesmediasourceSampleMapcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/Modules/mediasource/SampleMap.cpp (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/Modules/mediasource/SampleMap.cpp        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/Modules/mediasource/SampleMap.cpp        2014-08-19 23:26:50 UTC (rev 172778)
</span><span class="lines">@@ -113,9 +113,11 @@
</span><span class="cx"> RefPtr<MediaSample> sample = prpSample;
</span><span class="cx"> ASSERT(sample);
</span><span class="cx">
</span><del>- presentationOrder().m_samples.insert(PresentationOrderSampleMap::MapType::value_type(sample->presentationTime(), sample));
</del><ins>+ MediaTime presentationTime = sample->presentationTime();
</ins><span class="cx">
</span><del>- auto decodeKey = DecodeOrderSampleMap::KeyType(sample->decodeTime(), sample->presentationTime());
</del><ins>+ presentationOrder().m_samples.insert(PresentationOrderSampleMap::MapType::value_type(presentationTime, sample));
+
+ auto decodeKey = DecodeOrderSampleMap::KeyType(sample->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->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->presentationTime());
</del><ins>+ MediaTime presentationTime = sample->presentationTime();
</ins><span class="cx">
</span><del>- auto decodeKey = DecodeOrderSampleMap::KeyType(sample->decodeTime(), sample->presentationTime());
</del><ins>+ presentationOrder().m_samples.erase(presentationTime);
+
+ auto decodeKey = DecodeOrderSampleMap::KeyType(sample->decodeTime(), presentationTime);
</ins><span class="cx"> decodeOrder().m_samples.erase(decodeKey);
</span><span class="cx">
</span><span class="cx"> m_totalSize -= sample->sizeInBytes();
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebCoreModulesmediasourceSourceBuffercpp"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/Modules/mediasource/SourceBuffer.cpp (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2014-08-19 23:26:50 UTC (rev 172778)
</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 "TextTrackList.h"
</span><span class="cx"> #include "TimeRanges.h"
</span><span class="cx"> #include "VideoTrackList.h"
</span><ins>+#include <limits>
</ins><span class="cx"> #include <map>
</span><span class="cx"> #include <runtime/JSCInlines.h>
</span><span class="cx"> #include <runtime/JSLock.h>
</span><span class="cx"> #include <runtime/VM.h>
</span><span class="cx"> #include <wtf/CurrentTime.h>
</span><span class="cx"> #include <wtf/NeverDestroyed.h>
</span><ins>+#if !LOG_DISABLED
+#include <wtf/text/StringBuilder.h>
+#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, &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, &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& ec)
</span><span class="cx"> {
</span><del>- LOG(MediaSource, "SourceBuffer::remove(%p) - start(%s), end(%s)", this, toString(start).utf8().data(), toString(end).utf8().data());
</del><ins>+ LOG(MediaSource, "SourceBuffer::remove(%p) - start(%lf), end(%lf)", 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->openIfInEndedState();
</span><span class="cx">
</span><span class="cx"> // 4. Run the coded frame eviction algorithm.
</span><del>- m_private->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->isFull()) {
</del><ins>+ if (m_bufferFull) {
+ LOG(MediaSource, "SourceBuffer::appendBufferInternal(%p) - buffer full, failing with QUOTA_EXCEEDED_ERR error", 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() > this->maximumBufferSize())
+ m_bufferFull = true;
+
+ LOG(Media, "SourceBuffer::sourceBufferPrivateAppendComplete(%p) - buffered = %s", this, toString(m_buffered->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->decodeTime() < b.second->decodeTime();
</span><span class="cx"> }
</span><span class="cx">
</span><del>-static PassRefPtr<TimeRanges> removeSamplesFromTrackBuffer(const DecodeOrderSampleMap::MapType& samples, SourceBuffer::TrackBuffer& trackBuffer)
</del><ins>+static PassRefPtr<TimeRanges> removeSamplesFromTrackBuffer(const DecodeOrderSampleMap::MapType& samples, SourceBuffer::TrackBuffer& trackBuffer, const SourceBuffer* buffer, const char* logPrefix)
</ins><span class="cx"> {
</span><ins>+#if !LOG_DISABLED
+ double earliestSample = std::numeric_limits<double>::infinity();
+ double latestSample = 0;
+ size_t bytesRemoved = 0;
+#else
+ UNUSED_PARAM(logPrefix);
+ UNUSED_PARAM(buffer);
+#endif
+
</ins><span class="cx"> RefPtr<TimeRanges> 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& decodeKey = sampleIt.first;
</span><ins>+#if !LOG_DISABLED
+ size_t startBufferSize = trackBuffer.samples.sizeInBytes();
+#endif
+
</ins><span class="cx"> RefPtr<MediaSample>& sample = sampleIt.second;
</span><ins>+ LOG(MediaSource, "SourceBuffer::%s(%p) - removing sample(%s)", 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->presentationTime().toDouble();
</span><span class="cx"> double endTime = startTime + (sample->duration() + microsecond).toDouble();
</span><span class="cx"> erasedRanges->add(startTime, endTime);
</span><ins>+
+#if !LOG_DISABLED
+ bytesRemoved += startBufferSize - trackBuffer.samples.sizeInBytes();
+ if (startTime < earliestSample)
+ earliestSample = startTime;
+ if (endTime > latestSample)
+ latestSample = endTime;
+#endif
</ins><span class="cx"> }
</span><ins>+
+#if !LOG_DISABLED
+ if (bytesRemoved)
+ LOG(MediaSource, "SourceBuffer::%s(%p) removed %zu bytes, start(%lf), end(%lf)", 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<TimeRanges> erasedRanges = removeSamplesFromTrackBuffer(erasedSamples, trackBuffer);
</del><ins>+ RefPtr<TimeRanges> erasedRanges = removeSamplesFromTrackBuffer(erasedSamples, trackBuffer, this, "removeCodedFrames");
</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->ranges());
- if (possiblyEnqueuedRanges.length())
- trackBuffer.needsReenqueueing = true;
</del><ins>+ if (currentMediaTime < trackBuffer.lastEnqueuedPresentationTime) {
+ PlatformTimeRanges possiblyEnqueuedRanges(currentMediaTime, trackBuffer.lastEnqueuedPresentationTime);
+ possiblyEnqueuedRanges.intersectWith(erasedRanges->ranges());
+ if (possiblyEnqueuedRanges.length())
+ trackBuffer.needsReenqueueing = true;
+ }
</ins><span class="cx">
</span><span class="cx"> erasedRanges->invert();
</span><span class="cx"> m_buffered->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, "SourceBuffer::removeCodedFrames(%p) - buffered = %s", this, toString(m_buffered->ranges()).utf8().data());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void SourceBuffer::removeTimerFired(Timer<SourceBuffer>*)
</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->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->currentTime());
+ MediaTime maximumRangeEnd = currentTime - thirtySeconds;
+
+#if !LOG_DISABLED
+ LOG(MediaSource, "SourceBuffer::evictCodedFrames(%p) - currentTime = %lf, require %zu bytes, maximum buffer size is %zu", this, m_source->currentTime(), extraMemoryCost() + newDataSize, maximumBufferSize);
+ size_t initialBufferedSize = extraMemoryCost();
+#endif
+
+ MediaTime rangeStart = MediaTime::zeroTime();
+ MediaTime rangeEnd = rangeStart + thirtySeconds;
+ while (rangeStart < 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 < maximumBufferSize) {
+ m_bufferFull = false;
+ break;
+ }
+
+ rangeStart += thirtySeconds;
+ rangeEnd += thirtySeconds;
+ }
+
+ if (!m_bufferFull) {
+ LOG(MediaSource, "SourceBuffer::evictCodedFrames(%p) - evicted %zu bytes", 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->ranges();
+ size_t currentTimeRange = buffered.find(currentTime);
+ if (currentTimeRange == notFound || currentTimeRange == buffered.length() - 1) {
+ LOG(MediaSource, "SourceBuffer::evictCodedFrames(%p) - evicted %zu bytes but FAILED to free enough", this, initialBufferedSize - extraMemoryCost());
+ return;
+ }
+
+ MediaTime minimumRangeStart = currentTime + thirtySeconds;
+
+ rangeEnd = MediaTime::createWithDouble(m_source->duration());
+ rangeStart = rangeEnd - thirtySeconds;
+ while (rangeStart > 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 < maximumBufferSize) {
+ m_bufferFull = false;
+ break;
+ }
+
+ rangeStart -= thirtySeconds;
+ rangeEnd -= thirtySeconds;
+ }
+
+ LOG(MediaSource, "SourceBuffer::evictCodedFrames(%p) - evicted %zu bytes%s", this, initialBufferedSize - extraMemoryCost(), m_bufferFull ? "" : " but FAILED to free enough");
+}
+
+size_t SourceBuffer::maximumBufferSize() const
+{
+ if (isRemoved())
+ return 0;
+
+ HTMLMediaElement* element = m_source->mediaElement();
+ if (!element)
+ return 0;
+
+ return element->maximumSourceBufferSize(*this);
+}
+
</ins><span class="cx"> const AtomicString& SourceBuffer::decodeError()
</span><span class="cx"> {
</span><span class="cx"> static NeverDestroyed<AtomicString> decode("decode", 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<TimeRanges> erasedRanges = removeSamplesFromTrackBuffer(dependentSamples, trackBuffer);
-#if !LOG_DISABLED
- for (auto& samplePair : dependentSamples)
- LOG(MediaSource, "SourceBuffer::sourceBufferPrivateDidReceiveSample(%p) - removing sample(%s)", this, toString(*samplePair.second).utf8().data());
-#endif
</del><ins>+ RefPtr<TimeRanges> erasedRanges = removeSamplesFromTrackBuffer(dependentSamples, trackBuffer, this, "sourceBufferPrivateDidReceiveSample");
</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->currentTime());
</span><del>- PlatformTimeRanges possiblyEnqueuedRanges(currentMediaTime, trackBuffer.lastEnqueuedPresentationTime);
- possiblyEnqueuedRanges.intersectWith(erasedRanges->ranges());
- if (possiblyEnqueuedRanges.length())
- trackBuffer.needsReenqueueing = true;
</del><ins>+ if (currentMediaTime < trackBuffer.lastEnqueuedPresentationTime) {
+ PlatformTimeRanges possiblyEnqueuedRanges(currentMediaTime, trackBuffer.lastEnqueuedPresentationTime);
+ possiblyEnqueuedRanges.intersectWith(erasedRanges->ranges());
+ if (possiblyEnqueuedRanges.length())
+ trackBuffer.needsReenqueueing = true;
+ }
</ins><span class="cx">
</span><span class="cx"> erasedRanges->invert();
</span><span class="cx"> m_buffered->intersectWith(*erasedRanges.get());
</span><span class="lines">@@ -1262,16 +1410,26 @@
</span><span class="cx"> m_source->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 && m_audioTracks->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 && m_videoTracks->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->currentTime());
</span><ins>+ MediaTime duration = MediaTime::createWithDouble(m_source->duration());
+ if (currentTime >= duration)
+ return true;
+
</ins><span class="cx"> std::unique_ptr<PlatformTimeRanges> ranges = bufferedAccountingForEndOfStream();
</span><span class="cx"> return abs(ranges->nearest(currentTime) - currentTime) <= 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->currentTime());
</span><ins>+ MediaTime duration = MediaTime::createWithDouble(m_source->duration());
+ if (currentTime >= duration)
+ return true;
+
</ins><span class="cx"> MediaTime nearest = ranges->nearest(currentTime);
</span><span class="cx"> if (abs(nearest - currentTime) > 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->end(found);
</span><del>- MediaTime duration = MediaTime::createWithDouble(m_source->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 < 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& 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->extraMemoryCost();
</ins><span class="cx"> if (extraMemoryCost < 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& SourceBuffer::document() const
+{
+ ASSERT(scriptExecutionContext()->isDocument());
+ return *static_cast<Document*>(scriptExecutionContext());
+}
+
</ins><span class="cx"> } // namespace WebCore
</span><span class="cx">
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebCoreModulesmediasourceSourceBufferh"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/Modules/mediasource/SourceBuffer.h (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/Modules/mediasource/SourceBuffer.h        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/Modules/mediasource/SourceBuffer.h        2014-08-19 23:26:50 UTC (rev 172778)
</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& 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&, AtomicString trackID, const MediaTime&);
</span><span class="cx"> void provideMediaData(TrackBuffer&, 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<SourceBuffer>*);
</span><span class="cx"> void removeCodedFrames(const MediaTime& start, const MediaTime& 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<PlatformTimeRanges> 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<unsigned char> m_pendingAppendData;
</span><span class="cx"> Timer<SourceBuffer> 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<AtomicString, TrackBuffer> m_trackBufferMap;
</span><del>- bool m_receivedFirstInitializationSegment;
</del><span class="cx"> RefPtr<TimeRanges> 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<SourceBuffer> 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="branchessafari6001branchSourceWebCorehtmlHTMLMediaElementcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaElement.cpp (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaElement.cpp        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaElement.cpp        2014-08-19 23:26:50 UTC (rev 172778)
</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, "HTMLMediaElement::refreshCachedTime - caching time %f", 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& buffer) const
+{
+ return m_mediaSession->maximumMediaSourceBufferSize(buffer);
+}
+#endif
+
</ins><span class="cx"> void HTMLMediaElement::pausePlayback()
</span><span class="cx"> {
</span><span class="cx"> LOG(Media, "HTMLMediaElement::pausePlayback - paused = %s", boolString(paused()));
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebCorehtmlHTMLMediaElementh"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaElement.h (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaElement.h        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaElement.h        2014-08-19 23:26:50 UTC (rev 172778)
</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&) const;
</ins><span class="cx"> #endif
</span><span class="cx">
</span><span class="cx"> #if ENABLE(ENCRYPTED_MEDIA)
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebCorehtmlHTMLMediaSessioncpp"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaSession.cpp (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaSession.cpp        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaSession.cpp        2014-08-19 23:26:50 UTC (rev 172778)
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx"> #include "MediaSessionManager.h"
</span><span class="cx"> #include "Page.h"
</span><span class="cx"> #include "ScriptController.h"
</span><ins>+#include "SourceBuffer.h"
</ins><span class="cx">
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx"> #include "AudioSession.h"
</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& 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->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<size_t>(maximum * bufferBudgetPercentageForAudio);
+ if (buffer.hasVideo())
+ bufferSize += static_cast<size_t>(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="branchessafari6001branchSourceWebCorehtmlHTMLMediaSessionh"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaSession.h (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaSession.h        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/html/HTMLMediaSession.h        2014-08-19 23:26:50 UTC (rev 172778)
</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&) const;
+#endif
+
</ins><span class="cx"> private:
</span><span class="cx"> BehaviorRestrictions m_restrictions;
</span><span class="cx"> };
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebCorepageSettingsin"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/page/Settings.in (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/page/Settings.in        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/page/Settings.in        2014-08-19 23:26:50 UTC (rev 172778)
</span><span class="lines">@@ -228,3 +228,7 @@
</span><span class="cx"> # Allow clients to permit navigation to an invalid URL. Some apps may use invalid URLs
</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><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></pre></div>
<a id="branchessafari6001branchSourceWebCoreplatformgraphicsPlatformTimeRangescpp"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/platform/graphics/PlatformTimeRanges.cpp        2014-08-19 23:26:50 UTC (rev 172778)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> #include "PlatformTimeRanges.h"
</span><span class="cx">
</span><span class="cx"> #include <math.h>
</span><ins>+#include <wtf/PrintStream.h>
</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 < 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& out) const
+{
+ if (!length())
+ return;
+
+ for (size_t i = 0; i < length(); ++i)
+ out.print("[", start(i), "..", end(i), "] ");
</ins><span class="cx"> }
</span><ins>+
+}
</ins></span></pre></div>
<a id="branchessafari6001branchSourceWebCoreplatformgraphicsPlatformTimeRangesh"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/platform/graphics/PlatformTimeRanges.h (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/platform/graphics/PlatformTimeRanges.h        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/platform/graphics/PlatformTimeRanges.h        2014-08-19 23:26:50 UTC (rev 172778)
</span><span class="lines">@@ -32,6 +32,10 @@
</span><span class="cx"> #include <wtf/RefCounted.h>
</span><span class="cx"> #include <wtf/Vector.h>
</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&) const;
+
</ins><span class="cx"> private:
</span><span class="cx"> PlatformTimeRanges& copy(const PlatformTimeRanges&);
</span><span class="cx">
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebCoreplatformgraphicsSourceBufferPrivateh"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/platform/graphics/SourceBufferPrivate.h (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/platform/graphics/SourceBufferPrivate.h        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/platform/graphics/SourceBufferPrivate.h        2014-08-19 23:26:50 UTC (rev 172778)
</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<RefPtr<MediaSample>>, AtomicString) { }
</span><span class="cx"> virtual void enqueueSample(PassRefPtr<MediaSample>, AtomicString) { }
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCh"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h        2014-08-19 23:26:50 UTC (rev 172778)
</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<RefPtr<MediaSample>>, AtomicString trackID) override;
</span><span class="cx"> virtual void enqueueSample(PassRefPtr<MediaSample>, AtomicString trackID) override;
</span><span class="cx"> virtual bool isReadyForMoreSamples(AtomicString trackID) override;
</span></span></pre></div>
<a id="branchessafari6001branchSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCmm"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm        2014-08-19 23:26:50 UTC (rev 172778)
</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, "SourceBufferPrivateAVFObjC::processCodedFrame(%p) - size change detected: {width=%lf, height=%lf", formatSize.width(), formatSize.height());
</del><ins>+ LOG(MediaSource, "SourceBufferPrivateAVFObjC::processCodedFrame(%p) - size change detected: {width=%lf, height=%lf}", formatSize.width(), formatSize.height());
</ins><span class="cx"> m_cachedSize = formatSize;
</span><span class="cx"> if (m_mediaSource)
</span><span class="cx"> m_mediaSource->player()->sizeChanged();
</span><span class="lines">@@ -779,18 +779,6 @@
</span><span class="cx"> m_mediaSource->player()->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="branchessafari6001branchSourceWebCoreplatformmockmediasourceMockSourceBufferPrivatecpp"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp        2014-08-19 23:26:50 UTC (rev 172778)
</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->player()->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="branchessafari6001branchSourceWebCoreplatformmockmediasourceMockSourceBufferPrivateh"></a>
<div class="modfile"><h4>Modified: branches/safari-600.1-branch/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.h (172777 => 172778)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.1-branch/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.h        2014-08-19 23:25:37 UTC (rev 172777)
+++ branches/safari-600.1-branch/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.h        2014-08-19 23:26:50 UTC (rev 172778)
</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<RefPtr<MediaSample>>, AtomicString) override { }
</span><span class="cx"> virtual void enqueueSample(PassRefPtr<MediaSample>, AtomicString) override;
</span></span></pre>
</div>
</div>
</body>
</html>