Import Cobalt 13.95843
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 96e2ce3..6b70bdc 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-95615
\ No newline at end of file
+95843
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gni b/src/cobalt/build/config/base.gni
index 2bc87b6..834371c 100644
--- a/src/cobalt/build/config/base.gni
+++ b/src/cobalt/build/config/base.gni
@@ -241,7 +241,7 @@
 # The URL of default build time splash screen - see
 #   cobalt/doc/splash_screen.md for information about this.
 if (!defined(fallback_splash_screen_url)) {
-  fallback_splash_screen_url = "h5vcc-embedded://youtube_splash_screen.html"
+  fallback_splash_screen_url = "none"
 }
 
 # Cache parameters
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index 110e70d..77cba3a 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -291,7 +291,7 @@
 
     # The URL of default build time splash screen - see
     #   cobalt/doc/splash_screen.md for information about this.
-    'fallback_splash_screen_url%': 'h5vcc-embedded://youtube_splash_screen.html',
+    'fallback_splash_screen_url%': 'none',
 
     # Cache parameters
 
diff --git a/src/cobalt/media/base/sbplayer_pipeline.cc b/src/cobalt/media/base/sbplayer_pipeline.cc
index 5752961..bf397d8 100644
--- a/src/cobalt/media/base/sbplayer_pipeline.cc
+++ b/src/cobalt/media/base/sbplayer_pipeline.cc
@@ -227,6 +227,7 @@
   scoped_ptr<StarboardPlayer> player_;
   bool suspended_;
   bool stopped_;
+  bool ended_;
 
   VideoDumper video_dumper_;
 
@@ -250,6 +251,7 @@
       set_bounds_helper_(new SbPlayerSetBoundsHelper),
       suspended_(false),
       stopped_(false),
+      ended_(false),
       video_dumper_(kVideoDumpFileName) {}
 
 SbPlayerPipeline::~SbPlayerPipeline() { DCHECK(!player_); }
@@ -364,6 +366,7 @@
   }
 
   player_->PrepareForSeek();
+  ended_ = false;
 
   DCHECK(seek_cb_.is_null());
   DCHECK(!seek_cb.is_null());
@@ -429,6 +432,9 @@
   if (!player_) {
     return TimeDelta();
   }
+  if (ended_) {
+    return duration_;
+  }
   base::TimeDelta media_time;
   player_->GetInfo(&statistics_.video_frames_decoded,
                    &statistics_.video_frames_dropped, &media_time);
@@ -826,6 +832,7 @@
       break;
     case kSbPlayerStateEndOfStream:
       ended_cb_.Run(PIPELINE_OK);
+      ended_ = true;
       break;
     case kSbPlayerStateDestroyed:
       break;
diff --git a/src/cobalt/renderer/rasterizer/lib/exported/graphics.h b/src/cobalt/renderer/rasterizer/lib/exported/graphics.h
index 7b1d4bd..69e2125 100644
--- a/src/cobalt/renderer/rasterizer/lib/exported/graphics.h
+++ b/src/cobalt/renderer/rasterizer/lib/exported/graphics.h
@@ -14,6 +14,12 @@
 
 // All imported functions defined below MUST be implemented by client
 // applications.
+// All of callbacks in here will happen on Cobalt's rasterization thread
+// (i.e. the thread which owns the GL context). To guarantee no callbacks
+// are missed, all callbacks should be set before the rasterization thread
+// has started. Any other functions in here (e.g.
+// CbLibGrapicsGetMainTextureHandle) are also not thread-safe and should only be
+// invoked on the rasterization thread during one of the provided callbacks.
 
 #ifndef COBALT_RENDERER_RASTERIZER_LIB_EXPORTED_GRAPHICS_H_
 #define COBALT_RENDERER_RASTERIZER_LIB_EXPORTED_GRAPHICS_H_
@@ -26,8 +32,7 @@
 #endif
 
 typedef void (*CbLibGraphicsContextCreatedCallback)(void* context);
-typedef void (*CbLibGraphicsBeginRenderFrameCallback)(
-    void* context, intptr_t render_tree_texture_handle);
+typedef void (*CbLibGraphicsBeginRenderFrameCallback)(void* context);
 typedef void (*CbLibGraphicsEndRenderFrameCallback)(void* context);
 
 // Sets a callback which will be called from the rasterization thread once the
@@ -36,12 +41,19 @@
     void* context, CbLibGraphicsContextCreatedCallback callback);
 
 // Sets a callback which will be called as often as the platform can swap
-// buffers from the rasterization thread. |render_tree_texture_handle| which is
-// provided to the callback corresponds to a GLint texture ID for the current
-// RenderTree.
+// buffers from the rasterization thread.
 SB_EXPORT_PLATFORM void CbLibGraphicsSetBeginRenderFrameCallback(
     void* context, CbLibGraphicsBeginRenderFrameCallback callback);
 
+// Returns the texture ID for the current RenderTree. This should be
+// re-retrieved each frame in the event that the underlying texture has
+// changed. This method will return 0 if there is not yet a valid texture ID.
+// This will never return anything other than 0 until after the first frame is
+// started / the CbLibGraphicsBeginRenderFrameCallback is invoked (assuming the
+// callback is set). This is not thread-safe and should be invoked on the
+// rasterization thread only.
+SB_EXPORT_PLATFORM intptr_t CbLibGrapicsGetMainTextureHandle();
+
 // Sets a callback which will be called at the end of rendering, after swap
 // buffers has been called.
 SB_EXPORT_PLATFORM void CbLibGraphicsSetEndRenderFrameCallback(
diff --git a/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc b/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc
index 00dc1ee..fb2acaa 100644
--- a/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc
@@ -126,6 +126,8 @@
 EndRenderFrame::LazyCallback g_end_render_frame_callback =
     LAZY_INSTANCE_INITIALIZER;
 
+ExternalRasterizer::Impl* g_external_rasterizer_impl = nullptr;
+
 }  // namespace
 
 namespace cobalt {
@@ -148,6 +150,8 @@
 
   void MakeCurrent() { hardware_rasterizer_.MakeCurrent(); }
 
+  intptr_t GetMainTextureHandle();
+
  private:
   void RenderOffscreenVideo(render_tree::FilterNode* map_to_mesh_filter_node);
 
@@ -196,6 +200,8 @@
       video_projection_type_(kCbLibVideoProjectionTypeNone),
       video_stereo_mode_(render_tree::StereoMode::kMono),
       video_texture_rgb_(0) {
+  CHECK(!g_external_rasterizer_impl);
+  g_external_rasterizer_impl = this;
   options_.flags = Rasterizer::kSubmitFlags_Clear;
   graphics_context_->MakeCurrent();
 
@@ -322,8 +328,7 @@
 
   // TODO: Allow clients to specify arbitrary subtrees to render into
   // different textures?
-  const intptr_t texture_handle = main_texture_->GetPlatformHandle();
-  g_begin_render_frame_callback.Get().Run(texture_handle);
+  g_begin_render_frame_callback.Get().Run();
   graphics_context_->SwapBuffers(render_target_egl);
   g_end_render_frame_callback.Get().Run();
 }
@@ -332,6 +337,10 @@
   return hardware_rasterizer_.GetResourceProvider();
 }
 
+intptr_t ExternalRasterizer::Impl::GetMainTextureHandle() {
+  return main_texture_->GetPlatformHandle();
+}
+
 void ExternalRasterizer::Impl::RenderOffscreenVideo(
     render_tree::FilterNode* map_to_mesh_filter_node) {
   DCHECK(map_to_mesh_filter_node);
@@ -483,3 +492,14 @@
       callback ? base::Bind(callback, context)
                : base::Bind(&EndRenderFrame::DefaultImplementation);
 }
+
+intptr_t CbLibGrapicsGetMainTextureHandle() {
+  DCHECK(g_external_rasterizer_impl);
+  if (!g_external_rasterizer_impl) {
+    LOG(WARNING) << __FUNCTION__
+                 << "ExternalRasterizer not yet created; unable to progress.";
+    return 0;
+  }
+
+  return g_external_rasterizer_impl->GetMainTextureHandle();
+}
diff --git a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
index 6882f4a..5489d25 100644
--- a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
+++ b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
@@ -312,8 +312,9 @@
       (*player_worker_.*update_player_state_cb_)(kSbPlayerStateEndOfStream);
     }
 
-    scoped_refptr<VideoFrame> frame =
-        video_renderer_->GetCurrentFrame(audio_renderer_->GetCurrentTime());
+    scoped_refptr<VideoFrame> frame = video_renderer_->GetCurrentFrame(
+        audio_renderer_->GetCurrentTime(),
+        audio_renderer_->IsEndOfStreamPlayed());
     player_worker_->UpdateDroppedVideoFrames(
         video_renderer_->GetDroppedFrames());
 
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc b/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc
index badd1f1..65f9bc9 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc
@@ -87,7 +87,8 @@
 }
 
 scoped_refptr<VideoFrame> VideoRendererImpl::GetCurrentFrame(
-    SbMediaTime media_time) {
+    SbMediaTime media_time,
+    bool audio_eos_reached) {
   SB_DCHECK(thread_checker_.CalledOnValidThread());
   ScopedLock lock(mutex_);
 
@@ -103,6 +104,12 @@
     frames_.pop_front();
   }
 
+  if (audio_eos_reached) {
+    while (frames_.size() > 1) {
+      frames_.pop_back();
+    }
+  }
+
   last_displayed_frame_ = frames_.front();
   return last_displayed_frame_;
 }
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.h b/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.h
index c69aa8b..58e8fd6 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.h
@@ -49,7 +49,8 @@
 
   void Seek(SbMediaTime seek_to_pts) SB_OVERRIDE;
 
-  scoped_refptr<VideoFrame> GetCurrentFrame(SbMediaTime media_time) SB_OVERRIDE;
+  scoped_refptr<VideoFrame> GetCurrentFrame(SbMediaTime media_time,
+                                            bool audio_eos_reached) SB_OVERRIDE;
 
   bool IsEndOfStreamWritten() const SB_OVERRIDE {
     return end_of_stream_written_;
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_internal.h b/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
index 85906bf..5f1a284 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
@@ -39,7 +39,8 @@
   virtual void WriteSample(const scoped_refptr<InputBuffer>& input_buffer) = 0;
   virtual void WriteEndOfStream() = 0;
   virtual void Seek(SbMediaTime seek_to_pts) = 0;
-  virtual scoped_refptr<VideoFrame> GetCurrentFrame(SbMediaTime media_time) = 0;
+  virtual scoped_refptr<VideoFrame> GetCurrentFrame(SbMediaTime media_time,
+                                                    bool audio_eos_reached) = 0;
   virtual bool IsEndOfStreamWritten() const = 0;
   virtual bool IsEndOfStreamPlayed() const = 0;
   virtual bool CanAcceptMoreData() const = 0;
diff --git a/src/third_party/mozjs-45/js/src/gc/GCTrace.cpp b/src/third_party/mozjs-45/js/src/gc/GCTrace.cpp
index 48d9e7c..747e6ab 100644
--- a/src/third_party/mozjs-45/js/src/gc/GCTrace.cpp
+++ b/src/third_party/mozjs-45/js/src/gc/GCTrace.cpp
@@ -4,7 +4,155 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifdef JS_GC_TRACE
+#if defined(COBALT) && defined(COBALT_JS_GC_TRACE)
+
+#include "gc/GCTrace.h"
+#include "jscntxt.h"
+#include "jsfriendapi.h"
+#include "vm/Runtime.h"
+
+#include "nb/thread_local_object.h"
+#include "starboard/log.h"
+
+#include <unordered_map>
+
+namespace js {
+namespace gc {
+
+namespace {
+
+// A simple struct to bundle up both when and where a |GCThing| was allocated.
+struct AllocationInfo {
+  std::string stack;
+  SbTimeMonotonic time;
+};
+
+// A simple struct to bundle up all information relevant to the current thread
+// that we are tracing allocations for, which includes a mapping from |Cell|s
+// to their corresponding |AllocationInfo|, as well as the last time that we
+// dumped |thing2info|.
+struct TraceData {
+  std::unordered_map<Cell*, AllocationInfo> thing2info;
+  SbTimeMonotonic last_dump_time;
+};
+nb::ThreadLocalObject<TraceData> tlo_trace_data;
+
+const SbTimeMonotonic kDumpInterval = 15 * 60 * 1000 * 1000;
+const int kStackSize = 10;
+
+// Return the top first |n| stack frames of |cx| as a single string.  |cx|
+// must not be NULL.
+std::string DumpBacktrace(JSContext* cx, int n) {
+  SB_DCHECK(cx != NULL);
+
+  Sprinter sprinter(cx);
+  sprinter.init();
+  size_t depth = 0;
+
+  for (AllFramesIter it(cx); !it.done(); ++it, ++depth) {
+    if (depth > n) {
+      break;
+    }
+
+    const char* filename = JS_GetScriptFilename(it.script());
+    unsigned column = 0;
+    unsigned line = PCToLineNumber(it.script(), it.pc(), &column);
+
+    if (depth != 0) {
+      sprinter.printf(" ");
+    }
+
+    sprinter.printf("#%d %s:%d:%d", depth, filename, line, column);
+  }
+
+  return std::string(sprinter.string(),
+                     sprinter.string() + sprinter.getOffset());
+}
+
+// Add |thing| and its corresponding |AllocationInfo| to |thing2info|.
+void StartTrackingThing(Cell* thing) {
+  if (!thing) {
+    return;
+  }
+
+  auto* rt = thing->runtimeFromMainThread();
+  auto* cx = rt->contextList.getFirst();
+  // JavaScript allocations can still happen during the brief period of time
+  // in between when we destroy the sole |JSContext| and then finally destroy
+  // the entire |JSRuntime|.  They should be counted as having had no stack.
+  auto stack = cx ? DumpBacktrace(cx, kStackSize) : "";
+  auto& thing2info = tlo_trace_data.GetOrCreate()->thing2info;
+  thing2info[thing] = {stack, SbTimeGetMonotonicNow()};
+}
+
+// Remove |thing| from |tlo_thing2info|.  |tlo_thing2info| is expected to
+// actually contain |thing|, and will error if it does not.
+void StopTrackingThing(Cell* thing) {
+  if (!thing) {
+    return;
+  }
+
+  auto& thing2info = tlo_trace_data.GetOrCreate()->thing2info;
+  auto erased_count = thing2info.erase(thing);
+  SB_DCHECK(erased_count == 1);
+}
+
+// Dump the current state of the heap if |kDumpInterval| time has passed since
+// the last dump.
+void MaybeDump() {
+  auto& trace_data = *tlo_trace_data.GetOrCreate();
+  auto now = SbTimeGetMonotonicNow();
+  auto diff = now - trace_data.last_dump_time;
+  if (diff > kDumpInterval) {
+    trace_data.last_dump_time = now;
+    auto thread_id = SbThreadGetId();
+    SB_LOG(INFO) << "BEGIN_HEAP_DUMP: " << thread_id << " " << now;
+    for (const auto& pair : trace_data.thing2info) {
+      SB_LOG(INFO) << "HEAP_DUMP: " << thread_id << " "
+                   << static_cast<void*>(pair.first) << " "
+                   << pair.second.time << " " << pair.second.stack;
+    }
+    SB_LOG(INFO) << "END_HEAP_DUMP: " << thread_id << " " << now;
+  }
+}
+
+}  // namespace
+
+bool InitTrace(GCRuntime& gc) { return true; }
+
+void FinishTrace() {}
+
+bool TraceEnabled() { return true; }
+
+void TraceNurseryAlloc(Cell* thing, size_t size) {
+  // Don't do anything.  We will trace |thing| if it ends up getting
+  // tenured.
+}
+
+void TraceTenuredAlloc(Cell* thing, AllocKind kind) {
+  StartTrackingThing(thing);
+}
+
+void TraceCreateObject(JSObject* object) {}
+
+void TraceMinorGCStart() {}
+
+void TracePromoteToTenured(Cell* src, Cell* dst) { StartTrackingThing(dst); }
+
+void TraceMinorGCEnd() { MaybeDump(); }
+
+void TraceMajorGCStart() {}
+
+void TraceTenuredFinalize(Cell* thing) { StopTrackingThing(thing); }
+
+void TraceMajorGCEnd() { MaybeDump(); }
+
+void TraceTypeNewScript(js::ObjectGroup* group) {}
+
+}  // namespace gc
+}  // namespace js
+
+#elif defined(JS_GC_TRACE)
 
 #include "gc/GCTrace.h"
 
diff --git a/src/third_party/mozjs-45/js/src/gc/GCTrace.h b/src/third_party/mozjs-45/js/src/gc/GCTrace.h
index c34f6c5..30c2129 100644
--- a/src/third_party/mozjs-45/js/src/gc/GCTrace.h
+++ b/src/third_party/mozjs-45/js/src/gc/GCTrace.h
@@ -15,7 +15,7 @@
 
 namespace gc {
 
-#ifdef JS_GC_TRACE
+#if (defined(COBALT) && defined(COBALT_JS_GC_TRACE)) || defined(JS_GC_TRACE)
 
 extern bool InitTrace(GCRuntime& gc);
 extern void FinishTrace();
diff --git a/src/third_party/mozjs-45/mozjs-45.gyp b/src/third_party/mozjs-45/mozjs-45.gyp
index 4bc4c17..54fe066 100644
--- a/src/third_party/mozjs-45/mozjs-45.gyp
+++ b/src/third_party/mozjs-45/mozjs-45.gyp
@@ -34,6 +34,9 @@
       # See vm/Probes.h for different values. This was the value set by the
       # configure script when building for linux-release.
       'JS_DEFAULT_JITREPORT_GRANULARITY=3',
+      # |COBALT_JS_GC_TRACE| can be set here to enable the JSGCThingTracer,
+      # which logs GCThings that are alive in the JavaScript heap, along with
+      # where each thing was allocated, every 15 minutes.
     ],
     'common_include_dirs': [
       '<(DEPTH)/third_party/mozjs-45/js/src',