<!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>[211746] trunk</title>
</head>
<body>

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

<h3>Log Message</h3>
<pre>Playback stalls when a SourceBuffer append causes frame eviction
https://bugs.webkit.org/show_bug.cgi?id=167834

Reviewed by Eric Carlson.

PerformanceTests:

Add an in-page performance test measuring the amount of time required
to append a large amount of media data to a SourceBuffer, and then to
completely remove that data 30s at a time.

Add a microbenchmark for MediaTime which measures the amount of time
required to create a 1M entry std::map and traverse the map 1M times.

* Media/MSERemoveCodedFrames.html: Added.
* Media/media-source-loader.js:
(MediaSourceLoader.prototype.get duration):
* MediaTime/Configurations/Base.xcconfig: Added.
* MediaTime/Configurations/DebugRelease.xcconfig: Added.
* MediaTime/Makefile: Added.
* MediaTime/MediaTime.xcodeproj/project.pbxproj: Added.
* MediaTime/main.cpp: Added.
(performTest):
(test):
(main):
* Skipped:

Source/WebCore:

Test: PerformanceTests/Media/MSERemoveCodedFrames.html

Optimize searching through SampleMap by presentationTime.

Many of the methods exposed by PresentationOrderSampleMap used the bare  std::equal_range,
lower_bound, or upper_bound methods. Unlike those methods exposed on std::map, the bare
search methods perform a linear O(n) search, rather than a the binary O(log(n)) search used
by std::map. Rewrite those methods using the bare methods in terms of the std::map search
methods.

Drive-by fix: rename findSampleOnOrAfterPresentationTime to
findSampleStartingOnOrAfterPresentationTime to make the behavior of the method more
explicit.

* Modules/mediasource/SampleMap.cpp:
(WebCore::PresentationOrderSampleMap::findSampleContainingPresentationTime):
(WebCore::PresentationOrderSampleMap::findSampleStartingOnOrAfterPresentationTime):
(WebCore::PresentationOrderSampleMap::reverseFindSampleBeforePresentationTime):
(WebCore::DecodeOrderSampleMap::findSyncSampleAfterPresentationTime):
(WebCore::PresentationOrderSampleMap::findSamplesBetweenPresentationTimes):
(WebCore::PresentationOrderSampleMap::findSamplesWithinPresentationRange):
(WebCore::PresentationOrderSampleMap::findSampleOnOrAfterPresentationTime): Deleted.
* Modules/mediasource/SampleMap.h:
(WebCore::PresentationOrderSampleMap::begin):
(WebCore::PresentationOrderSampleMap::end):
(WebCore::PresentationOrderSampleMap::rbegin):
(WebCore::PresentationOrderSampleMap::rend):
(WebCore::DecodeOrderSampleMap::begin):
(WebCore::DecodeOrderSampleMap::end):
(WebCore::DecodeOrderSampleMap::rbegin):
(WebCore::DecodeOrderSampleMap::rend):
(WebCore::SampleMap::SampleMap):
(WebCore::SampleMap::sizeInBytes):
(WebCore::SampleMap::decodeOrder):
(WebCore::SampleMap::presentationOrder):
* Modules/mediasource/SourceBuffer.cpp:
(WebCore::removeSamplesFromTrackBuffer):
(WebCore::SourceBuffer::removeCodedFrames):
(WebCore::SourceBuffer::reenqueueMediaForTime):
* WebCore.xcodeproj/project.pbxproj:

Source/WTF:

Optimize the MediaTime class; specifically the compare() method. The class only
needs 6 bits to store the TimeFlags, so make that a uint8_t rather than uint32_t.
The implementation is slightly simpler if the TimeScale is unsigned, so make that
a uint32_t rather than int32_t. Inline the comparison operators. Optimize the equality
comparison by bitwise-and'ing the flags together and masking the result. Optimize for
common comparison scenarios (equal timeScales, equal timeValues(), etc.). Attempt the
mathematically simpler simpler method for comparing ratios, and only fall back to the
complex method if the results of multiplying the timeScale by the timeValue overflows.

* wtf/MediaTime.cpp:
(WTF::greatestCommonDivisor):
(WTF::leastCommonMultiple):
(WTF::signum):
(WTF::MediaTime::MediaTime):
(WTF::MediaTime::createWithFloat):
(WTF::MediaTime::createWithDouble):
(WTF::MediaTime::operator+):
(WTF::MediaTime::operator-):
(WTF::MediaTime::operator!):
(WTF::MediaTime::operator bool):
(WTF::MediaTime::compare):
(WTF::MediaTime::setTimeScale):
(WTF::abs):
(WTF::MediaTime::operator&lt;): Deleted.
(WTF::MediaTime::operator&gt;): Deleted.
(WTF::MediaTime::operator!=): Deleted.
(WTF::MediaTime::operator==): Deleted.
(WTF::MediaTime::operator&gt;=): Deleted.
(WTF::MediaTime::operator&lt;=): Deleted.
* wtf/MediaTime.h:

Tools:

Add new correctness tests for the Webcore::SampleMap class. Add additional subtests
for the WTF::MediaTime class.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WTF/MediaTime.cpp:
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WebCore/SampleMap.cpp: Added.
(WTF::operator&lt;&lt;):
(TestWebKitAPI::TestSample::create):
(TestWebKitAPI::TestSample::TestSample):
(TestWebKitAPI::TEST_F):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkPerformanceTestsChangeLog">trunk/PerformanceTests/ChangeLog</a></li>
<li><a href="#trunkPerformanceTestsMediamediasourceloaderjs">trunk/PerformanceTests/Media/media-source-loader.js</a></li>
<li><a href="#trunkPerformanceTestsSkipped">trunk/PerformanceTests/Skipped</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfMediaTimecpp">trunk/Source/WTF/wtf/MediaTime.cpp</a></li>
<li><a href="#trunkSourceWTFwtfMediaTimeh">trunk/Source/WTF/wtf/MediaTime.h</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesmediasourceSampleMapcpp">trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesmediasourceSampleMaph">trunk/Source/WebCore/Modules/mediasource/SampleMap.h</a></li>
<li><a href="#trunkSourceWebCoreModulesmediasourceSourceBuffercpp">trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj">trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWTFMediaTimecpp">trunk/Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkPerformanceTestsMediaMSERemoveCodedFrameshtml">trunk/PerformanceTests/Media/MSERemoveCodedFrames.html</a></li>
<li>trunk/PerformanceTests/MediaTime/</li>
<li>trunk/PerformanceTests/MediaTime/Configurations/</li>
<li><a href="#trunkPerformanceTestsMediaTimeConfigurationsBasexcconfig">trunk/PerformanceTests/MediaTime/Configurations/Base.xcconfig</a></li>
<li><a href="#trunkPerformanceTestsMediaTimeConfigurationsDebugReleasexcconfig">trunk/PerformanceTests/MediaTime/Configurations/DebugRelease.xcconfig</a></li>
<li><a href="#trunkPerformanceTestsMediaTimeMakefile">trunk/PerformanceTests/MediaTime/Makefile</a></li>
<li>trunk/PerformanceTests/MediaTime/MediaTime.xcodeproj/</li>
<li><a href="#trunkPerformanceTestsMediaTimeMediaTimexcodeprojprojectpbxproj">trunk/PerformanceTests/MediaTime/MediaTime.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkPerformanceTestsMediaTimemaincpp">trunk/PerformanceTests/MediaTime/main.cpp</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebCoreSampleMapcpp">trunk/Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkPerformanceTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/ChangeLog (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/ChangeLog        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/PerformanceTests/ChangeLog        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -1,3 +1,30 @@
</span><ins>+2017-02-06  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        Playback stalls when a SourceBuffer append causes frame eviction
+        https://bugs.webkit.org/show_bug.cgi?id=167834
+
+        Reviewed by Eric Carlson.
+
+        Add an in-page performance test measuring the amount of time required
+        to append a large amount of media data to a SourceBuffer, and then to
+        completely remove that data 30s at a time.
+
+        Add a microbenchmark for MediaTime which measures the amount of time
+        required to create a 1M entry std::map and traverse the map 1M times.
+
+        * Media/MSERemoveCodedFrames.html: Added.
+        * Media/media-source-loader.js:
+        (MediaSourceLoader.prototype.get duration):
+        * MediaTime/Configurations/Base.xcconfig: Added.
+        * MediaTime/Configurations/DebugRelease.xcconfig: Added.
+        * MediaTime/Makefile: Added.
+        * MediaTime/MediaTime.xcodeproj/project.pbxproj: Added.
+        * MediaTime/main.cpp: Added.
+        (performTest):
+        (test):
+        (main):
+        * Skipped:
+
</ins><span class="cx"> 2017-02-06  Saam Barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Make ARES-6 work from the CLI again
</span></span></pre></div>
<a id="trunkPerformanceTestsMediaMSERemoveCodedFrameshtml"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/Media/MSERemoveCodedFrames.html (0 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Media/MSERemoveCodedFrames.html                                (rev 0)
+++ trunk/PerformanceTests/Media/MSERemoveCodedFrames.html        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -0,0 +1,122 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;media-source-loader.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../resources/runner.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+var loader;
+var video;
+var longMediaSegment;
+
+function concatArrayBuffers() {
+    var byteLength = 0;
+    Array.prototype.forEach.call(arguments, arrayBuffer =&gt; {
+        if (!arrayBuffer.byteLength)
+            throw &quot;Not an ArrayBuffer!&quot;;
+        byteLength += arrayBuffer.byteLength;
+    });
+
+
+    var view = new Uint8Array(byteLength);
+    var offset = 0;
+    Array.prototype.forEach.call(arguments, arrayBuffer =&gt; {
+        view.set(new Uint8Array(arrayBuffer), offset);
+        offset += arrayBuffer.byteLength;
+    });
+    return view.buffer;
+}
+
+function concatMediaData() {
+    return new Promise((resolve, reject) =&gt; {
+        var segments = new Array(100);
+        segments.fill(loader.everyMediaSegment);
+        longMediaSegment = concatArrayBuffers.apply(this, segments);
+        resolve(longMediaSegment);
+    });
+}
+
+window.addEventListener('load', () =&gt; {
+    PerfTestRunner.prepareToMeasureValuesAsync({
+        unit: 'ms',
+        done: function () {
+            if (video) {
+                video.src = null;
+                video.load();
+            }
+        }
+    });
+
+    loader = new MediaSourceLoader('test-fragmented-video.json');
+    loader.loadMediaData().then(concatMediaData).then(runTest);
+});
+
+function remove30SecondsAtATimeTillEmpty(sourceBuffer) {
+    return new Promise(resolve =&gt; {
+        var removeNext30Seconds = () =&gt; {
+            var start = sourceBuffer.buffered.start(0);
+            sourceBuffer.remove(start, start + 30)
+        }
+        sourceBuffer.onupdate = () =&gt; {
+            if (sourceBuffer.buffered.length == 0 || sourceBuffer.buffered.start(0) - sourceBuffer.buffered.end(0) == 0) {
+                sourceBuffer.onupdate = null;
+                resolve();
+                return;
+            }
+            
+            removeNext30Seconds();
+        };
+        removeNext30Seconds();
+    });
+}
+
+function runTest() {   
+    video =  document.createElement('video');
+
+    loadMediaDataIntoVideo(video).then(sourceBuffer =&gt; {
+        startTime = PerfTestRunner.now();
+        return remove30SecondsAtATimeTillEmpty(sourceBuffer);
+    }).then(() =&gt; {
+        if (PerfTestRunner.measureValueAsync(PerfTestRunner.now() - startTime))
+            setTimeout(runTest, 0);
+    });
+}
+
+function loadMediaDataIntoVideo(video, segmentCount) {
+    return new Promise((resolve, reject) =&gt; {
+        var source = new MediaSource();
+        source.onsourceopen = () =&gt; {
+            source.onsourceopen = null;
+            source.duration = loader.duration * 100; 
+            var currentMediaSegment = 0;
+            var sourceBuffer = source.addSourceBuffer(loader.type);
+            sourceBuffer.mode = 'sequence';
+            sourceBuffer.appendBuffer(loader.initSegment);
+
+            var appendedMediaSegment = false;
+            sourceBuffer.onupdate = () =&gt; {
+
+                if (appendedMediaSegment) {
+                    if (source.readyState !== 'ended') {
+                        source.endOfStream();
+                        sourceBuffer.onupdate = null;
+                        sourceBuffer.onerror = null;
+                        resolve(sourceBuffer);
+                    }
+                    return;
+                }
+
+                sourceBuffer.appendBuffer(longMediaSegment);
+                appendedMediaSegment = true;
+            };
+            sourceBuffer.onerror = error =&gt; {
+                reject(error);
+            };
+        };
+        video.src = URL.createObjectURL(source);
+    });
+}
+&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkPerformanceTestsMediamediasourceloaderjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Media/media-source-loader.js (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Media/media-source-loader.js        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/PerformanceTests/Media/media-source-loader.js        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -87,7 +87,9 @@
</span><span class="cx"> 
</span><span class="cx">     get duration()
</span><span class="cx">     {
</span><del>-        return this._manifest ? this._manifest.duration : 0
</del><ins>+        if (!this._manifest)
+            return 0;
+        return this._manifest.media.reduce((duration, media) =&gt; { return duration + media.duration }, 0);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     get initSegment()
</span></span></pre></div>
<a id="trunkPerformanceTestsMediaTimeConfigurationsBasexcconfig"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/MediaTime/Configurations/Base.xcconfig (0 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/MediaTime/Configurations/Base.xcconfig                                (rev 0)
+++ trunk/PerformanceTests/MediaTime/Configurations/Base.xcconfig        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -0,0 +1,119 @@
</span><ins>+// Copyright (C) 2009, 2010, 2011, 2013 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+#include &quot;../../../../Internal/Configurations/HaveInternalSDK.xcconfig&quot;
+
+USE_INTERNAL_SDK = $(USE_INTERNAL_SDK_$(CONFIGURATION));
+USE_INTERNAL_SDK_Production = YES;
+USE_INTERNAL_SDK_Debug = $(HAVE_INTERNAL_SDK);
+USE_INTERNAL_SDK_Release = $(HAVE_INTERNAL_SDK);
+
+CLANG_CXX_LANGUAGE_STANDARD = gnu++14;
+CLANG_CXX_LIBRARY = libc++;
+CLANG_WARN_BOOL_CONVERSION = YES;
+CLANG_WARN_CONSTANT_CONVERSION = YES;
+CLANG_WARN_CXX0X_EXTENSIONS = NO;
+CLANG_WARN_EMPTY_BODY = YES;
+CLANG_WARN_ENUM_CONVERSION = YES;
+CLANG_WARN_INFINITE_RECURSION = YES;
+CLANG_WARN_INT_CONVERSION = YES;
+CLANG_WARN_SUSPICIOUS_MOVE = YES;
+CLANG_WARN_UNREACHABLE_CODE = YES;
+CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+COMBINE_HIDPI_IMAGES = NO;
+DEBUG_INFORMATION_FORMAT = dwarf-with-dsym;
+ENABLE_STRICT_OBJC_MSGSEND = YES;
+GCC_C_LANGUAGE_STANDARD = gnu99;
+GCC_DEBUGGING_SYMBOLS = default;
+GCC_DYNAMIC_NO_PIC = NO;
+GCC_ENABLE_CPP_EXCEPTIONS = NO;
+GCC_ENABLE_CPP_RTTI = NO;
+GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+GCC_ENABLE_SYMBOL_SEPARATION = NO;
+GCC_FAST_OBJC_DISPATCH = YES;
+GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
+GCC_NO_COMMON_BLOCKS = YES;
+GCC_OBJC_CALL_CXX_CDTORS = YES;
+GCC_PRECOMPILE_PREFIX_HEADER = YES;
+GCC_PREPROCESSOR_DEFINITIONS = $(DEBUG_DEFINES) $(inherited);
+GCC_STRICT_ALIASING = YES;
+GCC_THREADSAFE_STATICS = NO;
+GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+// FIXME: &lt;http://webkit.org/b/107093&gt; WTF should build with -Wshorten-64-to-32
+GCC_WARN_64_TO_32_BIT_CONVERSION = $(GCC_WARN_64_TO_32_BIT_CONVERSION_$(CURRENT_ARCH));
+GCC_WARN_64_TO_32_BIT_CONVERSION_ = YES;
+GCC_WARN_64_TO_32_BIT_CONVERSION_armv7 = YES;
+GCC_WARN_64_TO_32_BIT_CONVERSION_armv7k = YES;
+GCC_WARN_64_TO_32_BIT_CONVERSION_armv7s = YES;
+GCC_WARN_64_TO_32_BIT_CONVERSION_arm64 = NO;
+GCC_WARN_64_TO_32_BIT_CONVERSION_i386 = YES;
+GCC_WARN_64_TO_32_BIT_CONVERSION_x86_64 = NO;
+GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+GCC_WARN_ABOUT_RETURN_TYPE = YES;
+GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
+GCC_WARN_SIGN_COMPARE = YES;
+GCC_WARN_UNDECLARED_SELECTOR = YES;
+GCC_WARN_UNINITIALIZED_AUTOS = YES;
+GCC_WARN_UNUSED_FUNCTION = YES;
+GCC_WARN_UNUSED_VARIABLE = YES;
+PREBINDING = NO;
+WARNING_CFLAGS = -Wall -Wextra -Wcast-qual -Wchar-subscripts -Wextra-tokens -Wformat=2 -Winit-self -Wmissing-format-attribute -Wmissing-noreturn -Wpacked -Wpointer-arith -Wredundant-decls -Wundef -Wwrite-strings -Wexit-time-destructors -Wglobal-constructors -Wtautological-compare -Wimplicit-fallthrough;
+HEADER_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR)/usr/local/include $(DSTROOT)/usr/local/include icu $(HEADER_SEARCH_PATHS);
+
+TARGET_MAC_OS_X_VERSION_MAJOR = $(TARGET_MAC_OS_X_VERSION_MAJOR$(MACOSX_DEPLOYMENT_TARGET:suffix:identifier));
+TARGET_MAC_OS_X_VERSION_MAJOR_10 = 101000;
+TARGET_MAC_OS_X_VERSION_MAJOR_11 = 101100;
+TARGET_MAC_OS_X_VERSION_MAJOR_12 = 101200;
+TARGET_MAC_OS_X_VERSION_MAJOR_13 = 101300;
+
+SUPPORTED_PLATFORMS = iphoneos iphonesimulator macosx appletvos appletvsimulator watchos watchsimulator;
+
+JAVASCRIPTCORE_FRAMEWORKS_DIR = $(SYSTEM_LIBRARY_DIR)/Frameworks;
+
+// DEBUG_DEFINES, GCC_OPTIMIZATION_LEVEL, STRIP_INSTALLED_PRODUCT and DEAD_CODE_STRIPPING vary between the debug and normal variants.
+// We set up the values for each variant here, and have the Debug configuration in the Xcode project use the _debug variant.
+DEBUG_DEFINES_debug = ;
+DEBUG_DEFINES_normal = NDEBUG;
+DEBUG_DEFINES = $(DEBUG_DEFINES_$(CURRENT_VARIANT));
+
+GCC_OPTIMIZATION_LEVEL = $(GCC_OPTIMIZATION_LEVEL_$(CURRENT_VARIANT));
+GCC_OPTIMIZATION_LEVEL_normal = 3;
+GCC_OPTIMIZATION_LEVEL_debug = 0;
+
+STRIP_INSTALLED_PRODUCT = $(STRIP_INSTALLED_PRODUCT_$(CURRENT_VARIANT));
+STRIP_INSTALLED_PRODUCT_normal = YES;
+STRIP_INSTALLED_PRODUCT_debug = NO;
+
+DEAD_CODE_STRIPPING_debug = NO;
+DEAD_CODE_STRIPPING_normal = YES;
+DEAD_CODE_STRIPPING = $(DEAD_CODE_STRIPPING_$(CURRENT_VARIANT));
+
+SDKROOT = macosx.internal;
+
+OTHER_CFLAGS = $(ASAN_OTHER_CFLAGS);
+OTHER_CPLUSPLUSFLAGS = $(ASAN_OTHER_CPLUSPLUSFLAGS);
+OTHER_LDFLAGS = $(ASAN_OTHER_LDFLAGS);
</ins></span></pre></div>
<a id="trunkPerformanceTestsMediaTimeConfigurationsDebugReleasexcconfig"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/MediaTime/Configurations/DebugRelease.xcconfig (0 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/MediaTime/Configurations/DebugRelease.xcconfig                                (rev 0)
+++ trunk/PerformanceTests/MediaTime/Configurations/DebugRelease.xcconfig        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -0,0 +1,42 @@
</span><ins>+// Copyright (C) 2009, 2010, 2013 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+#include &quot;Base.xcconfig&quot;
+
+ARCHS = $(ARCHS_STANDARD_32_64_BIT);
+ONLY_ACTIVE_ARCH = YES;
+
+TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR);
+
+MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(PLATFORM_NAME)_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+MACOSX_DEPLOYMENT_TARGET_macosx_101000 = 10.10;
+MACOSX_DEPLOYMENT_TARGET_macosx_101100 = 10.11;
+MACOSX_DEPLOYMENT_TARGET_macosx_101200 = 10.12;
+MACOSX_DEPLOYMENT_TARGET_macosx_101300 = 10.13;
+
+GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
+DEBUG_INFORMATION_FORMAT = dwarf;
+
+SDKROOT = $(SDKROOT_$(USE_INTERNAL_SDK));
+SDKROOT_ = macosx;
+SDKROOT_YES = macosx.internal;
</ins></span></pre></div>
<a id="trunkPerformanceTestsMediaTimeMakefile"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/MediaTime/Makefile (0 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/MediaTime/Makefile                                (rev 0)
+++ trunk/PerformanceTests/MediaTime/Makefile        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+SCRIPTS_PATH ?= ../../Tools/Scripts
+include ../../Makefile.shared
</ins></span></pre></div>
<a id="trunkPerformanceTestsMediaTimeMediaTimexcodeprojprojectpbxproj"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/MediaTime/MediaTime.xcodeproj/project.pbxproj (0 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/MediaTime/MediaTime.xcodeproj/project.pbxproj                                (rev 0)
+++ trunk/PerformanceTests/MediaTime/MediaTime.xcodeproj/project.pbxproj        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -0,0 +1,256 @@
</span><ins>+// !$*UTF8*$!
+{
+        archiveVersion = 1;
+        classes = {
+        };
+        objectVersion = 46;
+        objects = {
+
+/* Begin PBXBuildFile section */
+                CDB099E11E4308470039E198 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDB099E01E4308470039E198 /* main.cpp */; };
+                CDB099E91E4308700039E198 /* libWTF.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CDB099E81E4308700039E198 /* libWTF.a */; };
+                CDB099EB1E430B250039E198 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDB099EA1E430B250039E198 /* CoreFoundation.framework */; };
+                CDB099ED1E430B440039E198 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDB099EC1E430B440039E198 /* Foundation.framework */; };
+                CDB099EF1E430B550039E198 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CDB099EE1E430B550039E198 /* libicucore.dylib */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+                CDB099DB1E4308470039E198 /* CopyFiles */ = {
+                        isa = PBXCopyFilesBuildPhase;
+                        buildActionMask = 2147483647;
+                        dstPath = /usr/share/man/man1/;
+                        dstSubfolderSpec = 0;
+                        files = (
+                        );
+                        runOnlyForDeploymentPostprocessing = 1;
+                };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+                CD836CFE1E43BDB4009F8091 /* Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = &quot;&lt;group&gt;&quot;; };
+                CD836D001E43BDB4009F8091 /* DebugRelease.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DebugRelease.xcconfig; sourceTree = &quot;&lt;group&gt;&quot;; };
+                CDB099DD1E4308470039E198 /* MediaTime */ = {isa = PBXFileReference; explicitFileType = &quot;compiled.mach-o.executable&quot;; includeInIndex = 0; path = MediaTime; sourceTree = BUILT_PRODUCTS_DIR; };
+                CDB099E01E4308470039E198 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = ../../../../Testcases/MediaTimeTestcase/MediaTime/main.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                CDB099E81E4308700039E198 /* libWTF.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libWTF.a; path = ../../WebKit.git/OpenSource/WebKitBuild/Debug/libWTF.a; sourceTree = &quot;&lt;group&gt;&quot;; };
+                CDB099EA1E430B250039E198 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+                CDB099EC1E430B440039E198 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+                CDB099EE1E430B550039E198 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = &quot;compiled.mach-o.dylib&quot;; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+                CDB099DA1E4308470039E198 /* Frameworks */ = {
+                        isa = PBXFrameworksBuildPhase;
+                        buildActionMask = 2147483647;
+                        files = (
+                                CDB099EF1E430B550039E198 /* libicucore.dylib in Frameworks */,
+                                CDB099ED1E430B440039E198 /* Foundation.framework in Frameworks */,
+                                CDB099EB1E430B250039E198 /* CoreFoundation.framework in Frameworks */,
+                                CDB099E91E4308700039E198 /* libWTF.a in Frameworks */,
+                        );
+                        runOnlyForDeploymentPostprocessing = 0;
+                };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+                CD836CFD1E43BDB4009F8091 /* Configurations */ = {
+                        isa = PBXGroup;
+                        children = (
+                                CD836CFE1E43BDB4009F8091 /* Base.xcconfig */,
+                                CD836D001E43BDB4009F8091 /* DebugRelease.xcconfig */,
+                        );
+                        path = Configurations;
+                        sourceTree = &quot;&lt;group&gt;&quot;;
+                };
+                CDB099D41E4308470039E198 = {
+                        isa = PBXGroup;
+                        children = (
+                                CDB099E01E4308470039E198 /* main.cpp */,
+                                CD836CFD1E43BDB4009F8091 /* Configurations */,
+                                CDB099DE1E4308470039E198 /* Products */,
+                                CDB099E71E43086F0039E198 /* Frameworks */,
+                        );
+                        sourceTree = &quot;&lt;group&gt;&quot;;
+                };
+                CDB099DE1E4308470039E198 /* Products */ = {
+                        isa = PBXGroup;
+                        children = (
+                                CDB099DD1E4308470039E198 /* MediaTime */,
+                        );
+                        name = Products;
+                        sourceTree = &quot;&lt;group&gt;&quot;;
+                };
+                CDB099E71E43086F0039E198 /* Frameworks */ = {
+                        isa = PBXGroup;
+                        children = (
+                                CDB099EE1E430B550039E198 /* libicucore.dylib */,
+                                CDB099EC1E430B440039E198 /* Foundation.framework */,
+                                CDB099EA1E430B250039E198 /* CoreFoundation.framework */,
+                                CDB099E81E4308700039E198 /* libWTF.a */,
+                        );
+                        name = Frameworks;
+                        sourceTree = &quot;&lt;group&gt;&quot;;
+                };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+                CDB099DC1E4308470039E198 /* MediaTime */ = {
+                        isa = PBXNativeTarget;
+                        buildConfigurationList = CDB099E41E4308470039E198 /* Build configuration list for PBXNativeTarget &quot;MediaTime&quot; */;
+                        buildPhases = (
+                                CDB099D91E4308470039E198 /* Sources */,
+                                CDB099DA1E4308470039E198 /* Frameworks */,
+                                CDB099DB1E4308470039E198 /* CopyFiles */,
+                        );
+                        buildRules = (
+                        );
+                        dependencies = (
+                        );
+                        name = MediaTime;
+                        productName = MediaTimeTestcase;
+                        productReference = CDB099DD1E4308470039E198 /* MediaTime */;
+                        productType = &quot;com.apple.product-type.tool&quot;;
+                };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+                CDB099D51E4308470039E198 /* Project object */ = {
+                        isa = PBXProject;
+                        attributes = {
+                                LastUpgradeCheck = 0830;
+                                ORGANIZATIONNAME = &quot;Jeremy Noble&quot;;
+                                TargetAttributes = {
+                                        CDB099DC1E4308470039E198 = {
+                                                CreatedOnToolsVersion = 8.3;
+                                                DevelopmentTeam = G5UYP5CS7K;
+                                                ProvisioningStyle = Automatic;
+                                        };
+                                };
+                        };
+                        buildConfigurationList = CDB099D81E4308470039E198 /* Build configuration list for PBXProject &quot;MediaTime&quot; */;
+                        compatibilityVersion = &quot;Xcode 3.2&quot;;
+                        developmentRegion = English;
+                        hasScannedForEncodings = 0;
+                        knownRegions = (
+                                en,
+                        );
+                        mainGroup = CDB099D41E4308470039E198;
+                        productRefGroup = CDB099DE1E4308470039E198 /* Products */;
+                        projectDirPath = &quot;&quot;;
+                        projectRoot = &quot;&quot;;
+                        targets = (
+                                CDB099DC1E4308470039E198 /* MediaTime */,
+                        );
+                };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+                CDB099D91E4308470039E198 /* Sources */ = {
+                        isa = PBXSourcesBuildPhase;
+                        buildActionMask = 2147483647;
+                        files = (
+                                CDB099E11E4308470039E198 /* main.cpp in Sources */,
+                        );
+                        runOnlyForDeploymentPostprocessing = 0;
+                };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+                CDB099E21E4308470039E198 /* Debug */ = {
+                        isa = XCBuildConfiguration;
+                        baseConfigurationReference = CD836D001E43BDB4009F8091 /* DebugRelease.xcconfig */;
+                        buildSettings = {
+                                ALWAYS_SEARCH_USER_PATHS = YES;
+                                CLANG_CXX_LANGUAGE_STANDARD = &quot;c++0x&quot;;
+                                CLANG_CXX_LIBRARY = &quot;libc++&quot;;
+                                DEBUG_INFORMATION_FORMAT = dwarf;
+                                ENABLE_TESTABILITY = YES;
+                                GCC_DYNAMIC_NO_PIC = NO;
+                                GCC_NO_COMMON_BLOCKS = YES;
+                                GCC_OPTIMIZATION_LEVEL = 0;
+                                GCC_PREPROCESSOR_DEFINITIONS = (
+                                        &quot;DEBUG=1&quot;,
+                                        &quot;$(inherited)&quot;,
+                                );
+                                ONLY_ACTIVE_ARCH = YES;
+                        };
+                        name = Debug;
+                };
+                CDB099E31E4308470039E198 /* Release */ = {
+                        isa = XCBuildConfiguration;
+                        baseConfigurationReference = CD836D001E43BDB4009F8091 /* DebugRelease.xcconfig */;
+                        buildSettings = {
+                                ALWAYS_SEARCH_USER_PATHS = YES;
+                                CLANG_CXX_LANGUAGE_STANDARD = &quot;c++0x&quot;;
+                                CLANG_CXX_LIBRARY = &quot;libc++&quot;;
+                                DEBUG_INFORMATION_FORMAT = &quot;dwarf-with-dsym&quot;;
+                                GCC_NO_COMMON_BLOCKS = YES;
+                        };
+                        name = Release;
+                };
+                CDB099E51E4308470039E198 /* Debug */ = {
+                        isa = XCBuildConfiguration;
+                        buildSettings = {
+                                CLANG_CXX_LANGUAGE_STANDARD = &quot;c++14&quot;;
+                                DEVELOPMENT_TEAM = G5UYP5CS7K;
+                                PRODUCT_NAME = &quot;$(TARGET_NAME)&quot;;
+                        };
+                        name = Debug;
+                };
+                CDB099E61E4308470039E198 /* Release */ = {
+                        isa = XCBuildConfiguration;
+                        buildSettings = {
+                                CLANG_CXX_LANGUAGE_STANDARD = &quot;c++14&quot;;
+                                DEVELOPMENT_TEAM = G5UYP5CS7K;
+                                PRODUCT_NAME = &quot;$(TARGET_NAME)&quot;;
+                        };
+                        name = Release;
+                };
+                CDB099F01E4394540039E198 /* Control */ = {
+                        isa = XCBuildConfiguration;
+                        buildSettings = {
+                                ALWAYS_SEARCH_USER_PATHS = YES;
+                                CLANG_CXX_LANGUAGE_STANDARD = &quot;c++0x&quot;;
+                                CLANG_CXX_LIBRARY = &quot;libc++&quot;;
+                                DEBUG_INFORMATION_FORMAT = &quot;dwarf-with-dsym&quot;;
+                                GCC_NO_COMMON_BLOCKS = YES;
+                                HEADER_SEARCH_PATHS = /usr/local/include;
+                                LIBRARY_SEARCH_PATHS = /usr/local/lib;
+                        };
+                        name = Control;
+                };
+                CDB099F11E4394540039E198 /* Control */ = {
+                        isa = XCBuildConfiguration;
+                        buildSettings = {
+                                CLANG_CXX_LANGUAGE_STANDARD = &quot;c++14&quot;;
+                                DEVELOPMENT_TEAM = G5UYP5CS7K;
+                                PRODUCT_NAME = &quot;$(TARGET_NAME)&quot;;
+                        };
+                        name = Control;
+                };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+                CDB099D81E4308470039E198 /* Build configuration list for PBXProject &quot;MediaTime&quot; */ = {
+                        isa = XCConfigurationList;
+                        buildConfigurations = (
+                                CDB099E21E4308470039E198 /* Debug */,
+                                CDB099E31E4308470039E198 /* Release */,
+                                CDB099F01E4394540039E198 /* Control */,
+                        );
+                        defaultConfigurationIsVisible = 0;
+                        defaultConfigurationName = Release;
+                };
+                CDB099E41E4308470039E198 /* Build configuration list for PBXNativeTarget &quot;MediaTime&quot; */ = {
+                        isa = XCConfigurationList;
+                        buildConfigurations = (
+                                CDB099E51E4308470039E198 /* Debug */,
+                                CDB099E61E4308470039E198 /* Release */,
+                                CDB099F11E4394540039E198 /* Control */,
+                        );
+                        defaultConfigurationIsVisible = 0;
+                        defaultConfigurationName = Release;
+                };
+/* End XCConfigurationList section */
+        };
+        rootObject = CDB099D51E4308470039E198 /* Project object */;
+}
</ins></span></pre></div>
<a id="trunkPerformanceTestsMediaTimemaincpp"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/MediaTime/main.cpp (0 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/MediaTime/main.cpp                                (rev 0)
+++ trunk/PerformanceTests/MediaTime/main.cpp        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -0,0 +1,94 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &lt;chrono&gt;
+#include &lt;random&gt;
+#include &lt;set&gt;
+#include &lt;wtf/MediaTime.h&gt;
+
+using namespace std;
+using namespace std::chrono;
+
+static const size_t setSize = 100000;
+
+void performTest(const char* name, function&lt;void()&gt; test)
+{
+    vector&lt;double&gt; runtimes(21);
+    for (auto&amp; runtime : runtimes) {
+        auto start = steady_clock::now();
+        test();
+        runtime = duration_cast&lt;milliseconds&gt;(steady_clock::now() - start).count();
+    }
+    sort(runtimes.begin(), runtimes.end());
+    double sum = std::accumulate(runtimes.begin(), runtimes.end(), 0);
+    double mean = sum / runtimes.size();
+    double median = runtimes[(runtimes.size() + 1) / 2];
+    double min = runtimes.front();
+    double max = runtimes.back();
+    double sqSum = std::inner_product(runtimes.begin(), runtimes.end(), runtimes.begin(), 0);
+    double stdev = std::sqrt(sqSum / runtimes.size() - mean * mean);
+
+    printf(&quot;RESULT %s: Time= %g ms&quot;, name, sum);
+    printf(&quot;median= %g ms, stdev= %g ms, min= %g ms, max = %g ms&quot;, median, stdev, min, max);
+}
+
+void test(int32_t count, function&lt;MediaTime(int32_t)&gt; generator)
+{
+    set&lt;MediaTime&gt; times;
+
+    for (int32_t i = 0; i &lt; count; ++i)
+        times.insert(generator(i));
+
+    for (int32_t i = 0; i &lt; count; ++i)
+        times.upper_bound(generator(i));
+}
+
+int main(int argc, const char * argv[])
+{
+    performTest(&quot;Equal TimeScales&quot;, [] { test(setSize, [] (int32_t i) { return MediaTime(i, 1); }); });
+    performTest(&quot;Equal TimeValues&quot;, [] { test(setSize, [] (int32_t i) { return MediaTime(1, i + 1); }); });
+    performTest(&quot;Disparate TimeValues &amp; TimeScales&quot;, [] { test(setSize, [] (int32_t i) { return MediaTime(i, i + 1); }); });
+    performTest(&quot;Non-uniform&quot;, [] {
+        test(setSize, [] (int32_t i) {
+            switch (i % 6) {
+            case 0:
+                return MediaTime::invalidTime();
+            case 1:
+                return MediaTime::positiveInfiniteTime();
+            case 2:
+                return MediaTime::negativeInfiniteTime();
+            case 3:
+                return MediaTime::indefiniteTime();
+            case 4:
+                return MediaTime(i, 1);
+            case 5:
+            default:
+                return MediaTime(i, i + 1);
+            }
+        });
+    });
+
+    return 0;
+}
</ins></span></pre></div>
<a id="trunkPerformanceTestsSkipped"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/Skipped (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/Skipped        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/PerformanceTests/Skipped        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -107,6 +107,7 @@
</span><span class="cx"> # Media tests take too long to run; require MSE, HLS which are not supported on all ports;
</span><span class="cx"> # and require a webserver (run-webkit-httpd) which is not part of normal performance testing.
</span><span class="cx"> Media/
</span><ins>+MediaTime/
</ins><span class="cx"> 
</span><span class="cx"> # Bugs 167622, 167637, 167638 and 167640 - Some IndexedDB test deadlock on the GTK+ perf bot.
</span><span class="cx"> [GTK] IndexedDB/index-get.html
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/Source/WTF/ChangeLog        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -1,3 +1,41 @@
</span><ins>+2017-02-06  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        Playback stalls when a SourceBuffer append causes frame eviction
+        https://bugs.webkit.org/show_bug.cgi?id=167834
+
+        Reviewed by Eric Carlson.
+
+        Optimize the MediaTime class; specifically the compare() method. The class only
+        needs 6 bits to store the TimeFlags, so make that a uint8_t rather than uint32_t.
+        The implementation is slightly simpler if the TimeScale is unsigned, so make that
+        a uint32_t rather than int32_t. Inline the comparison operators. Optimize the equality
+        comparison by bitwise-and'ing the flags together and masking the result. Optimize for
+        common comparison scenarios (equal timeScales, equal timeValues(), etc.). Attempt the
+        mathematically simpler simpler method for comparing ratios, and only fall back to the
+        complex method if the results of multiplying the timeScale by the timeValue overflows.
+
+        * wtf/MediaTime.cpp:
+        (WTF::greatestCommonDivisor):
+        (WTF::leastCommonMultiple):
+        (WTF::signum):
+        (WTF::MediaTime::MediaTime):
+        (WTF::MediaTime::createWithFloat):
+        (WTF::MediaTime::createWithDouble):
+        (WTF::MediaTime::operator+):
+        (WTF::MediaTime::operator-):
+        (WTF::MediaTime::operator!):
+        (WTF::MediaTime::operator bool):
+        (WTF::MediaTime::compare):
+        (WTF::MediaTime::setTimeScale):
+        (WTF::abs):
+        (WTF::MediaTime::operator&lt;): Deleted.
+        (WTF::MediaTime::operator&gt;): Deleted.
+        (WTF::MediaTime::operator!=): Deleted.
+        (WTF::MediaTime::operator==): Deleted.
+        (WTF::MediaTime::operator&gt;=): Deleted.
+        (WTF::MediaTime::operator&lt;=): Deleted.
+        * wtf/MediaTime.h:
+
</ins><span class="cx"> 2017-02-04  Michael Catanzaro  &lt;mcatanzaro@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK] Fix huge ENABLE_RESOURCE_USAGE warning spam
</span></span></pre></div>
<a id="trunkSourceWTFwtfMediaTimecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/MediaTime.cpp (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/MediaTime.cpp        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/Source/WTF/wtf/MediaTime.cpp        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> #include &quot;MediaTime.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #include &lt;algorithm&gt;
</span><ins>+#include &lt;cstdlib&gt;
</ins><span class="cx"> #include &lt;wtf/CheckedArithmetic.h&gt;
</span><span class="cx"> #include &lt;wtf/MathExtras.h&gt;
</span><span class="cx"> #include &lt;wtf/PrintStream.h&gt;
</span><span class="lines">@@ -36,10 +37,10 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="cx"> 
</span><del>-static int32_t greatestCommonDivisor(int32_t a, int32_t b)
</del><ins>+static uint32_t greatestCommonDivisor(uint32_t a, uint32_t b)
</ins><span class="cx"> {
</span><span class="cx">     // Euclid's Algorithm
</span><del>-    int32_t temp = 0;
</del><ins>+    uint32_t temp = 0;
</ins><span class="cx">     while (b) {
</span><span class="cx">         temp = b;
</span><span class="cx">         b = a % b;
</span><span class="lines">@@ -48,17 +49,17 @@
</span><span class="cx">     return a;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static int32_t leastCommonMultiple(int32_t a, int32_t b, int32_t &amp;result)
</del><ins>+static uint32_t leastCommonMultiple(uint32_t a, uint32_t b, uint32_t &amp;result)
</ins><span class="cx"> {
</span><span class="cx">     return safeMultiply(a, b / greatestCommonDivisor(a, b), result);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static int32_t signum(int64_t val)
</del><ins>+static int64_t signum(int64_t val)
</ins><span class="cx"> {
</span><span class="cx">     return (0 &lt; val) - (val &lt; 0);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-const int32_t MediaTime::MaximumTimeScale = 0x7fffffffL;
</del><ins>+const uint32_t MediaTime::MaximumTimeScale = 0x7fffffffL;
</ins><span class="cx"> 
</span><span class="cx"> MediaTime::MediaTime()
</span><span class="cx">     : m_timeValue(0)
</span><span class="lines">@@ -67,7 +68,7 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-MediaTime::MediaTime(int64_t value, int32_t scale, uint32_t flags)
</del><ins>+MediaTime::MediaTime(int64_t value, uint32_t scale, uint8_t flags)
</ins><span class="cx">     : m_timeValue(value)
</span><span class="cx">     , m_timeScale(scale)
</span><span class="cx">     , m_timeFlags(flags)
</span><span class="lines">@@ -99,7 +100,7 @@
</span><span class="cx">     return value;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-MediaTime MediaTime::createWithFloat(float floatTime, int32_t timeScale)
</del><ins>+MediaTime MediaTime::createWithFloat(float floatTime, uint32_t timeScale)
</ins><span class="cx"> {
</span><span class="cx">     if (floatTime != floatTime)
</span><span class="cx">         return invalidTime();
</span><span class="lines">@@ -131,7 +132,7 @@
</span><span class="cx">     return value;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-MediaTime MediaTime::createWithDouble(double doubleTime, int32_t timeScale)
</del><ins>+MediaTime MediaTime::createWithDouble(double doubleTime, uint32_t timeScale)
</ins><span class="cx"> {
</span><span class="cx">     if (doubleTime != doubleTime)
</span><span class="cx">         return invalidTime();
</span><span class="lines">@@ -212,7 +213,7 @@
</span><span class="cx">     else if (b.hasDoubleValue())
</span><span class="cx">         b.setTimeScale(DefaultTimeScale);
</span><span class="cx"> 
</span><del>-    int32_t commonTimeScale;
</del><ins>+    uint32_t commonTimeScale;
</ins><span class="cx">     if (!leastCommonMultiple(a.m_timeScale, b.m_timeScale, commonTimeScale) || commonTimeScale &gt; MaximumTimeScale)
</span><span class="cx">         commonTimeScale = MaximumTimeScale;
</span><span class="cx">     a.setTimeScale(commonTimeScale);
</span><span class="lines">@@ -258,7 +259,7 @@
</span><span class="cx">     else if (b.hasDoubleValue())
</span><span class="cx">         b.setTimeScale(DefaultTimeScale);
</span><span class="cx"> 
</span><del>-    int32_t commonTimeScale;
</del><ins>+    uint32_t commonTimeScale;
</ins><span class="cx">     if (!leastCommonMultiple(this-&gt;m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale &gt; MaximumTimeScale)
</span><span class="cx">         commonTimeScale = MaximumTimeScale;
</span><span class="cx">     a.setTimeScale(commonTimeScale);
</span><span class="lines">@@ -334,73 +335,41 @@
</span><span class="cx">     return a;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool MediaTime::operator&lt;(const MediaTime&amp; rhs) const
-{
-    return compare(rhs) == LessThan;
-}
-
-bool MediaTime::operator&gt;(const MediaTime&amp; rhs) const
-{
-    return compare(rhs) == GreaterThan;
-}
-
-bool MediaTime::operator!=(const MediaTime&amp; rhs) const
-{
-    return compare(rhs) != EqualTo;
-}
-
-bool MediaTime::operator==(const MediaTime&amp; rhs) const
-{
-    return compare(rhs) == EqualTo;
-}
-
-bool MediaTime::operator&gt;=(const MediaTime&amp; rhs) const
-{
-    return compare(rhs) &gt;= EqualTo;
-}
-
-bool MediaTime::operator&lt;=(const MediaTime&amp; rhs) const
-{
-    return compare(rhs) &lt;= EqualTo;
-}
-
</del><span class="cx"> bool MediaTime::operator!() const
</span><span class="cx"> {
</span><del>-    return compare(zeroTime()) == EqualTo;
</del><ins>+    return (m_timeFlags == Valid &amp;&amp; !m_timeValue)
+        || (m_timeFlags == (Valid | DoubleValue) &amp;&amp; !m_timeValueAsDouble);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MediaTime::operator bool() const
</span><span class="cx"> {
</span><del>-    return compare(zeroTime()) != EqualTo;
</del><ins>+    return !(m_timeFlags == Valid &amp;&amp; !m_timeValue)
+        &amp;&amp; !(m_timeFlags == (Valid | DoubleValue) &amp;&amp; !m_timeValueAsDouble);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MediaTime::ComparisonFlags MediaTime::compare(const MediaTime&amp; rhs) const
</span><span class="cx"> {
</span><del>-    if ((isPositiveInfinite() &amp;&amp; rhs.isPositiveInfinite())
-        || (isNegativeInfinite() &amp;&amp; rhs.isNegativeInfinite())
-        || (isInvalid() &amp;&amp; rhs.isInvalid())
-        || (isIndefinite() &amp;&amp; rhs.isIndefinite()))
</del><ins>+    auto andFlags = m_timeFlags &amp; rhs.m_timeFlags;
+    if (andFlags &amp; (PositiveInfinite | NegativeInfinite | Indefinite))
</ins><span class="cx">         return EqualTo;
</span><span class="cx"> 
</span><del>-    if (isInvalid())
-        return GreaterThan;
</del><ins>+    auto orFlags = m_timeFlags | rhs.m_timeFlags;
+    if (!(orFlags &amp; Valid))
+        return EqualTo;
</ins><span class="cx"> 
</span><del>-    if (rhs.isInvalid())
-        return LessThan;
</del><ins>+    if (!(andFlags &amp; Valid))
+        return isInvalid() ? GreaterThan : LessThan;
</ins><span class="cx"> 
</span><del>-    if (rhs.isNegativeInfinite() || isPositiveInfinite())
-        return GreaterThan;
</del><ins>+    if (orFlags &amp; NegativeInfinite)
+        return isNegativeInfinite() ? LessThan : GreaterThan;
</ins><span class="cx"> 
</span><del>-    if (rhs.isPositiveInfinite() || isNegativeInfinite())
-        return LessThan;
</del><ins>+    if (orFlags &amp; PositiveInfinite)
+        return isPositiveInfinite() ? GreaterThan : LessThan;
</ins><span class="cx"> 
</span><del>-    if (isIndefinite())
-        return GreaterThan;
</del><ins>+    if (orFlags &amp; Indefinite)
+        return isIndefinite() ? GreaterThan : LessThan;
</ins><span class="cx"> 
</span><del>-    if (rhs.isIndefinite())
-        return LessThan;
-
-    if (hasDoubleValue() &amp;&amp; rhs.hasDoubleValue()) {
</del><ins>+    if (andFlags &amp; DoubleValue) {
</ins><span class="cx">         if (m_timeValueAsDouble == rhs.m_timeValueAsDouble)
</span><span class="cx">             return EqualTo;
</span><span class="cx"> 
</span><span class="lines">@@ -407,7 +376,7 @@
</span><span class="cx">         return m_timeValueAsDouble &lt; rhs.m_timeValueAsDouble ? LessThan : GreaterThan;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (hasDoubleValue() || rhs.hasDoubleValue()) {
</del><ins>+    if (orFlags &amp; DoubleValue) {
</ins><span class="cx">         double a = toDouble();
</span><span class="cx">         double b = rhs.toDouble();
</span><span class="cx">         if (a &gt; b)
</span><span class="lines">@@ -417,20 +386,47 @@
</span><span class="cx">         return EqualTo;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    MediaTime a = *this;
-    MediaTime b = rhs;
</del><ins>+    if ((m_timeValue &lt; 0) != (rhs.m_timeValue &lt; 0))
+        return m_timeValue &lt; 0 ? LessThan : GreaterThan;
</ins><span class="cx"> 
</span><del>-    int64_t rhsWhole = b.m_timeValue / b.m_timeScale;
-    int64_t lhsWhole = a.m_timeValue / a.m_timeScale;
</del><ins>+    if (!m_timeValue &amp;&amp; !rhs.m_timeValue)
+        return EqualTo;
+
+    if (m_timeScale == rhs.m_timeScale) {
+        if (m_timeValue == rhs.m_timeValue)
+            return EqualTo;
+        return m_timeValue &lt; rhs.m_timeValue ? LessThan : GreaterThan;
+    }
+
+    if (m_timeValue == rhs.m_timeValue)
+        return m_timeScale &lt; rhs.m_timeScale ? GreaterThan : LessThan;
+
+    if (m_timeValue &lt; rhs.m_timeValue &amp;&amp; m_timeScale &gt; rhs.m_timeScale)
+        return LessThan;
+
+    if (m_timeValue &gt; rhs.m_timeValue &amp;&amp; m_timeScale &lt; rhs.m_timeScale)
+        return GreaterThan;
+
+    int64_t lhsFactor;
+    int64_t rhsFactor;
+    if (safeMultiply(m_timeValue, static_cast&lt;int64_t&gt;(rhs.m_timeScale), lhsFactor)
+        &amp;&amp; safeMultiply(rhs.m_timeValue, static_cast&lt;int64_t&gt;(m_timeScale), rhsFactor)) {
+        if (lhsFactor == rhsFactor)
+            return EqualTo;
+        return lhsFactor &lt; rhsFactor ? LessThan : GreaterThan;
+    }
+
+    int64_t rhsWhole = rhs.m_timeValue / rhs.m_timeScale;
+    int64_t lhsWhole = m_timeValue / m_timeScale;
</ins><span class="cx">     if (lhsWhole &gt; rhsWhole)
</span><span class="cx">         return GreaterThan;
</span><span class="cx">     if (lhsWhole &lt; rhsWhole)
</span><span class="cx">         return LessThan;
</span><span class="cx"> 
</span><del>-    int64_t rhsRemain = b.m_timeValue % b.m_timeScale;
-    int64_t lhsRemain = a.m_timeValue % a.m_timeScale;
-    int64_t lhsFactor = lhsRemain * b.m_timeScale;
-    int64_t rhsFactor = rhsRemain * a.m_timeScale;
</del><ins>+    int64_t rhsRemain = rhs.m_timeValue % rhs.m_timeScale;
+    int64_t lhsRemain = m_timeValue % m_timeScale;
+    lhsFactor = lhsRemain * rhs.m_timeScale;
+    rhsFactor = rhsRemain * m_timeScale;
</ins><span class="cx"> 
</span><span class="cx">     if (lhsFactor == rhsFactor)
</span><span class="cx">         return EqualTo;
</span><span class="lines">@@ -474,7 +470,7 @@
</span><span class="cx">     return *time;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MediaTime::setTimeScale(int32_t timeScale)
</del><ins>+void MediaTime::setTimeScale(uint32_t timeScale)
</ins><span class="cx"> {
</span><span class="cx">     if (hasDoubleValue()) {
</span><span class="cx">         *this = MediaTime::createWithDouble(m_timeValueAsDouble, timeScale);
</span><span class="lines">@@ -490,7 +486,7 @@
</span><span class="cx">     // timescale by two until the number will fit, and round the
</span><span class="cx">     // result.
</span><span class="cx">     int64_t newWholePart;
</span><del>-    while (!safeMultiply(wholePart, timeScale, newWholePart))
</del><ins>+    while (!safeMultiply(wholePart, static_cast&lt;int64_t&gt;(timeScale), newWholePart))
</ins><span class="cx">         timeScale /= 2;
</span><span class="cx"> 
</span><span class="cx">     int64_t remainder = m_timeValue % m_timeScale;
</span><span class="lines">@@ -513,7 +509,7 @@
</span><span class="cx">         return MediaTime::createWithDouble(fabs(rhs.m_timeValueAsDouble));
</span><span class="cx"> 
</span><span class="cx">     MediaTime val = rhs;
</span><del>-    val.m_timeValue *= signum(rhs.m_timeScale) * signum(rhs.m_timeValue);
</del><ins>+    val.m_timeValue = std::abs(rhs.m_timeValue);
</ins><span class="cx">     return val;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWTFwtfMediaTimeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/MediaTime.h (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/MediaTime.h        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/Source/WTF/wtf/MediaTime.h        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -53,14 +53,14 @@
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     MediaTime();
</span><del>-    MediaTime(int64_t value, int32_t scale, uint32_t flags = Valid);
</del><ins>+    MediaTime(int64_t value, uint32_t scale, uint8_t flags = Valid);
</ins><span class="cx">     MediaTime(const MediaTime&amp; rhs);
</span><span class="cx">     ~MediaTime();
</span><span class="cx"> 
</span><span class="cx">     static MediaTime createWithFloat(float floatTime);
</span><del>-    static MediaTime createWithFloat(float floatTime, int32_t timeScale);
</del><ins>+    static MediaTime createWithFloat(float floatTime, uint32_t timeScale);
</ins><span class="cx">     static MediaTime createWithDouble(double doubleTime);
</span><del>-    static MediaTime createWithDouble(double doubleTime, int32_t timeScale);
</del><ins>+    static MediaTime createWithDouble(double doubleTime, uint32_t timeScale);
</ins><span class="cx"> 
</span><span class="cx">     float toFloat() const;
</span><span class="cx">     double toDouble() const;
</span><span class="lines">@@ -72,12 +72,12 @@
</span><span class="cx">     MediaTime operator-(const MediaTime&amp; rhs) const;
</span><span class="cx">     MediaTime operator-() const;
</span><span class="cx">     MediaTime operator*(int32_t) const;
</span><del>-    bool operator&lt;(const MediaTime&amp; rhs) const;
-    bool operator&gt;(const MediaTime&amp; rhs) const;
-    bool operator!=(const MediaTime&amp; rhs) const;
-    bool operator==(const MediaTime&amp; rhs) const;
-    bool operator&gt;=(const MediaTime&amp; rhs) const;
-    bool operator&lt;=(const MediaTime&amp; rhs) const;
</del><ins>+    bool operator&lt;(const MediaTime&amp; rhs) const { return compare(rhs) == LessThan; }
+    bool operator&gt;(const MediaTime&amp; rhs) const { return compare(rhs) == GreaterThan; }
+    bool operator!=(const MediaTime&amp; rhs) const { return compare(rhs) != EqualTo; }
+    bool operator==(const MediaTime&amp; rhs) const { return compare(rhs) == EqualTo; }
+    bool operator&gt;=(const MediaTime&amp; rhs) const { return compare(rhs) &gt;= EqualTo; }
+    bool operator&lt;=(const MediaTime&amp; rhs) const { return compare(rhs) &lt;= EqualTo; }
</ins><span class="cx">     bool operator!() const;
</span><span class="cx">     explicit operator bool() const;
</span><span class="cx"> 
</span><span class="lines">@@ -105,7 +105,7 @@
</span><span class="cx">     static const MediaTime&amp; indefiniteTime();
</span><span class="cx"> 
</span><span class="cx">     const int64_t&amp; timeValue() const { return m_timeValue; }
</span><del>-    const int32_t&amp; timeScale() const { return m_timeScale; }
</del><ins>+    const uint32_t&amp; timeScale() const { return m_timeScale; }
</ins><span class="cx"> 
</span><span class="cx">     void dump(PrintStream&amp; out) const;
</span><span class="cx"> 
</span><span class="lines">@@ -117,18 +117,18 @@
</span><span class="cx"> 
</span><span class="cx">     friend WTF_EXPORT_PRIVATE MediaTime abs(const MediaTime&amp; rhs);
</span><span class="cx"> 
</span><del>-    static const int32_t DefaultTimeScale = 10000000;
-    static const int32_t MaximumTimeScale;
</del><ins>+    static const uint32_t DefaultTimeScale = 10000000;
+    static const uint32_t MaximumTimeScale;
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    void setTimeScale(int32_t);
</del><ins>+    void setTimeScale(uint32_t);
</ins><span class="cx"> 
</span><span class="cx">     union {
</span><span class="cx">         int64_t m_timeValue;
</span><span class="cx">         double m_timeValueAsDouble;
</span><span class="cx">     };
</span><del>-    int32_t m_timeScale;
-    uint32_t m_timeFlags;
</del><ins>+    uint32_t m_timeScale;
+    uint8_t m_timeFlags;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> inline MediaTime operator*(int32_t lhs, const MediaTime&amp; rhs) { return rhs.operator*(lhs); }
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/Source/WebCore/ChangeLog        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -1,3 +1,51 @@
</span><ins>+2017-02-06  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        Playback stalls when a SourceBuffer append causes frame eviction
+        https://bugs.webkit.org/show_bug.cgi?id=167834
+
+        Reviewed by Eric Carlson.
+
+        Test: PerformanceTests/Media/MSERemoveCodedFrames.html
+
+        Optimize searching through SampleMap by presentationTime.
+
+        Many of the methods exposed by PresentationOrderSampleMap used the bare  std::equal_range,
+        lower_bound, or upper_bound methods. Unlike those methods exposed on std::map, the bare
+        search methods perform a linear O(n) search, rather than a the binary O(log(n)) search used
+        by std::map. Rewrite those methods using the bare methods in terms of the std::map search
+        methods.
+
+        Drive-by fix: rename findSampleOnOrAfterPresentationTime to
+        findSampleStartingOnOrAfterPresentationTime to make the behavior of the method more
+        explicit.
+
+        * Modules/mediasource/SampleMap.cpp:
+        (WebCore::PresentationOrderSampleMap::findSampleContainingPresentationTime):
+        (WebCore::PresentationOrderSampleMap::findSampleStartingOnOrAfterPresentationTime):
+        (WebCore::PresentationOrderSampleMap::reverseFindSampleBeforePresentationTime):
+        (WebCore::DecodeOrderSampleMap::findSyncSampleAfterPresentationTime):
+        (WebCore::PresentationOrderSampleMap::findSamplesBetweenPresentationTimes):
+        (WebCore::PresentationOrderSampleMap::findSamplesWithinPresentationRange):
+        (WebCore::PresentationOrderSampleMap::findSampleOnOrAfterPresentationTime): Deleted.
+        * Modules/mediasource/SampleMap.h:
+        (WebCore::PresentationOrderSampleMap::begin):
+        (WebCore::PresentationOrderSampleMap::end):
+        (WebCore::PresentationOrderSampleMap::rbegin):
+        (WebCore::PresentationOrderSampleMap::rend):
+        (WebCore::DecodeOrderSampleMap::begin):
+        (WebCore::DecodeOrderSampleMap::end):
+        (WebCore::DecodeOrderSampleMap::rbegin):
+        (WebCore::DecodeOrderSampleMap::rend):
+        (WebCore::SampleMap::SampleMap):
+        (WebCore::SampleMap::sizeInBytes):
+        (WebCore::SampleMap::decodeOrder):
+        (WebCore::SampleMap::presentationOrder):
+        * Modules/mediasource/SourceBuffer.cpp:
+        (WebCore::removeSamplesFromTrackBuffer):
+        (WebCore::SourceBuffer::removeCodedFrames):
+        (WebCore::SourceBuffer::reenqueueMediaForTime):
+        * WebCore.xcodeproj/project.pbxproj:
+
</ins><span class="cx"> 2017-02-06  Said Abou-Hallawa  &lt;sabouhallawa@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Rename AnimationController to CSSAnimationController
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSampleMapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/Source/WebCore/Modules/mediasource/SampleMap.cpp        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -142,13 +142,21 @@
</span><span class="cx"> 
</span><span class="cx"> PresentationOrderSampleMap::iterator PresentationOrderSampleMap::findSampleContainingPresentationTime(const MediaTime&amp; time)
</span><span class="cx"> {
</span><del>-    auto range = std::equal_range(begin(), end(), time, SampleIsLessThanMediaTimeComparator&lt;MapType&gt;());
-    if (range.first == range.second)
</del><ins>+    // upper_bound will return the first sample whose presentation start time is greater than the search time.
+    // If this is the first sample, that means no sample in the map contains the requested time.
+    auto iter = m_samples.upper_bound(time);
+    if (iter == begin())
</ins><span class="cx">         return end();
</span><del>-    return range.first;
</del><ins>+
+    // Look at the previous sample; does it contain the requested time?
+    --iter;
+    MediaSample&amp; sample = *iter-&gt;second;
+    if (sample.presentationTime() + sample.duration() &gt; time)
+        return iter;
+    return end();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-PresentationOrderSampleMap::iterator PresentationOrderSampleMap::findSampleOnOrAfterPresentationTime(const MediaTime&amp; time)
</del><ins>+PresentationOrderSampleMap::iterator PresentationOrderSampleMap::findSampleStartingOnOrAfterPresentationTime(const MediaTime&amp; time)
</ins><span class="cx"> {
</span><span class="cx">     return m_samples.lower_bound(time);
</span><span class="cx"> }
</span><span class="lines">@@ -168,7 +176,22 @@
</span><span class="cx"> 
</span><span class="cx"> PresentationOrderSampleMap::reverse_iterator PresentationOrderSampleMap::reverseFindSampleBeforePresentationTime(const MediaTime&amp; time)
</span><span class="cx"> {
</span><del>-    return std::lower_bound(rbegin(), rend(), time, SampleIsGreaterThanMediaTimeComparator&lt;MapType&gt;());
</del><ins>+    if (m_samples.empty())
+        return rend();
+
+    // upper_bound will return the first sample whose presentation start time is greater than the search time.
+    auto found = m_samples.upper_bound(time);
+
+    // If no sample was found with a time greater than the search time, return the last sample.
+    if (found == end())
+        return rbegin();
+
+    // If the first sample has a time grater than the search time, no samples will have a presentation time before the search time.
+    if (found == begin())
+        return rend();
+
+    // Otherwise, return the sample immediately previous to the one found.
+    return --reverse_iterator(--found);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> DecodeOrderSampleMap::reverse_iterator DecodeOrderSampleMap::reverseFindSampleWithDecodeKey(const KeyType&amp; key)
</span><span class="lines">@@ -203,7 +226,7 @@
</span><span class="cx"> 
</span><span class="cx"> DecodeOrderSampleMap::iterator DecodeOrderSampleMap::findSyncSampleAfterPresentationTime(const MediaTime&amp; time, const MediaTime&amp; threshold)
</span><span class="cx"> {
</span><del>-    PresentationOrderSampleMap::iterator currentSamplePTS = m_presentationOrder.findSampleOnOrAfterPresentationTime(time);
</del><ins>+    PresentationOrderSampleMap::iterator currentSamplePTS = m_presentationOrder.findSampleStartingOnOrAfterPresentationTime(time);
</ins><span class="cx">     if (currentSamplePTS == m_presentationOrder.end())
</span><span class="cx">         return end();
</span><span class="cx"> 
</span><span class="lines">@@ -228,14 +251,24 @@
</span><span class="cx"> 
</span><span class="cx"> PresentationOrderSampleMap::iterator_range PresentationOrderSampleMap::findSamplesBetweenPresentationTimes(const MediaTime&amp; beginTime, const MediaTime&amp; endTime)
</span><span class="cx"> {
</span><del>-    std::pair&lt;MediaTime, MediaTime&gt; range(beginTime, endTime);
-    return std::equal_range(begin(), end(), range, SamplePresentationTimeIsInsideRangeComparator());
</del><ins>+    // startTime is inclusive, so use lower_bound to include samples wich start exactly at startTime.
+    // endTime is not inclusive, so use lower_bound to exclude samples which start exactly at endTime.
+    auto lower_bound = m_samples.lower_bound(beginTime);
+    auto upper_bound = m_samples.lower_bound(endTime);
+    if (lower_bound == upper_bound)
+        return { end(), end() };
+    return { lower_bound, upper_bound };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PresentationOrderSampleMap::iterator_range PresentationOrderSampleMap::findSamplesWithinPresentationRange(const MediaTime&amp; beginTime, const MediaTime&amp; endTime)
</span><span class="cx"> {
</span><del>-    std::pair&lt;MediaTime, MediaTime&gt; range(beginTime, endTime);
-    return std::equal_range(begin(), end(), range, SamplePresentationTimeIsWithinRangeComparator());
</del><ins>+    // startTime is not inclusive, so use upper_bound to exclude samples which start exactly at startTime.
+    // endTime is inclusive, so use upper_bound to include samples which start exactly at endTime.
+    auto lower_bound = m_samples.upper_bound(beginTime);
+    auto upper_bound = m_samples.upper_bound(endTime);
+    if (lower_bound == upper_bound)
+        return { end(), end() };
+    return { lower_bound, upper_bound };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PresentationOrderSampleMap::iterator_range PresentationOrderSampleMap::findSamplesWithinPresentationRangeFromEnd(const MediaTime&amp; beginTime, const MediaTime&amp; endTime)
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSampleMaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SampleMap.h (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SampleMap.h        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/Source/WebCore/Modules/mediasource/SampleMap.h        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -46,23 +46,23 @@
</span><span class="cx">     typedef MapType::const_reverse_iterator const_reverse_iterator;
</span><span class="cx">     typedef std::pair&lt;iterator, iterator&gt; iterator_range;
</span><span class="cx"> 
</span><del>-    iterator begin() { return m_samples.begin(); }
-    const_iterator begin() const { return m_samples.begin(); }
-    iterator end() { return m_samples.end(); }
-    const_iterator end() const { return m_samples.end(); }
-    reverse_iterator rbegin() { return m_samples.rbegin(); }
-    const_reverse_iterator rbegin() const { return m_samples.rbegin(); }
-    reverse_iterator rend() { return m_samples.rend(); }
-    const_reverse_iterator rend() const { return m_samples.rend(); }
</del><ins>+    WEBCORE_EXPORT iterator begin() { return m_samples.begin(); }
+    WEBCORE_EXPORT const_iterator begin() const { return m_samples.begin(); }
+    WEBCORE_EXPORT iterator end() { return m_samples.end(); }
+    WEBCORE_EXPORT const_iterator end() const { return m_samples.end(); }
+    WEBCORE_EXPORT reverse_iterator rbegin() { return m_samples.rbegin(); }
+    WEBCORE_EXPORT const_reverse_iterator rbegin() const { return m_samples.rbegin(); }
+    WEBCORE_EXPORT reverse_iterator rend() { return m_samples.rend(); }
+    WEBCORE_EXPORT const_reverse_iterator rend() const { return m_samples.rend(); }
</ins><span class="cx"> 
</span><del>-    iterator findSampleWithPresentationTime(const MediaTime&amp;);
-    iterator findSampleContainingPresentationTime(const MediaTime&amp;);
-    iterator findSampleOnOrAfterPresentationTime(const MediaTime&amp;);
-    reverse_iterator reverseFindSampleContainingPresentationTime(const MediaTime&amp;);
-    reverse_iterator reverseFindSampleBeforePresentationTime(const MediaTime&amp;);
-    iterator_range findSamplesBetweenPresentationTimes(const MediaTime&amp;, const MediaTime&amp;);
-    iterator_range findSamplesWithinPresentationRange(const MediaTime&amp;, const MediaTime&amp;);
-    iterator_range findSamplesWithinPresentationRangeFromEnd(const MediaTime&amp;, const MediaTime&amp;);
</del><ins>+    WEBCORE_EXPORT iterator findSampleWithPresentationTime(const MediaTime&amp;);
+    WEBCORE_EXPORT iterator findSampleContainingPresentationTime(const MediaTime&amp;);
+    WEBCORE_EXPORT iterator findSampleStartingOnOrAfterPresentationTime(const MediaTime&amp;);
+    WEBCORE_EXPORT reverse_iterator reverseFindSampleContainingPresentationTime(const MediaTime&amp;);
+    WEBCORE_EXPORT reverse_iterator reverseFindSampleBeforePresentationTime(const MediaTime&amp;);
+    WEBCORE_EXPORT iterator_range findSamplesBetweenPresentationTimes(const MediaTime&amp;, const MediaTime&amp;);
+    WEBCORE_EXPORT iterator_range findSamplesWithinPresentationRange(const MediaTime&amp;, const MediaTime&amp;);
+    WEBCORE_EXPORT iterator_range findSamplesWithinPresentationRangeFromEnd(const MediaTime&amp;, const MediaTime&amp;);
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     MapType m_samples;
</span><span class="lines">@@ -79,22 +79,22 @@
</span><span class="cx">     typedef MapType::const_reverse_iterator const_reverse_iterator;
</span><span class="cx">     typedef std::pair&lt;reverse_iterator, reverse_iterator&gt; reverse_iterator_range;
</span><span class="cx"> 
</span><del>-    iterator begin() { return m_samples.begin(); }
-    const_iterator begin() const { return m_samples.begin(); }
-    iterator end() { return m_samples.end(); }
-    const_iterator end() const { return m_samples.end(); }
-    reverse_iterator rbegin() { return m_samples.rbegin(); }
-    const_reverse_iterator rbegin() const { return m_samples.rbegin(); }
-    reverse_iterator rend() { return m_samples.rend(); }
-    const_reverse_iterator rend() const { return m_samples.rend(); }
</del><ins>+    WEBCORE_EXPORT iterator begin() { return m_samples.begin(); }
+    WEBCORE_EXPORT const_iterator begin() const { return m_samples.begin(); }
+    WEBCORE_EXPORT iterator end() { return m_samples.end(); }
+    WEBCORE_EXPORT const_iterator end() const { return m_samples.end(); }
+    WEBCORE_EXPORT reverse_iterator rbegin() { return m_samples.rbegin(); }
+    WEBCORE_EXPORT const_reverse_iterator rbegin() const { return m_samples.rbegin(); }
+    WEBCORE_EXPORT reverse_iterator rend() { return m_samples.rend(); }
+    WEBCORE_EXPORT const_reverse_iterator rend() const { return m_samples.rend(); }
</ins><span class="cx"> 
</span><del>-    iterator findSampleWithDecodeKey(const KeyType&amp;);
-    reverse_iterator reverseFindSampleWithDecodeKey(const KeyType&amp;);
-    reverse_iterator findSyncSamplePriorToPresentationTime(const MediaTime&amp;, const MediaTime&amp; threshold = MediaTime::positiveInfiniteTime());
-    reverse_iterator findSyncSamplePriorToDecodeIterator(reverse_iterator);
-    iterator findSyncSampleAfterPresentationTime(const MediaTime&amp;, const MediaTime&amp; threshold = MediaTime::positiveInfiniteTime());
-    iterator findSyncSampleAfterDecodeIterator(iterator);
-    reverse_iterator_range findDependentSamples(MediaSample*);
</del><ins>+    WEBCORE_EXPORT iterator findSampleWithDecodeKey(const KeyType&amp;);
+    WEBCORE_EXPORT reverse_iterator reverseFindSampleWithDecodeKey(const KeyType&amp;);
+    WEBCORE_EXPORT reverse_iterator findSyncSamplePriorToPresentationTime(const MediaTime&amp;, const MediaTime&amp; threshold = MediaTime::positiveInfiniteTime());
+    WEBCORE_EXPORT reverse_iterator findSyncSamplePriorToDecodeIterator(reverse_iterator);
+    WEBCORE_EXPORT iterator findSyncSampleAfterPresentationTime(const MediaTime&amp;, const MediaTime&amp; threshold = MediaTime::positiveInfiniteTime());
+    WEBCORE_EXPORT iterator findSyncSampleAfterDecodeIterator(iterator);
+    WEBCORE_EXPORT reverse_iterator_range findDependentSamples(MediaSample*);
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     MapType m_samples;
</span><span class="lines">@@ -103,24 +103,24 @@
</span><span class="cx"> 
</span><span class="cx"> class SampleMap {
</span><span class="cx"> public:
</span><del>-    SampleMap()
</del><ins>+    WEBCORE_EXPORT SampleMap()
</ins><span class="cx">         : m_totalSize(0)
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    bool empty() const;
-    void clear();
-    void addSample(MediaSample&amp;);
-    void removeSample(MediaSample*);
-    size_t sizeInBytes() const { return m_totalSize; }
</del><ins>+    WEBCORE_EXPORT bool empty() const;
+    WEBCORE_EXPORT void clear();
+    WEBCORE_EXPORT void addSample(MediaSample&amp;);
+    WEBCORE_EXPORT void removeSample(MediaSample*);
+    WEBCORE_EXPORT size_t sizeInBytes() const { return m_totalSize; }
</ins><span class="cx"> 
</span><span class="cx">     template&lt;typename I&gt;
</span><span class="cx">     void addRange(I begin, I end);
</span><span class="cx"> 
</span><del>-    DecodeOrderSampleMap&amp; decodeOrder() { return m_decodeOrder; }
-    const DecodeOrderSampleMap&amp; decodeOrder() const { return m_decodeOrder; }
-    PresentationOrderSampleMap&amp; presentationOrder() { return m_decodeOrder.m_presentationOrder; }
-    const PresentationOrderSampleMap&amp; presentationOrder() const { return m_decodeOrder.m_presentationOrder; }
</del><ins>+    WEBCORE_EXPORT DecodeOrderSampleMap&amp; decodeOrder() { return m_decodeOrder; }
+    WEBCORE_EXPORT const DecodeOrderSampleMap&amp; decodeOrder() const { return m_decodeOrder; }
+    WEBCORE_EXPORT PresentationOrderSampleMap&amp; presentationOrder() { return m_decodeOrder.m_presentationOrder; }
+    WEBCORE_EXPORT const PresentationOrderSampleMap&amp; presentationOrder() const { return m_decodeOrder.m_presentationOrder; }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     DecodeOrderSampleMap m_decodeOrder;
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesmediasourceSourceBuffercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/Source/WebCore/Modules/mediasource/SourceBuffer.cpp        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -705,7 +705,7 @@
</span><span class="cx">                 additionalErasedRanges.add(previousSample.presentationTime() + previousSample.duration(), erasedStart);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        auto endIterator = trackBuffer.samples.presentationOrder().findSampleOnOrAfterPresentationTime(erasedEnd);
</del><ins>+        auto endIterator = trackBuffer.samples.presentationOrder().findSampleStartingOnOrAfterPresentationTime(erasedEnd);
</ins><span class="cx">         if (endIterator == trackBuffer.samples.presentationOrder().end())
</span><span class="cx">             additionalErasedRanges.add(erasedEnd, MediaTime::positiveInfiniteTime());
</span><span class="cx">         else {
</span><span class="lines">@@ -775,7 +775,7 @@
</span><span class="cx">         else
</span><span class="cx">             removePresentationEnd = trackBuffer.samples.presentationOrder().findSampleWithPresentationTime(removeDecodeEnd-&gt;second-&gt;presentationTime());
</span><span class="cx"> 
</span><del>-        PresentationOrderSampleMap::iterator removePresentationStart = trackBuffer.samples.presentationOrder().findSampleOnOrAfterPresentationTime(start);
</del><ins>+        PresentationOrderSampleMap::iterator removePresentationStart = trackBuffer.samples.presentationOrder().findSampleStartingOnOrAfterPresentationTime(start);
</ins><span class="cx">         if (removePresentationStart == removePresentationEnd)
</span><span class="cx">             continue;
</span><span class="cx"> 
</span><span class="lines">@@ -1842,7 +1842,7 @@
</span><span class="cx">     auto currentSamplePTSIterator = trackBuffer.samples.presentationOrder().findSampleContainingPresentationTime(time);
</span><span class="cx"> 
</span><span class="cx">     if (currentSamplePTSIterator == trackBuffer.samples.presentationOrder().end())
</span><del>-        currentSamplePTSIterator = trackBuffer.samples.presentationOrder().findSampleOnOrAfterPresentationTime(time);
</del><ins>+        currentSamplePTSIterator = trackBuffer.samples.presentationOrder().findSampleStartingOnOrAfterPresentationTime(time);
</ins><span class="cx"> 
</span><span class="cx">     if (currentSamplePTSIterator == trackBuffer.samples.presentationOrder().end()
</span><span class="cx">         || (currentSamplePTSIterator-&gt;first - time) &gt; MediaSource::currentTimeFudgeFactor())
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -5929,7 +5929,7 @@
</span><span class="cx">                 CDCFABBD18C0AF78006F8450 /* SelectionSubtreeRoot.h in Headers */ = {isa = PBXBuildFile; fileRef = CDCFABBB18C0AE31006F8450 /* SelectionSubtreeRoot.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 CDCFABBE18C0AF84006F8450 /* SelectionSubtreeRoot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDCFABBC18C0AF19006F8450 /* SelectionSubtreeRoot.cpp */; };
</span><span class="cx">                 CDD7089618359F6F002B3DC6 /* SampleMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDD7089418359F6E002B3DC6 /* SampleMap.cpp */; };
</span><del>-                CDD7089718359F6F002B3DC6 /* SampleMap.h in Headers */ = {isa = PBXBuildFile; fileRef = CDD7089518359F6F002B3DC6 /* SampleMap.h */; };
</del><ins>+                CDD7089718359F6F002B3DC6 /* SampleMap.h in Headers */ = {isa = PBXBuildFile; fileRef = CDD7089518359F6F002B3DC6 /* SampleMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 CDDC1E7A18A952F30027A9D4 /* MediaSourcePrivateClient.h in Headers */ = {isa = PBXBuildFile; fileRef = CDDC1E7918A952F30027A9D4 /* MediaSourcePrivateClient.h */; };
</span><span class="cx">                 CDDE02ED18B3ED6D00CF7FF1 /* CDMSessionAVFoundationObjC.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDDE02EB18B3ED6D00CF7FF1 /* CDMSessionAVFoundationObjC.mm */; };
</span><span class="cx">                 CDDE02F018B5651300CF7FF1 /* CDMSessionAVStreamSession.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDDE02EF18B5651200CF7FF1 /* CDMSessionAVStreamSession.mm */; };
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/Tools/ChangeLog        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -1,3 +1,22 @@
</span><ins>+2017-02-06  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        Playback stalls when a SourceBuffer append causes frame eviction
+        https://bugs.webkit.org/show_bug.cgi?id=167834
+
+        Reviewed by Eric Carlson.
+
+        Add new correctness tests for the Webcore::SampleMap class. Add additional subtests
+        for the WTF::MediaTime class.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WTF/MediaTime.cpp:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WebCore/SampleMap.cpp: Added.
+        (WTF::operator&lt;&lt;):
+        (TestWebKitAPI::TestSample::create):
+        (TestWebKitAPI::TestSample::TestSample):
+        (TestWebKitAPI::TEST_F):
+
</ins><span class="cx"> 2017-02-06  Ryan Haddad  &lt;ryanhaddad@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Change capitalization in platform name after r211735.
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -531,6 +531,7 @@
</span><span class="cx">                 CDC8E4951BC6F10800594FEC /* video-with-audio.mp4 in Copy Resources */ = {isa = PBXBuildFile; fileRef = CDC8E48A1BC5C96200594FEC /* video-with-audio.mp4 */; };
</span><span class="cx">                 CDC8E4961BC6F10800594FEC /* video-without-audio.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CDC8E48B1BC5C96200594FEC /* video-without-audio.html */; };
</span><span class="cx">                 CDC8E4971BC6F10800594FEC /* video-without-audio.mp4 in Copy Resources */ = {isa = PBXBuildFile; fileRef = CDC8E48C1BC5C96200594FEC /* video-without-audio.mp4 */; };
</span><ins>+                CDCFA7AA1E45183200C2433D /* SampleMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDCFA7A91E45122F00C2433D /* SampleMap.cpp */; };
</ins><span class="cx">                 CDE195B51CFE0B880053D256 /* FullscreenTopContentInset.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CDE195B21CFE0ADE0053D256 /* FullscreenTopContentInset.html */; };
</span><span class="cx">                 CE06DF9B1E1851F200E570C9 /* SecurityOrigin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE06DF9A1E1851F200E570C9 /* SecurityOrigin.cpp */; };
</span><span class="cx">                 CE14F1A4181873B0001C2705 /* WillPerformClientRedirectToURLCrash.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CE14F1A2181873B0001C2705 /* WillPerformClientRedirectToURLCrash.html */; };
</span><span class="lines">@@ -1328,6 +1329,7 @@
</span><span class="cx">                 CDC8E48A1BC5C96200594FEC /* video-with-audio.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = &quot;video-with-audio.mp4&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 CDC8E48B1BC5C96200594FEC /* video-without-audio.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = &quot;video-without-audio.html&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 CDC8E48C1BC5C96200594FEC /* video-without-audio.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = &quot;video-without-audio.mp4&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                CDCFA7A91E45122F00C2433D /* SampleMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SampleMap.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 CDE195B21CFE0ADE0053D256 /* FullscreenTopContentInset.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = FullscreenTopContentInset.html; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 CDE195B31CFE0ADE0053D256 /* FullscreenTopContentInset.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FullscreenTopContentInset.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 CE06DF9A1E1851F200E570C9 /* SecurityOrigin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecurityOrigin.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -1626,6 +1628,7 @@
</span><span class="cx">                                 83B88A331C80056D00BB2418 /* HTMLParserIdioms.cpp */,
</span><span class="cx">                                 14464012167A8305000BD218 /* LayoutUnit.cpp */,
</span><span class="cx">                                 CD225C071C45A69200140761 /* ParsedContentRange.cpp */,
</span><ins>+                                CDCFA7A91E45122F00C2433D /* SampleMap.cpp */,
</ins><span class="cx">                                 CE06DF9A1E1851F200E570C9 /* SecurityOrigin.cpp */,
</span><span class="cx">                                 41973B5C1AF22875006C7B36 /* SharedBuffer.cpp */,
</span><span class="cx">                                 A17991891E1CA24100A505ED /* SharedBufferTest.cpp */,
</span><span class="lines">@@ -2754,6 +2757,7 @@
</span><span class="cx">                                 7CCE7F191A411AE600447C4C /* WebArchive.cpp in Sources */,
</span><span class="cx">                                 2D4CF8BD1D8360CC0001CE8D /* WKThumbnailView.mm in Sources */,
</span><span class="cx">                                 7C83E04C1D0A641800FEBCF3 /* WebCoreNSURLSession.mm in Sources */,
</span><ins>+                                CDCFA7AA1E45183200C2433D /* SampleMap.cpp in Sources */,
</ins><span class="cx">                                 7CCE7F1A1A411AE600447C4C /* WebCoreStatisticsWithNoWebProcess.cpp in Sources */,
</span><span class="cx">                                 7CCE7EAB1A411A2400447C4C /* WebKitAgnosticTest.mm in Sources */,
</span><span class="cx">                                 51714EB81CF8CA17004723C4 /* WebProcessKillIDBCleanup.mm in Sources */,
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWTFMediaTimecpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp (211745 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp        2017-02-06 20:49:25 UTC (rev 211745)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/MediaTime.cpp        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -85,6 +85,8 @@
</span><span class="cx">     EXPECT_EQ(MediaTime(1, 1) != MediaTime(2, 1), true);
</span><span class="cx">     EXPECT_EQ(MediaTime(2, 1) == MediaTime(2, 1), true);
</span><span class="cx">     EXPECT_EQ(MediaTime(2, 1) == MediaTime(4, 2), true);
</span><ins>+    EXPECT_TRUE((bool)MediaTime(1, 1));
+    EXPECT_TRUE(!MediaTime(0, 1));
</ins><span class="cx"> 
</span><span class="cx">     // Addition Operators
</span><span class="cx">     EXPECT_EQ(MediaTime::positiveInfiniteTime() + MediaTime::positiveInfiniteTime(), MediaTime::positiveInfiniteTime());
</span><span class="lines">@@ -158,8 +160,6 @@
</span><span class="cx">     EXPECT_EQ(abs(MediaTime::invalidTime()), MediaTime::invalidTime());
</span><span class="cx">     EXPECT_EQ(abs(MediaTime(1, 1)), MediaTime(1, 1));
</span><span class="cx">     EXPECT_EQ(abs(MediaTime(-1, 1)), MediaTime(1, 1));
</span><del>-    EXPECT_EQ(abs(MediaTime(-1, -1)), MediaTime(-1, -1));
-    EXPECT_EQ(abs(MediaTime(1, -1)), MediaTime(-1, -1));
</del><span class="cx"> 
</span><span class="cx">     // Floating Point Functions
</span><span class="cx">     EXPECT_EQ(MediaTime::createWithFloat(1.0f), MediaTime(1, 1));
</span><span class="lines">@@ -200,14 +200,14 @@
</span><span class="cx">     // Overflow Behavior
</span><span class="cx">     EXPECT_EQ(MediaTime::createWithFloat(pow(2.0f, 64.0f)), MediaTime::positiveInfiniteTime());
</span><span class="cx">     EXPECT_EQ(MediaTime::createWithFloat(-pow(2.0f, 64.0f)), MediaTime::negativeInfiniteTime());
</span><del>-    EXPECT_EQ(MediaTime::createWithFloat(pow(2.0f, 63.0f), 2).timeScale(), 1);
-    EXPECT_EQ(MediaTime::createWithFloat(pow(2.0f, 63.0f), 3).timeScale(), 1);
</del><ins>+    EXPECT_EQ(MediaTime::createWithFloat(pow(2.0f, 63.0f), 2).timeScale(), 1U);
+    EXPECT_EQ(MediaTime::createWithFloat(pow(2.0f, 63.0f), 3).timeScale(), 1U);
</ins><span class="cx">     EXPECT_EQ(MediaTime::createWithDouble(pow(2.0, 64.0)), MediaTime::positiveInfiniteTime());
</span><span class="cx">     EXPECT_EQ(MediaTime::createWithDouble(-pow(2.0, 64.0)), MediaTime::negativeInfiniteTime());
</span><del>-    EXPECT_EQ(MediaTime::createWithDouble(pow(2.0, 63.0), 2).timeScale(), 1);
-    EXPECT_EQ(MediaTime::createWithDouble(pow(2.0, 63.0), 3).timeScale(), 1);
-    EXPECT_EQ((MediaTime(numeric_limits&lt;int64_t&gt;::max(), 2) + MediaTime(numeric_limits&lt;int64_t&gt;::max(), 2)).timeScale(), 1);
-    EXPECT_EQ((MediaTime(numeric_limits&lt;int64_t&gt;::min(), 2) - MediaTime(numeric_limits&lt;int64_t&gt;::max(), 2)).timeScale(), 1);
</del><ins>+    EXPECT_EQ(MediaTime::createWithDouble(pow(2.0, 63.0), 2).timeScale(), 1U);
+    EXPECT_EQ(MediaTime::createWithDouble(pow(2.0, 63.0), 3).timeScale(), 1U);
+    EXPECT_EQ((MediaTime(numeric_limits&lt;int64_t&gt;::max(), 2) + MediaTime(numeric_limits&lt;int64_t&gt;::max(), 2)).timeScale(), 1U);
+    EXPECT_EQ((MediaTime(numeric_limits&lt;int64_t&gt;::min(), 2) - MediaTime(numeric_limits&lt;int64_t&gt;::max(), 2)).timeScale(), 1U);
</ins><span class="cx">     EXPECT_EQ(MediaTime(numeric_limits&lt;int64_t&gt;::max(), 1) + MediaTime(numeric_limits&lt;int64_t&gt;::max(), 1), MediaTime::positiveInfiniteTime());
</span><span class="cx">     EXPECT_EQ(MediaTime(numeric_limits&lt;int64_t&gt;::min(), 1) + MediaTime(numeric_limits&lt;int64_t&gt;::min(), 1), MediaTime::negativeInfiniteTime());
</span><span class="cx">     EXPECT_EQ(MediaTime(numeric_limits&lt;int64_t&gt;::min(), 1) - MediaTime(numeric_limits&lt;int64_t&gt;::max(), 1), MediaTime::negativeInfiniteTime());
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebCoreSampleMapcpp"></a>
<div class="addfile"><h4>Added: trunk/Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp (0 => 211746)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp                                (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp        2017-02-06 21:49:24 UTC (rev 211746)
</span><span class="lines">@@ -0,0 +1,224 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+
+#if ENABLE(MEDIA_SOURCE)
+
+#include &quot;Test.h&quot;
+#include &lt;WebCore/MediaSample.h&gt;
+#include &lt;WebCore/SampleMap.h&gt;
+
+namespace WTF {
+inline std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, const MediaTime&amp; time)
+{
+    if (time.hasDoubleValue())
+        os &lt;&lt; &quot;{ &quot; &lt;&lt; time.toDouble() &lt;&lt; &quot; }&quot;;
+    else
+        os &lt;&lt; &quot;{ &quot; &lt;&lt; time.timeValue() &lt;&lt; &quot; / &quot; &lt;&lt; time.timeScale() &lt;&lt; &quot;, &quot; &lt;&lt; time.toDouble() &lt;&lt; &quot; }&quot;;
+    return os;
+}
+}
+
+using namespace WebCore;
+
+namespace TestWebKitAPI {
+
+class TestSample : public MediaSample {
+public:
+    static Ref&lt;TestSample&gt; create(const MediaTime&amp; presentationTime, const MediaTime&amp; decodeTime, const MediaTime&amp; duration, SampleFlags flags)
+    {
+        return adoptRef(*new TestSample(presentationTime, decodeTime, duration, flags));
+    }
+    
+    MediaTime presentationTime() const final { return m_presentationTime; }
+    MediaTime decodeTime() const final { return m_decodeTime; }
+    MediaTime duration() const final { return m_duration; }
+    AtomicString trackID() const final { return m_trackID; }
+    void setTrackID(const String&amp; trackID) final { m_trackID = trackID; }
+    size_t sizeInBytes() const final { return m_sizeInBytes; }
+    FloatSize presentationSize() const final { return m_presentationSize; }
+    void offsetTimestampsBy(const MediaTime&amp; offset) final { m_presentationTime += offset; m_decodeTime += offset; }
+    void setTimestamps(const MediaTime&amp; presentationTime, const MediaTime&amp; decodeTime) final {
+        m_presentationTime = presentationTime;
+        m_decodeTime = decodeTime;
+    };
+    bool isDivisable() const final { return false; }
+    std::pair&lt;RefPtr&lt;MediaSample&gt;, RefPtr&lt;MediaSample&gt;&gt; divide(const MediaTime&amp; presentationTime) final { return { }; }
+    Ref&lt;MediaSample&gt; createNonDisplayingCopy() const final {
+        return create(m_presentationTime, m_decodeTime, m_duration, static_cast&lt;SampleFlags&gt;(m_flags | IsNonDisplaying));
+    }
+    SampleFlags flags() const final { return m_flags; }
+    PlatformSample platformSample() final { return { PlatformSample::None, {nullptr}}; }
+    void dump(PrintStream&amp;) const final { }
+
+private:
+    TestSample(const MediaTime&amp; presentationTime, const MediaTime&amp; decodeTime, const MediaTime&amp; duration, SampleFlags flags)
+        : m_presentationTime(presentationTime)
+        , m_decodeTime(decodeTime)
+        , m_duration(duration)
+        , m_flags(flags)
+    {
+    }
+
+    MediaTime m_presentationTime;
+    MediaTime m_decodeTime;
+    MediaTime m_duration;
+    FloatSize m_presentationSize;
+    AtomicString m_trackID;
+    size_t m_sizeInBytes { 0 };
+    SampleFlags m_flags { None };
+};
+
+class SampleMapTest : public testing::Test {
+public:
+    void SetUp() final {
+        map.addSample(TestSample::create(MediaTime(0, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::IsSync));
+        map.addSample(TestSample::create(MediaTime(1, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        map.addSample(TestSample::create(MediaTime(2, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        map.addSample(TestSample::create(MediaTime(3, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        map.addSample(TestSample::create(MediaTime(4, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        map.addSample(TestSample::create(MediaTime(5, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::IsSync));
+        map.addSample(TestSample::create(MediaTime(6, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        map.addSample(TestSample::create(MediaTime(7, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        map.addSample(TestSample::create(MediaTime(8, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        map.addSample(TestSample::create(MediaTime(9, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        // Gap at MediaTime(10, 1) -&gt; MediaTime(11, 1);
+        map.addSample(TestSample::create(MediaTime(11, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::IsSync));
+        map.addSample(TestSample::create(MediaTime(12, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        map.addSample(TestSample::create(MediaTime(13, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        map.addSample(TestSample::create(MediaTime(14, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        map.addSample(TestSample::create(MediaTime(15, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::IsSync));
+        map.addSample(TestSample::create(MediaTime(16, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        map.addSample(TestSample::create(MediaTime(17, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        map.addSample(TestSample::create(MediaTime(18, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+        map.addSample(TestSample::create(MediaTime(19, 1), MediaTime(0, 1), MediaTime(1, 1), MediaSample::None));
+    }
+
+    SampleMap map;
+};
+
+TEST_F(SampleMapTest, findSampleWithPresentationTime)
+{
+    auto&amp; presentationMap = map.presentationOrder();
+    EXPECT_EQ(MediaTime(0, 1), presentationMap.findSampleWithPresentationTime(MediaTime(0, 1))-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(19, 1), presentationMap.findSampleWithPresentationTime(MediaTime(19, 1))-&gt;second-&gt;presentationTime());
+    EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleWithPresentationTime(MediaTime(-1, 1)));
+    EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleWithPresentationTime(MediaTime(10, 1)));
+    EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleWithPresentationTime(MediaTime(20, 1)));
+    EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleWithPresentationTime(MediaTime(1, 2)));
+}
+
+TEST_F(SampleMapTest, findSampleContainingPresentationTime)
+{
+    auto&amp; presentationMap = map.presentationOrder();
+    EXPECT_EQ(MediaTime(0, 1), presentationMap.findSampleContainingPresentationTime(MediaTime(0, 1))-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(19, 1), presentationMap.findSampleContainingPresentationTime(MediaTime(19, 1))-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(0, 1), presentationMap.findSampleContainingPresentationTime(MediaTime(1, 2))-&gt;second-&gt;presentationTime());
+    EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleContainingPresentationTime(MediaTime(-1, 1)));
+    EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleContainingPresentationTime(MediaTime(10, 1)));
+    EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleContainingPresentationTime(MediaTime(20, 1)));
+}
+
+TEST_F(SampleMapTest, findSampleStartingOnOrAfterPresentationTime)
+{
+    auto&amp; presentationMap = map.presentationOrder();
+    EXPECT_EQ(MediaTime(0, 1), presentationMap.findSampleStartingOnOrAfterPresentationTime(MediaTime(0, 1))-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(19, 1), presentationMap.findSampleStartingOnOrAfterPresentationTime(MediaTime(19, 1))-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(1, 1), presentationMap.findSampleStartingOnOrAfterPresentationTime(MediaTime(1, 2))-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(0, 1), presentationMap.findSampleStartingOnOrAfterPresentationTime(MediaTime(-1, 1))-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(11, 1), presentationMap.findSampleStartingOnOrAfterPresentationTime(MediaTime(10, 1))-&gt;second-&gt;presentationTime());
+    EXPECT_TRUE(presentationMap.end() == presentationMap.findSampleContainingPresentationTime(MediaTime(20, 1)));
+}
+
+TEST_F(SampleMapTest, findSamplesBetweenPresentationTimes)
+{
+    auto&amp; presentationMap = map.presentationOrder();
+    auto iterator_range = presentationMap.findSamplesBetweenPresentationTimes(MediaTime(0, 1), MediaTime(1, 1));
+    EXPECT_EQ(MediaTime(0, 1), iterator_range.first-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(1, 1), iterator_range.second-&gt;second-&gt;presentationTime());
+
+    iterator_range = presentationMap.findSamplesBetweenPresentationTimes(MediaTime(1, 2), MediaTime(3, 2));
+    EXPECT_EQ(MediaTime(1, 1), iterator_range.first-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(2, 1), iterator_range.second-&gt;second-&gt;presentationTime());
+
+    iterator_range = presentationMap.findSamplesBetweenPresentationTimes(MediaTime(9, 1), MediaTime(21, 1));
+    EXPECT_EQ(MediaTime(9, 1), iterator_range.first-&gt;second-&gt;presentationTime());
+    EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+
+    iterator_range = presentationMap.findSamplesBetweenPresentationTimes(MediaTime(-1, 1), MediaTime(0, 1));
+    EXPECT_TRUE(presentationMap.end() == iterator_range.first);
+    EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+
+    iterator_range = presentationMap.findSamplesBetweenPresentationTimes(MediaTime(19, 2), MediaTime(10, 1));
+    EXPECT_TRUE(presentationMap.end() == iterator_range.first);
+    EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+
+    iterator_range = presentationMap.findSamplesBetweenPresentationTimes(MediaTime(20, 1), MediaTime(21, 1));
+    EXPECT_TRUE(presentationMap.end() == iterator_range.first);
+    EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+}
+
+TEST_F(SampleMapTest, findSamplesWithinPresentationRange)
+{
+    auto&amp; presentationMap = map.presentationOrder();
+    auto iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(0, 1), MediaTime(1, 1));
+    EXPECT_EQ(MediaTime(1, 1), iterator_range.first-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(2, 1), iterator_range.second-&gt;second-&gt;presentationTime());
+
+    iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(1, 2), MediaTime(3, 2));
+    EXPECT_EQ(MediaTime(1, 1), iterator_range.first-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(2, 1), iterator_range.second-&gt;second-&gt;presentationTime());
+
+    iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(9, 1), MediaTime(21, 1));
+    EXPECT_EQ(MediaTime(11, 1), iterator_range.first-&gt;second-&gt;presentationTime());
+    EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+
+    iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(-1, 1), MediaTime(0, 1));
+    EXPECT_EQ(MediaTime(0, 1), iterator_range.first-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(1, 1), iterator_range.second-&gt;second-&gt;presentationTime());
+
+    iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(10, 1), MediaTime(21, 2));
+    EXPECT_TRUE(presentationMap.end() == iterator_range.first);
+    EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+
+    iterator_range = presentationMap.findSamplesWithinPresentationRange(MediaTime(20, 1), MediaTime(21, 1));
+    EXPECT_TRUE(presentationMap.end() == iterator_range.first);
+    EXPECT_TRUE(presentationMap.end() == iterator_range.second);
+}
+
+TEST_F(SampleMapTest, reverseFindSampleBeforePresentationTime)
+{
+    auto&amp; presentationMap = map.presentationOrder();
+    EXPECT_EQ(MediaTime(0, 1), presentationMap.reverseFindSampleBeforePresentationTime(MediaTime(0, 1))-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(9, 1), presentationMap.reverseFindSampleBeforePresentationTime(MediaTime(10, 1))-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(19, 1), presentationMap.reverseFindSampleBeforePresentationTime(MediaTime(19, 1))-&gt;second-&gt;presentationTime());
+    EXPECT_EQ(MediaTime(19, 1), presentationMap.reverseFindSampleBeforePresentationTime(MediaTime(21, 1))-&gt;second-&gt;presentationTime());
+    EXPECT_TRUE(presentationMap.rend() == presentationMap.reverseFindSampleBeforePresentationTime(MediaTime(-1, 1)));
+}
+
+}
+
+#endif // ENABLE(MEDIA_SOURCE)
</ins></span></pre>
</div>
</div>

</body>
</html>