Import Cobalt 20.master.0.243969

Includes the following patches:
  https://cobalt-review.googlesource.com/c/cobalt/+/5610
    by r97922153@gmail.com
diff --git a/src/starboard/shared/blittergles/blitter_flip_swap_chain.cc b/src/starboard/shared/blittergles/blitter_flip_swap_chain.cc
index bbfeb89..932e610 100644
--- a/src/starboard/shared/blittergles/blitter_flip_swap_chain.cc
+++ b/src/starboard/shared/blittergles/blitter_flip_swap_chain.cc
@@ -18,6 +18,7 @@
 
 #include "starboard/common/log.h"
 #include "starboard/common/recursive_mutex.h"
+#include "starboard/shared/blittergles/blitter_context.h"
 #include "starboard/shared/blittergles/blitter_internal.h"
 
 bool SbBlitterFlipSwapChain(SbBlitterSwapChain swap_chain) {
@@ -25,6 +26,14 @@
     SB_DLOG(ERROR) << ": Invalid swap chain.";
     return false;
   }
+  starboard::shared::blittergles::SbBlitterContextRegistry* context_registry =
+      starboard::shared::blittergles::GetBlitterContextRegistry();
+  starboard::ScopedLock registry_lock(context_registry->mutex);
+  SbBlitterContextPrivate::ScopedCurrentContext scoped_current_context(
+      context_registry->context, &swap_chain->render_target);
+  if (scoped_current_context.InitializationError()) {
+    return false;
+  }
 
   starboard::ScopedRecursiveLock lock(swap_chain->render_target.device->mutex);
   eglSwapBuffers(swap_chain->render_target.device->display,
diff --git a/src/starboard/shared/dlmalloc/page_internal.h b/src/starboard/shared/dlmalloc/page_internal.h
index b792207..040e362 100644
--- a/src/starboard/shared/dlmalloc/page_internal.h
+++ b/src/starboard/shared/dlmalloc/page_internal.h
@@ -62,9 +62,6 @@
 // actually have mmap(), we call that directly. Otherwise we use
 // platform-specific system allocators.
 //
-// Platforms that have OS support for the virtual region ("MORECORE") behavior
-// will enable SB_HAS_VIRTUAL_REGIONS in configuration_public.h.
-//
 // Platforms that support SbMap() must be at least starboard version 12 or
 // enable SB_HAS_MMAP in their configuration_public.h file. dlmalloc is very
 // flexible and if a platform can't implement virtual regions, it will use
@@ -76,7 +73,8 @@
 //
 // See also dlmalloc_config.h which controls some dlmalloc behavior.
 
-#if SB_HAS(VIRTUAL_REGIONS)
+#if SB_API_VERSION < SB_VIRTUAL_REGIONS_FLAG_DEPRECATED && \
+    SB_HAS(VIRTUAL_REGIONS)
 // Reserves a virtual address space |size_bytes| big, without mapping any
 // physical pages to that range, returning a pointer to the beginning of the
 // reserved virtual address range. To get memory that is actually usable and
@@ -103,7 +101,8 @@
 
 // How big of a virtual region dlmalloc should allocate.
 size_t SbPageGetVirtualRegionSize();
-#endif
+#endif  // SB_API_VERSION < SB_VIRTUAL_REGIONS_FLAG_DEPRECATED &&
+        // SB_HAS(VIRTUAL_REGIONS)
 
 #if SB_API_VERSION >= SB_MMAP_REQUIRED_VERSION || SB_HAS(MMAP)
 // Allocates |size_bytes| worth of physical memory pages and maps them into an
@@ -138,7 +137,7 @@
 #endif  // SB_API_VERSION >= SB_MMAP_REQUIRED_VERSION || SB_HAS(MMAP)
 
 // Returns the total amount, in bytes, of physical memory available. Should
-// always be a multiple of SB_MEMORY_PAGE_SIZE.
+// always be a multiple of kSbMemoryPageSize.
 size_t SbPageGetTotalPhysicalMemoryBytes();
 
 // Returns the amount, in bytes, of physical memory that hasn't yet been mapped.
@@ -146,7 +145,7 @@
 int64_t SbPageGetUnallocatedPhysicalMemoryBytes();
 
 // Returns the total amount, in bytes, currently allocated via Map().  Should
-// always be a multiple of SB_MEMORY_PAGE_SIZE.
+// always be a multiple of kSbMemoryPageSize.
 size_t SbPageGetMappedBytes();
 
 // Declaration of the allocator API.
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder_impl.cc b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder_impl.cc
index 8fe9577..fec161c 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder_impl.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder_impl.cc
@@ -43,12 +43,13 @@
   switch (audio_codec) {
     case kSbMediaAudioCodecAac:
       return AV_CODEC_ID_AAC;
-#if SB_HAS(AC3_AUDIO)
+#if SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION || SB_HAS(AC3_AUDIO)
     case kSbMediaAudioCodecAc3:
-      return AV_CODEC_ID_AC3;
+      return kSbHasAc3Audio ? AV_CODEC_ID_AC3 : AV_CODEC_ID_NONE;
     case kSbMediaAudioCodecEac3:
-      return AV_CODEC_ID_EAC3;
-#endif  // SB_HAS(AC3_AUDIO)
+      return kSbHasAc3Audio ? AV_CODEC_ID_EAC3 : AV_CODEC_ID_NONE;
+#endif  // SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION ||
+        // SB_HAS(AC3_AUDIO)
     case kSbMediaAudioCodecOpus:
       return AV_CODEC_ID_OPUS;
     default:
@@ -125,11 +126,9 @@
   packet.data = const_cast<uint8_t*>(input_buffer->data());
   packet.size = input_buffer->size();
 
-#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
-  ffmpeg_->av_frame_unref(av_frame_);
-#else   // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#if LIBAVUTIL_VERSION_INT < LIBAVUTIL_VERSION_52_8
   ffmpeg_->avcodec_get_frame_defaults(av_frame_);
-#endif  // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#endif  // LIBAVUTIL_VERSION_INT < LIBAVUTIL_VERSION_52_8
   int frame_decoded = 0;
   int result = ffmpeg_->avcodec_decode_audio4(codec_context_, av_frame_,
                                               &frame_decoded, &packet);
@@ -315,11 +314,11 @@
     return;
   }
 
-#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   av_frame_ = ffmpeg_->av_frame_alloc();
-#else   // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#else   // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   av_frame_ = ffmpeg_->avcodec_alloc_frame();
-#endif  // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#endif  // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   if (av_frame_ == NULL) {
     SB_LOG(ERROR) << "Unable to allocate audio frame";
     TeardownCodec();
@@ -329,12 +328,9 @@
 void AudioDecoderImpl<FFMPEG>::TeardownCodec() {
   if (codec_context_) {
     ffmpeg_->CloseCodec(codec_context_);
-    if (codec_context_->extradata_size) {
-      ffmpeg_->av_freep(&codec_context_->extradata);
-    }
-    ffmpeg_->av_freep(&codec_context_);
+    ffmpeg_->FreeContext(&codec_context_);
   }
-  ffmpeg_->av_freep(&av_frame_);
+  ffmpeg_->FreeFrame(&av_frame_);
 }
 
 }  // namespace ffmpeg
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_common.h b/src/starboard/shared/ffmpeg/ffmpeg_common.h
index b22b73d..61d562e 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_common.h
+++ b/src/starboard/shared/ffmpeg/ffmpeg_common.h
@@ -26,6 +26,10 @@
 
 #include "starboard/shared/internal_only.h"
 
+#ifndef LIBAVUTIL_VERSION_52_8
+#define LIBAVUTIL_VERSION_52_8 AV_VERSION_INT(52, 8, 0)
+#endif
+
 #if !defined(LIBAVUTIL_VERSION_MAJOR)
 #error "LIBAVUTIL_VERSION_MAJOR not defined"
 #endif  // !defined(LIBAVUTIL_VERSION_MAJOR)
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_dispatch.cc b/src/starboard/shared/ffmpeg/ffmpeg_dispatch.cc
index e037724..6344706 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_dispatch.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_dispatch.cc
@@ -42,6 +42,25 @@
   SbMutexRelease(&g_codec_mutex);
 }
 
+void FFMPEGDispatch::FreeFrame(AVFrame** frame) {
+#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
+  av_frame_free(frame);
+#else   // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
+  av_freep(frame);
+#endif  // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
+}
+
+void FFMPEGDispatch::FreeContext(AVCodecContext** avctx) {
+#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
+  avcodec_free_context(avctx);
+#else   // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
+  if (avctx->extradata_size) {
+    av_freep(&((*avctx)->extradata));
+  }
+  av_freep(avctx);
+#endif  // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
+}
+
 }  // namespace ffmpeg
 }  // namespace shared
 }  // namespace starboard
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_dispatch.h b/src/starboard/shared/ffmpeg/ffmpeg_dispatch.h
index 260a33a..4d70b66 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_dispatch.h
+++ b/src/starboard/shared/ffmpeg/ffmpeg_dispatch.h
@@ -53,6 +53,9 @@
   void* (*av_malloc)(size_t size);
   void (*av_freep)(void* ptr);
   AVFrame* (*av_frame_alloc)(void);
+#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
+  void (*av_frame_free)(AVFrame** frame);
+#endif  // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   void (*av_frame_unref)(AVFrame* frame);
   int (*av_samples_get_buffer_size)(int* linesize,
                                     int nb_channels,
@@ -75,6 +78,9 @@
 
   unsigned (*avcodec_version)(void);
   AVCodecContext* (*avcodec_alloc_context3)(const AVCodec* codec);
+#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
+  void (*avcodec_free_context)(AVCodecContext** avctx);
+#endif  // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   AVCodec* (*avcodec_find_decoder)(int id);
   int (*avcodec_close)(AVCodecContext* avctx);
   int (*avcodec_open2)(AVCodecContext* avctx,
@@ -108,6 +114,9 @@
   // this.
   int OpenCodec(AVCodecContext* codec_context, const AVCodec* codec);
   void CloseCodec(AVCodecContext* codec_context);
+
+  void FreeFrame(AVFrame** frame);
+  void FreeContext(AVCodecContext** avctx);
 };
 
 }  // namespace ffmpeg
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_dynamic_load_dispatch_impl.cc b/src/starboard/shared/ffmpeg/ffmpeg_dynamic_load_dispatch_impl.cc
index 1506cd5..69ddd5b 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_dynamic_load_dispatch_impl.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_dynamic_load_dispatch_impl.cc
@@ -244,6 +244,9 @@
   INITSYMBOL(avutil_, av_malloc);
   INITSYMBOL(avutil_, av_freep);
   INITSYMBOL(avutil_, av_frame_alloc);
+#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
+  INITSYMBOL(avutil_, av_frame_free);
+#endif  // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   INITSYMBOL(avutil_, av_frame_unref);
   INITSYMBOL(avutil_, av_samples_get_buffer_size);
   INITSYMBOL(avutil_, av_opt_set_int);
@@ -254,6 +257,9 @@
   INITSYMBOL(avcodec_, avcodec_version);
   SB_DCHECK(ffmpeg_->avcodec_version);
   INITSYMBOL(avcodec_, avcodec_alloc_context3);
+#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
+  INITSYMBOL(avcodec_, avcodec_free_context);
+#endif  // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   INITSYMBOL(avcodec_, avcodec_find_decoder);
   INITSYMBOL(avcodec_, avcodec_close);
   INITSYMBOL(avcodec_, avcodec_open2);
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_linked_dispatch_impl.cc b/src/starboard/shared/ffmpeg/ffmpeg_linked_dispatch_impl.cc
index a10330a..20d7d1b 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_linked_dispatch_impl.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_linked_dispatch_impl.cc
@@ -53,10 +53,11 @@
   SB_DCHECK(ffmpeg->avutil_version);
   INITSYMBOL(av_malloc);
   INITSYMBOL(av_freep);
-#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   INITSYMBOL(av_frame_alloc);
+  INITSYMBOL(av_frame_free);
   INITSYMBOL(av_frame_unref);
-#endif
+#endif  // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   INITSYMBOL(av_samples_get_buffer_size);
   INITSYMBOL(av_opt_set_int);
   INITSYMBOL(av_image_check_size);
@@ -66,6 +67,9 @@
   INITSYMBOL(avcodec_version);
   SB_DCHECK(ffmpeg->avcodec_version);
   INITSYMBOL(avcodec_alloc_context3);
+#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
+  INITSYMBOL(avcodec_free_context);
+#endif  // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   INITSYMBOL(avcodec_find_decoder);
   INITSYMBOL(avcodec_close);
   INITSYMBOL(avcodec_open2);
@@ -73,10 +77,10 @@
   INITSYMBOL(avcodec_decode_audio4);
   INITSYMBOL(avcodec_decode_video2);
   INITSYMBOL(avcodec_flush_buffers);
-#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 8, 0)
+#if LIBAVUTIL_VERSION_INT < LIBAVUTIL_VERSION_52_8
   INITSYMBOL(avcodec_alloc_frame);
   INITSYMBOL(avcodec_get_frame_defaults);
-#endif
+#endif  // LIBAVUTIL_VERSION_INT > LIBAVUTIL_VERSION_52_8
   INITSYMBOL(avcodec_align_dimensions2);
 
   // Load symbols from the avformat shared library.
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.cc b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.cc
index 26724c2..fac3b9b 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder_impl.cc
@@ -46,7 +46,7 @@
   return width * height * 3 / 2;
 }
 
-#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
 
 void ReleaseBuffer(void* opaque, uint8_t* data) {
   SbMemoryDeallocate(data);
@@ -60,7 +60,7 @@
   return video_decoder->AllocateBuffer(codec_context, frame, flags);
 }
 
-#else   // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#else   // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
 
 int AllocateBufferCallback(AVCodecContext* codec_context, AVFrame* frame) {
   VideoDecoderImpl<FFMPEG>* video_decoder =
@@ -75,7 +75,7 @@
   // The FFmpeg API expects us to zero the data pointers in this callback.
   SbMemorySet(frame->data, 0, sizeof(frame->data));
 }
-#endif  // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#endif  // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
 
 const bool g_registered =
     FFMPEGDispatch::RegisterSpecialization(FFMPEG,
@@ -248,11 +248,9 @@
 bool VideoDecoderImpl<FFMPEG>::DecodePacket(AVPacket* packet) {
   SB_DCHECK(packet != NULL);
 
-#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
-  ffmpeg_->av_frame_unref(av_frame_);
-#else   // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#if LIBAVUTIL_VERSION_INT < LIBAVUTIL_VERSION_52_8
   ffmpeg_->avcodec_get_frame_defaults(av_frame_);
-#endif  // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#endif  // LIBAVUTIL_VERSION_INT < LIBAVUTIL_VERSION_52_8
   int frame_decoded = 0;
   int decode_result = ffmpeg_->avcodec_decode_video2(codec_context_, av_frame_,
                                                      &frame_decoded, packet);
@@ -343,12 +341,12 @@
 #if defined(CODEC_FLAG_EMU_EDGE)
   codec_context_->flags |= CODEC_FLAG_EMU_EDGE;
 #endif
-#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   codec_context_->get_buffer2 = AllocateBufferCallback;
-#else   // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#else   // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   codec_context_->get_buffer = AllocateBufferCallback;
   codec_context_->release_buffer = ReleaseBuffer;
-#endif  // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#endif  // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
 
   codec_context_->extradata = NULL;
   codec_context_->extradata_size = 0;
@@ -368,11 +366,11 @@
     return;
   }
 
-#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   av_frame_ = ffmpeg_->av_frame_alloc();
-#else   // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#else   // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   av_frame_ = ffmpeg_->avcodec_alloc_frame();
-#endif  // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#endif  // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
   if (av_frame_ == NULL) {
     SB_LOG(ERROR) << "Unable to allocate audio frame";
     TeardownCodec();
@@ -382,9 +380,9 @@
 void VideoDecoderImpl<FFMPEG>::TeardownCodec() {
   if (codec_context_) {
     ffmpeg_->CloseCodec(codec_context_);
-    ffmpeg_->av_freep(&codec_context_);
+    ffmpeg_->FreeContext(&codec_context_);
   }
-  ffmpeg_->av_freep(&av_frame_);
+  ffmpeg_->FreeFrame(&av_frame_);
 
   if (output_mode_ == kSbPlayerOutputModeDecodeToTexture) {
     ScopedLock lock(decode_target_mutex_);
@@ -418,7 +416,7 @@
   }
 }
 
-#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#if LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
 
 int VideoDecoderImpl<FFMPEG>::AllocateBuffer(AVCodecContext* codec_context,
                                              AVFrame* frame,
@@ -472,7 +470,7 @@
   return 0;
 }
 
-#else   // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#else   // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
 
 int VideoDecoderImpl<FFMPEG>::AllocateBuffer(AVCodecContext* codec_context,
                                              AVFrame* frame) {
@@ -527,7 +525,7 @@
 
   return 0;
 }
-#endif  // LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 8, 0)
+#endif  // LIBAVUTIL_VERSION_INT >= LIBAVUTIL_VERSION_52_8
 
 }  // namespace ffmpeg
 }  // namespace shared
diff --git a/src/starboard/shared/iso/impl/directory_get_next.h b/src/starboard/shared/iso/impl/directory_get_next.h
index 74d3c39..712ca0e 100644
--- a/src/starboard/shared/iso/impl/directory_get_next.h
+++ b/src/starboard/shared/iso/impl/directory_get_next.h
@@ -21,6 +21,7 @@
 #include <errno.h>
 
 #include "starboard/common/string.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/file.h"
 
 #include "starboard/shared/internal_only.h"
@@ -35,7 +36,7 @@
 #if SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION
                         char* out_entry,
                         size_t out_entry_size) {
-  if (out_entry_size < SB_FILE_MAX_NAME) {
+  if (out_entry_size < kSbFileMaxName) {
     return false;
   }
 #else   // SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION
diff --git a/src/starboard/shared/linux/dev_input/dev_input.cc b/src/starboard/shared/linux/dev_input/dev_input.cc
index 2acca58..bd5a4d3 100644
--- a/src/starboard/shared/linux/dev_input/dev_input.cc
+++ b/src/starboard/shared/linux/dev_input/dev_input.cc
@@ -21,19 +21,19 @@
 #include <string.h>
 #include <sys/time.h>
 #include <unistd.h>
-#include <unordered_map>
-#include <vector>
 
 #include <algorithm>
 #include <cmath>
 #include <map>
 #include <memory>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "starboard/common/log.h"
 #include "starboard/common/string.h"
 #include "starboard/configuration.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/directory.h"
 #include "starboard/input.h"
 #include "starboard/key.h"
@@ -770,9 +770,9 @@
 
   while (true) {
 #if SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION
-    std::vector<char> entry(SB_FILE_MAX_NAME);
+    std::vector<char> entry(kSbFileMaxName);
 
-    if (!SbDirectoryGetNext(directory, entry.data(), SB_FILE_MAX_NAME)) {
+    if (!SbDirectoryGetNext(directory, entry.data(), kSbFileMaxName)) {
       break;
     }
 
@@ -808,11 +808,6 @@
     input_devices.push_back(info);
   }
 
-  if (input_devices.empty()) {
-    SB_DLOG(ERROR) << __FUNCTION__ << ": No /dev/input support. "
-                   << "No keyboards or game controllers available.";
-  }
-
   SbDirectoryClose(directory);
   return input_devices;
 }
diff --git a/src/starboard/shared/linux/get_home_directory.cc b/src/starboard/shared/linux/get_home_directory.cc
index b10b689..796e178 100644
--- a/src/starboard/shared/linux/get_home_directory.cc
+++ b/src/starboard/shared/linux/get_home_directory.cc
@@ -16,9 +16,11 @@
 #include <stdlib.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <vector>
 
 #include "starboard/common/log.h"
 #include "starboard/common/string.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/shared/nouser/user_internal.h"
 
 namespace starboard {
@@ -38,20 +40,18 @@
 
   SB_DLOG(WARNING) << "No HOME environment variable.";
   struct passwd passwd;
-  const size_t kBufferSize = SB_FILE_MAX_PATH * 4;
-  char* buffer = new char[kBufferSize];
+  const size_t kBufferSize = kSbFileMaxPath * 4;
+  std::vector<char> buffer(kBufferSize);
   struct passwd* pw_result = NULL;
   int result =
-      getpwuid_r(getuid(), &passwd, buffer, kBufferSize, &pw_result);
+      getpwuid_r(getuid(), &passwd, buffer.data(), kBufferSize, &pw_result);
   if (result != 0) {
     SB_DLOG(ERROR) << "getpwuid_r failed for uid " << getuid() << ": result = "
                    << result;
-    delete[] buffer;
     return false;
   }
 
   SbStringCopy(out_path, passwd.pw_dir, path_size);
-  delete[] buffer;
   return true;
 }
 
diff --git a/src/starboard/shared/linux/page_internal.cc b/src/starboard/shared/linux/page_internal.cc
index 1c55f45..8ee3dd2 100644
--- a/src/starboard/shared/linux/page_internal.cc
+++ b/src/starboard/shared/linux/page_internal.cc
@@ -22,6 +22,7 @@
 
 #include "starboard/atomic.h"
 #include "starboard/common/log.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/memory.h"
 
 namespace {
@@ -30,7 +31,7 @@
 
 int32_t GetPageCount(size_t byte_count) {
   return static_cast<int32_t>(SbMemoryAlignToPageSize(byte_count) /
-                              SB_MEMORY_PAGE_SIZE);
+                              kSbMemoryPageSize);
 }
 
 int SbMemoryMapFlagsToMmapProtect(int sb_flags) {
@@ -125,10 +126,10 @@
 
   fscanf(f, "%zu %zu", &program_size, &resident);
   fclose(f);
-  return SbPageGetTotalPhysicalMemoryBytes() - resident * SB_MEMORY_PAGE_SIZE;
+  return SbPageGetTotalPhysicalMemoryBytes() - resident * kSbMemoryPageSize;
 }
 
 size_t SbPageGetMappedBytes() {
   return static_cast<size_t>(SbAtomicNoBarrier_Load(&s_tracked_page_count) *
-                             SB_MEMORY_PAGE_SIZE);
+                             kSbMemoryPageSize);
 }
diff --git a/src/starboard/shared/nouser/user_get_property.cc b/src/starboard/shared/nouser/user_get_property.cc
index b585e42..fa991c1 100644
--- a/src/starboard/shared/nouser/user_get_property.cc
+++ b/src/starboard/shared/nouser/user_get_property.cc
@@ -14,7 +14,10 @@
 
 #include "starboard/user.h"
 
+#include <vector>
+
 #include "starboard/common/string.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/shared/nouser/user_internal.h"
 
 int SbUserGetPropertySize(SbUser user, SbUserPropertyId property_id) {
@@ -30,12 +33,13 @@
       return static_cast<int>(SbStringGetLength(user->id) + 1);
 
     case kSbUserPropertyHomeDirectory: {
-      char path[SB_FILE_MAX_PATH];
-      if (!starboard::shared::nouser::GetHomeDirectory(
-              user, path, SB_ARRAY_SIZE_INT(path))) {
+      std::vector<char> path(kSbFileMaxPath);
+      const int path_size = static_cast<int>(path.size());
+      if (!starboard::shared::nouser::GetHomeDirectory(user, path.data(),
+                                                       path_size)) {
         return 0;
       }
-      return static_cast<int>(SbStringGetLength(path));
+      return static_cast<int>(SbStringGetLength(path.data()));
     }
 
     case kSbUserPropertyAvatarUrl:
diff --git a/src/starboard/shared/posix/file_atomic_replace.cc b/src/starboard/shared/posix/file_atomic_replace.cc
index 3ee0700..7d86485 100644
--- a/src/starboard/shared/posix/file_atomic_replace.cc
+++ b/src/starboard/shared/posix/file_atomic_replace.cc
@@ -15,9 +15,11 @@
 #include "starboard/file.h"
 
 #include <cstdio>
+#include <vector>
 
 #include "starboard/common/log.h"
 #include "starboard/common/string.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/shared/starboard/file_atomic_replace_write_file.h"
 
 #if SB_API_VERSION >= SB_FILE_ATOMIC_REPLACE_VERSION
@@ -36,19 +38,19 @@
   }
 
   const bool file_exists = SbFileExists(path);
-  char temp_path[SB_FILE_MAX_PATH];
+  std::vector<char> temp_path(kSbFileMaxPath);
 
-  SbStringCopy(temp_path, path, SB_FILE_MAX_PATH);
-  SbStringConcat(temp_path, kTempFileSuffix, SB_FILE_MAX_PATH);
+  SbStringCopy(temp_path.data(), path, kSbFileMaxPath);
+  SbStringConcat(temp_path.data(), kTempFileSuffix, kSbFileMaxPath);
 
   if (!::starboard::shared::starboard::SbFileAtomicReplaceWriteFile(
-          temp_path, data, data_size)) {
+          temp_path.data(), data, data_size)) {
     return false;
   }
   if (file_exists && !SbFileDelete(path)) {
     return false;
   }
-  if (rename(temp_path, path) != 0) {
+  if (rename(temp_path.data(), path) != 0) {
     return false;
   }
   return true;
diff --git a/src/starboard/shared/posix/storage_write_record.cc b/src/starboard/shared/posix/storage_write_record.cc
index dfa8fa4..99b22bb 100644
--- a/src/starboard/shared/posix/storage_write_record.cc
+++ b/src/starboard/shared/posix/storage_write_record.cc
@@ -15,9 +15,11 @@
 #include "starboard/common/storage.h"
 
 #include <algorithm>
+#include <vector>
 
 #include "starboard/common/log.h"
 #include "starboard/common/string.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/file.h"
 #include "starboard/shared/starboard/file_storage/storage_internal.h"
 
@@ -31,19 +33,20 @@
   }
 
   const char* name = record->name.c_str();
-  char original_file_path[SB_FILE_MAX_PATH];
+  std::vector<char> original_file_path(kSbFileMaxPath);
   if (!starboard::shared::starboard::GetUserStorageFilePath(
-          record->user, name, original_file_path, SB_FILE_MAX_PATH)) {
+          record->user, name, original_file_path.data(), kSbFileMaxPath)) {
     return false;
   }
-  char temp_file_path[SB_FILE_MAX_PATH];
-  SbStringCopy(temp_file_path, original_file_path, SB_FILE_MAX_PATH);
-  SbStringConcat(temp_file_path, kTempFileSuffix, SB_FILE_MAX_PATH);
+  std::vector<char> temp_file_path(kSbFileMaxPath);
+  SbStringCopy(temp_file_path.data(), original_file_path.data(),
+               kSbFileMaxPath);
+  SbStringConcat(temp_file_path.data(), kTempFileSuffix, kSbFileMaxPath);
 
   SbFileError error;
   SbFile temp_file = SbFileOpen(
-      temp_file_path, kSbFileCreateAlways | kSbFileWrite | kSbFileRead, NULL,
-      &error);
+      temp_file_path.data(), kSbFileCreateAlways | kSbFileWrite | kSbFileRead,
+      NULL, &error);
   if (error != kSbFileOk) {
     return false;
   }
@@ -58,7 +61,7 @@
     int bytes_written = SbFileWrite(temp_file, source, to_write_max);
     if (bytes_written < 0) {
       SbFileClose(temp_file);
-      SbFileDelete(temp_file_path);
+      SbFileDelete(temp_file_path.data());
       return false;
     }
 
@@ -70,16 +73,16 @@
 
   if (SbFileIsValid(record->file) && !SbFileClose(record->file)) {
     SbFileClose(temp_file);
-    SbFileDelete(temp_file_path);
+    SbFileDelete(temp_file_path.data());
     return false;
   }
 
   record->file = kSbFileInvalid;
 
-  if ((!SbFileDelete(original_file_path)) ||
-   (rename(temp_file_path, original_file_path) != 0)) {
+  if ((!SbFileDelete(original_file_path.data())) ||
+      (rename(temp_file_path.data(), original_file_path.data()) != 0)) {
     SbFileClose(temp_file);
-    SbFileDelete(temp_file_path);
+    SbFileDelete(temp_file_path.data());
     return false;
   }
 
diff --git a/src/starboard/shared/pthread/thread_create.cc b/src/starboard/shared/pthread/thread_create.cc
index 2193253..3d9edd6 100644
--- a/src/starboard/shared/pthread/thread_create.cc
+++ b/src/starboard/shared/pthread/thread_create.cc
@@ -28,7 +28,8 @@
 namespace shared {
 namespace pthread {
 
-#if !SB_HAS(THREAD_PRIORITY_SUPPORT)
+#if SB_API_VERSION < SB_FEATURE_RUNTIME_CONFIGS_VERSION && \
+    !SB_HAS(THREAD_PRIORITY_SUPPORT)
 // Default implementation without thread priority support
 void ThreadSetPriority(SbThreadPriority /* priority */) {
 }
diff --git a/src/starboard/shared/pthread/thread_create_priority.h b/src/starboard/shared/pthread/thread_create_priority.h
index 71897f8..a23d4a3 100644
--- a/src/starboard/shared/pthread/thread_create_priority.h
+++ b/src/starboard/shared/pthread/thread_create_priority.h
@@ -15,6 +15,7 @@
 #ifndef STARBOARD_SHARED_PTHREAD_THREAD_CREATE_PRIORITY_H_
 #define STARBOARD_SHARED_PTHREAD_THREAD_CREATE_PRIORITY_H_
 
+#include "starboard/configuration_constants.h"
 #include "starboard/thread.h"
 
 namespace starboard {
diff --git a/src/starboard/shared/signal/suspend_signals.cc b/src/starboard/shared/signal/suspend_signals.cc
index 0ad5584..d5a0ace 100644
--- a/src/starboard/shared/signal/suspend_signals.cc
+++ b/src/starboard/shared/signal/suspend_signals.cc
@@ -94,7 +94,7 @@
 
 class SignalHandlerThread : public ::starboard::Thread {
  public:
-  SignalHandlerThread() : Thread("SignalHandlerThread") {}
+  SignalHandlerThread() : Thread("SignalHandlTh") {}
 
   void Run() override {
     SignalMask(kAllSignals, SIG_UNBLOCK);
diff --git a/src/starboard/shared/starboard/configuration_constants_compatibility_defines.h b/src/starboard/shared/starboard/configuration_constants_compatibility_defines.h
index 3485e21..4f3487c 100644
--- a/src/starboard/shared/starboard/configuration_constants_compatibility_defines.h
+++ b/src/starboard/shared/starboard/configuration_constants_compatibility_defines.h
@@ -27,10 +27,62 @@
 
 #else  // SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION
 
+#define kSbDefaultMmapThreshold SB_DEFAULT_MMAP_THRESHOLD
+
+#define kSbFileMaxName SB_FILE_MAX_NAME
+
+#define kSbFileMaxOpen SB_FILE_MAX_OPEN
+
+#define kSbFileAltSepChar SB_FILE_ALT_SEP_CHAR
+
+#define kSbFileAltSepString SB_FILE_ALT_SEP_STRING
+
+#define kSbFileMaxPath SB_FILE_MAX_PATH
+
+#define kSbFileSepChar SB_FILE_SEP_CHAR
+
+#define kSbFileSepString SB_FILE_SEP_STRING
+
+#define kSbHasAc3Audio SB_HAS_AC3_AUDIO
+
+#define kSbHasAudiolessVideo SB_HAS_AUDIOLESS_VIDEO
+
+#define kSbHasMediaWebmVp9Support SB_HAS_MEDIA_WEBM_VP9_SUPPORT
+
+#define kSbHasThreadPrioritySupport SB_HAS_THREAD_PRIORITY_SUPPORT
+
 #define kSbMallocAlignment SB_MALLOC_ALIGNMENT
 
+#define kSbMaxThreadLocalKeys SB_MAX_THREAD_LOCAL_KEYS
+
 #define kSbMaxThreadNameLength SB_MAX_THREAD_NAME_LENGTH
 
+#define kSbMediaMaxAudioBitrateInBitsPerSecond \
+  SB_MEDIA_MAX_AUDIO_BITRATE_IN_BITS_PER_SECOND
+
+#define kSbMediaMaxVideoBitrateInBitsPerSecond \
+  SB_MEDIA_MAX_VIDEO_BITRATE_IN_BITS_PER_SECOND
+
+#define kSbMediaMaximumVideoFrames SB_MEDIA_MAXIMUM_VIDEO_FRAMES
+
+#define kSbMediaMaximumVideoPrerollFrames SB_MEDIA_MAXIMUM_VIDEO_PREROLL_FRAMES
+
+#define kSbMediaVideoFrameAlignment SB_MEDIA_VIDEO_FRAME_ALIGNMENT
+
+#define kSbMemoryLogPath SB_MEMORY_LOG_PATH
+
+#define kSbMemoryPageSize SB_MEMORY_PAGE_SIZE
+
+#define kSbNetworkReceiveBufferSize SB_NETWORK_RECEIVE_BUFFER_SIZE
+
+#define kSbMaxThreads SB_MAX_THREADS
+
+#define kSbPathSepChar SB_PATH_SEP_CHAR
+
+#define kSbPathSepString SB_PATH_SEP_STRING
+
+#define kSbUserMaxSignedIn SB_USER_MAX_SIGNED_IN
+
 #endif  // SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION
 
 #endif  // STARBOARD_SHARED_STARBOARD_CONFIGURATION_CONSTANTS_COMPATIBILITY_DEFINES_H_
diff --git a/src/starboard/shared/starboard/file_storage/storage_delete_record.cc b/src/starboard/shared/starboard/file_storage/storage_delete_record.cc
index 4f611d8..7a43c37 100644
--- a/src/starboard/shared/starboard/file_storage/storage_delete_record.cc
+++ b/src/starboard/shared/starboard/file_storage/storage_delete_record.cc
@@ -14,6 +14,9 @@
 
 #include "starboard/common/storage.h"
 
+#include <vector>
+
+#include "starboard/configuration_constants.h"
 #include "starboard/file.h"
 #include "starboard/shared/starboard/file_storage/storage_internal.h"
 #include "starboard/user.h"
@@ -23,12 +26,12 @@
     return false;
   }
 
-  char path[SB_FILE_MAX_PATH];
+  std::vector<char> path(kSbFileMaxPath);
   bool success = starboard::shared::starboard::GetUserStorageFilePath(
-      user, name, path, SB_ARRAY_SIZE_INT(path));
+      user, name, path.data(), static_cast<int>(path.size()));
   if (!success) {
     return false;
   }
 
-  return SbFileDelete(path);
+  return SbFileDelete(path.data());
 }
diff --git a/src/starboard/shared/starboard/file_storage/storage_open_record.cc b/src/starboard/shared/starboard/file_storage/storage_open_record.cc
index 8e753f9..c324c22 100644
--- a/src/starboard/shared/starboard/file_storage/storage_open_record.cc
+++ b/src/starboard/shared/starboard/file_storage/storage_open_record.cc
@@ -14,7 +14,10 @@
 
 #include "starboard/common/storage.h"
 
+#include <vector>
+
 #include "starboard/common/log.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/file.h"
 #include "starboard/shared/starboard/file_storage/storage_internal.h"
 #include "starboard/user.h"
@@ -24,17 +27,17 @@
     return kSbStorageInvalidRecord;
   }
 
-  char path[SB_FILE_MAX_PATH];
+  std::vector<char> path(kSbFileMaxPath);
   bool success = starboard::shared::starboard::GetUserStorageFilePath(
-      user, name, path, SB_ARRAY_SIZE_INT(path));
+      user, name, path.data(), static_cast<int>(path.size()));
   if (!success) {
     return kSbStorageInvalidRecord;
   }
 
   // This will always create the storage file, even if it is just opened and
   // closed without doing any operation.
-  SbFile file = SbFileOpen(path, kSbFileOpenAlways | kSbFileRead | kSbFileWrite,
-                           NULL, NULL);
+  SbFile file = SbFileOpen(
+      path.data(), kSbFileOpenAlways | kSbFileRead | kSbFileWrite, NULL, NULL);
   if (!SbFileIsValid(file)) {
     return kSbStorageInvalidRecord;
   }
diff --git a/src/starboard/shared/starboard/link_receiver.cc b/src/starboard/shared/starboard/link_receiver.cc
index 3aeb386..d92ff2c 100644
--- a/src/starboard/shared/starboard/link_receiver.cc
+++ b/src/starboard/shared/starboard/link_receiver.cc
@@ -23,6 +23,7 @@
 #include "starboard/common/semaphore.h"
 #include "starboard/common/socket.h"
 #include "starboard/common/string.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/file.h"
 #include "starboard/shared/starboard/application.h"
 #include "starboard/socket_waiter.h"
@@ -136,7 +137,7 @@
 }
 
 std::string GetTemporaryDirectory() {
-  const int kMaxPathLength = SB_FILE_MAX_PATH;
+  const int kMaxPathLength = kSbFileMaxPath;
   scoped_array<char> temp_path(new char[kMaxPathLength]);
   bool has_temp = SbSystemGetPath(kSbSystemPathTempDirectory, temp_path.get(),
                                   kMaxPathLength);
@@ -156,7 +157,7 @@
     return;
   }
 
-  path += SB_FILE_SEP_STRING;
+  path += kSbFileSepString;
   path += name;
   ScopedFile file(path.c_str(), kSbFileCreateAlways | kSbFileWrite);
   if (!file.IsValid()) {
diff --git a/src/starboard/shared/starboard/media/codec_util.cc b/src/starboard/shared/starboard/media/codec_util.cc
index 59fc4f7..ce45a9b 100644
--- a/src/starboard/shared/starboard/media/codec_util.cc
+++ b/src/starboard/shared/starboard/media/codec_util.cc
@@ -22,6 +22,7 @@
 #include "starboard/common/log.h"
 #include "starboard/common/string.h"
 #include "starboard/configuration.h"
+#include "starboard/configuration_constants.h"
 
 namespace starboard {
 namespace shared {
@@ -579,14 +580,18 @@
   if (SbStringCompare(codec, "mp4a.40.", 8) == 0) {
     return kSbMediaAudioCodecAac;
   }
-#if SB_HAS(AC3_AUDIO)
-  if (SbStringCompareAll(codec, "ac-3") == 0) {
-    return kSbMediaAudioCodecAc3;
+#if SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION || \
+    defined(SB_HAS_AC3_AUDIO)
+  if (kSbHasAc3Audio) {
+    if (SbStringCompareAll(codec, "ac-3") == 0) {
+      return kSbMediaAudioCodecAc3;
+    }
+    if (SbStringCompareAll(codec, "ec-3") == 0) {
+      return kSbMediaAudioCodecEac3;
+    }
   }
-  if (SbStringCompareAll(codec, "ec-3") == 0) {
-    return kSbMediaAudioCodecEac3;
-  }
-#endif  // SB_HAS(AC3_AUDIO)
+#endif  // SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION ||
+        // defined(SB_HAS_AC3_AUDIO)
   if (SbStringCompare(codec, "opus", 4) == 0) {
     return kSbMediaAudioCodecOpus;
   }
diff --git a/src/starboard/shared/starboard/media/media_is_audio_supported_aac_and_opus.cc b/src/starboard/shared/starboard/media/media_is_audio_supported_aac_and_opus.cc
index 8e55eb2..23937a7 100644
--- a/src/starboard/shared/starboard/media/media_is_audio_supported_aac_and_opus.cc
+++ b/src/starboard/shared/starboard/media/media_is_audio_supported_aac_and_opus.cc
@@ -15,15 +15,16 @@
 #include "starboard/shared/starboard/media/media_support_internal.h"
 
 #include "starboard/configuration.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/media.h"
 
 bool SbMediaIsAudioSupported(SbMediaAudioCodec audio_codec, int64_t bitrate) {
   if (audio_codec == kSbMediaAudioCodecAac) {
-    return bitrate <= SB_MEDIA_MAX_AUDIO_BITRATE_IN_BITS_PER_SECOND;
+    return bitrate <= kSbMediaMaxAudioBitrateInBitsPerSecond;
   }
 
   if (audio_codec == kSbMediaAudioCodecOpus) {
-    return bitrate <= SB_MEDIA_MAX_AUDIO_BITRATE_IN_BITS_PER_SECOND;
+    return bitrate <= kSbMediaMaxAudioBitrateInBitsPerSecond;
   }
 
   return false;
diff --git a/src/starboard/shared/starboard/media/media_is_audio_supported_aac_only.cc b/src/starboard/shared/starboard/media/media_is_audio_supported_aac_only.cc
index eec13e0..843ba3a 100644
--- a/src/starboard/shared/starboard/media/media_is_audio_supported_aac_only.cc
+++ b/src/starboard/shared/starboard/media/media_is_audio_supported_aac_only.cc
@@ -15,9 +15,10 @@
 #include "starboard/shared/starboard/media/media_support_internal.h"
 
 #include "starboard/configuration.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/media.h"
 
 bool SbMediaIsAudioSupported(SbMediaAudioCodec audio_codec, int64_t bitrate) {
   return audio_codec == kSbMediaAudioCodecAac &&
-         bitrate <= SB_MEDIA_MAX_AUDIO_BITRATE_IN_BITS_PER_SECOND;
+         bitrate <= kSbMediaMaxAudioBitrateInBitsPerSecond;
 }
diff --git a/src/starboard/shared/starboard/media/media_util.cc b/src/starboard/shared/starboard/media/media_util.cc
index f66216f..f5e37f6 100644
--- a/src/starboard/shared/starboard/media/media_util.cc
+++ b/src/starboard/shared/starboard/media/media_util.cc
@@ -70,12 +70,23 @@
       return false;
     case kSbMediaAudioCodecAac:
       return mime_type.subtype() == "mp4";
-#if SB_HAS(AC3_AUDIO)
+#if SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION || SB_HAS(AC3_AUDIO)
     case kSbMediaAudioCodecAc3:
+      if (!kSbHasAc3Audio) {
+        SB_NOTREACHED() << "AC3 audio is not enabled on this platform. To "
+                        << "enable it, set kSbHasAc3Audio to |true|.";
+        return false;
+      }
       return mime_type.subtype() == "mp4";
     case kSbMediaAudioCodecEac3:
+      if (!kSbHasAc3Audio) {
+        SB_NOTREACHED() << "AC3 audio is not enabled on this platform. To "
+                        << "enable it, set kSbHasAc3Audio to |true|.";
+        return false;
+      }
       return mime_type.subtype() == "mp4";
-#endif  // SB_HAS(AC3_AUDIO)
+#endif  // SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION ||
+        // SB_HAS(AC3_AUDIO)
     case kSbMediaAudioCodecOpus:
     case kSbMediaAudioCodecVorbis:
       return mime_type.subtype() == "webm";
@@ -189,8 +200,9 @@
 #endif  // SB_API_VERSION < 11
       return mime_type.subtype() == "mp4";
     case kSbMediaVideoCodecVp8:
-    case kSbMediaVideoCodecVp9:
       return mime_type.subtype() == "webm";
+    case kSbMediaVideoCodecVp9:
+      return mime_type.subtype() == "mp4" || mime_type.subtype() == "webm";
   }
 
   SB_NOTREACHED();
@@ -352,12 +364,23 @@
       return "none";
     case kSbMediaAudioCodecAac:
       return "aac";
-#if SB_HAS(AC3_AUDIO)
+#if SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION || SB_HAS(AC3_AUDIO)
     case kSbMediaAudioCodecAc3:
+      if (!kSbHasAc3Audio) {
+        SB_NOTREACHED() << "AC3 audio is not enabled on this platform. To "
+                        << "enable it, set kSbHasAc3Audio to |true|.";
+        return "invalid";
+      }
       return "ac3";
     case kSbMediaAudioCodecEac3:
+      if (!kSbHasAc3Audio) {
+        SB_NOTREACHED() << "AC3 audio is not enabled on this platform. To "
+                        << "enable it, set kSbHasAc3Audio to |true|.";
+        return "invalid";
+      }
       return "ec3";
-#endif  // SB_HAS(AC3_AUDIO)
+#endif  // SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION ||
+        // SB_HAS(AC3_AUDIO)
     case kSbMediaAudioCodecOpus:
       return "opus";
     case kSbMediaAudioCodecVorbis:
diff --git a/src/starboard/shared/starboard/player/file_cache_reader.cc b/src/starboard/shared/starboard/player/file_cache_reader.cc
new file mode 100644
index 0000000..b43f62a
--- /dev/null
+++ b/src/starboard/shared/starboard/player/file_cache_reader.cc
@@ -0,0 +1,76 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/starboard/player/file_cache_reader.h"
+
+#include <algorithm>
+
+#include "starboard/common/log.h"
+#include "starboard/memory.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace player {
+
+FileCacheReader::FileCacheReader(const char* filename, int file_cache_size)
+    : file_(filename, kSbFileOpenOnly | kSbFileRead),
+      max_file_cache_size_(
+          std::min(file_cache_size, static_cast<int>(file_.GetSize()))) {
+  SB_CHECK(file_.IsValid());
+  file_cache_.resize(max_file_cache_size_);
+  file_cache_offset_ = max_file_cache_size_;
+}
+
+int FileCacheReader::Read(void* out_buffer, int bytes_to_read) {
+  int total_bytes_read = 0;
+
+  while (bytes_to_read > 0 && file_cache_.size() != 0) {
+    int bytes_read = ReadFromCache(
+        static_cast<char*>(out_buffer) + total_bytes_read, bytes_to_read);
+    SB_CHECK(bytes_read >= 0);
+    bytes_to_read -= bytes_read;
+    total_bytes_read += bytes_read;
+    RefillCacheIfEmpty();
+  }
+
+  return total_bytes_read;
+}
+
+int FileCacheReader::ReadFromCache(void* out_buffer, int bytes_to_read) {
+  SB_CHECK(file_cache_offset_ <= file_cache_.size());
+  bytes_to_read = std::min(
+      static_cast<int>(file_cache_.size()) - file_cache_offset_, bytes_to_read);
+  SbMemoryCopy(out_buffer, file_cache_.data() + file_cache_offset_,
+               bytes_to_read);
+  file_cache_offset_ += bytes_to_read;
+  return bytes_to_read;
+}
+
+void FileCacheReader::RefillCacheIfEmpty() {
+  if (file_cache_offset_ != file_cache_.size()) {
+    return;
+  }
+  file_cache_offset_ = 0;
+  int bytes_read = file_.ReadAll(file_cache_.data(), file_cache_.size());
+  SB_CHECK(bytes_read >= 0);
+  if (bytes_read < static_cast<int>(file_cache_.size())) {
+    file_cache_.resize(bytes_read);
+  }
+}
+
+}  // namespace player
+}  // namespace starboard
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/starboard/player/file_cache_reader.h b/src/starboard/shared/starboard/player/file_cache_reader.h
new file mode 100644
index 0000000..58768df
--- /dev/null
+++ b/src/starboard/shared/starboard/player/file_cache_reader.h
@@ -0,0 +1,62 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_STARBOARD_PLAYER_FILE_CACHE_READER_H_
+#define STARBOARD_SHARED_STARBOARD_PLAYER_FILE_CACHE_READER_H_
+
+#include <vector>
+
+#include "starboard/file.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace player {
+
+class FileCacheReader {
+ public:
+  FileCacheReader(const char* filename, int file_cache_size);
+
+  int Read(void* out_buffer, int bytes_to_read);
+
+  int64_t GetSize() const { return file_.GetSize(); }
+
+ private:
+  // Reads from the currently cached file contents, into the output buffer.
+  // Returns the final number of bytes read out from the cache.
+  int ReadFromCache(void* out_buffer, int bytes_to_read);
+
+  // Reads from the file into the intermediate cache, if the intermediate cache
+  // is emptied out.
+  void RefillCacheIfEmpty();
+
+  ScopedFile file_;
+
+  // Maximum size of the buffered file.
+  const int max_file_cache_size_;
+
+  // Position marker in the buffer that we have finished reading.
+  int file_cache_offset_ = 0;
+
+  // The intermediate buffer that will hold file contents as needed by
+  // parsing.
+  std::vector<char> file_cache_;
+};
+
+}  // namespace player
+}  // namespace starboard
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_STARBOARD_PLAYER_FILE_CACHE_READER_H_
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 ea3a192..a9dfdc1 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
@@ -16,7 +16,10 @@
 
 #include "starboard/audio_sink.h"
 #include "starboard/common/log.h"
+#include "starboard/common/murmurhash2.h"
+#include "starboard/format_string.h"
 #include "starboard/memory.h"
+#include "starboard/shared/starboard/application.h"
 #include "starboard/shared/starboard/drm/drm_system_internal.h"
 #include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
 #include "starboard/shared/starboard/player/filter/player_components.h"
@@ -47,6 +50,31 @@
   }
 };
 
+#if defined(COBALT_BUILD_TYPE_GOLD)
+
+void DumpInputHash(const InputBuffer* input_buffer) {}
+
+#else  // defined(COBALT_BUILD_TYPE_GOLD)
+
+void DumpInputHash(const InputBuffer* input_buffer) {
+  static const bool s_dump_input_hash =
+      Application::Get()->GetCommandLine()->HasSwitch("dump_video_input_hash");
+
+  if (!s_dump_input_hash) {
+    return;
+  }
+
+  bool is_audio = input_buffer->sample_type() == kSbMediaTypeAudio;
+  SB_LOG(ERROR) << "Dump "
+                << (input_buffer->drm_info() ? "encrypted " : "clear ")
+                << (is_audio ? "audio input hash @ " : "video input hash @ ")
+                << input_buffer->timestamp() << ": "
+                << MurmurHash2_32(input_buffer->data(), input_buffer->size(),
+                                  0);
+}
+
+#endif  // defined(COBALT_BUILD_TYPE_GOLD)
+
 }  // namespace
 
 FilterBasedPlayerWorkerHandler::FilterBasedPlayerWorkerHandler(
@@ -88,7 +116,8 @@
     UpdateMediaInfoCB update_media_info_cb,
     GetPlayerStateCB get_player_state_cb,
     UpdatePlayerStateCB update_player_state_cb,
-    UpdatePlayerErrorCB update_player_error_cb) {
+    UpdatePlayerErrorCB update_player_error_cb,
+    std::string* error_message) {
   // This function should only be called once.
   SB_DCHECK(update_media_info_cb_ == NULL);
 
@@ -97,6 +126,7 @@
   SB_DCHECK(update_media_info_cb);
   SB_DCHECK(get_player_state_cb);
   SB_DCHECK(update_player_state_cb);
+  SB_DCHECK(error_message);
 
   AttachToCurrentThread();
 
@@ -123,15 +153,20 @@
       SB_LOG(ERROR) << "Audio channels requested " << required_audio_channels
                     << ", but currently supported less than or equal to "
                     << supported_audio_channels;
+      *error_message =
+          FormatString("Required channel %d is greater than maximum channel %d",
+                       required_audio_channels, supported_audio_channels);
       return false;
     }
 
     PlayerComponents::AudioParameters audio_parameters = {
         audio_codec_, audio_sample_info_, drm_system_};
 
-    audio_renderer_ = player_components->CreateAudioRenderer(audio_parameters);
+    audio_renderer_ =
+        player_components->CreateAudioRenderer(audio_parameters, error_message);
     if (!audio_renderer_) {
-      SB_DLOG(ERROR) << "Failed to create audio renderer";
+      SB_DLOG(ERROR) << "Failed to create audio renderer with error: "
+                     << *error_message;
       return false;
     }
     audio_renderer_->Initialize(
@@ -174,9 +209,10 @@
     SB_DCHECK(media_time_provider);
 
     video_renderer_ = player_components->CreateVideoRenderer(
-        video_parameters, media_time_provider);
+        video_parameters, media_time_provider, error_message);
     if (!video_renderer_) {
-      SB_DLOG(ERROR) << "Failed to create video renderer";
+      SB_DLOG(ERROR) << "Failed to create video renderer with error: "
+                     << *error_message;
       return false;
     }
     video_renderer_->Initialize(
@@ -245,6 +281,7 @@
         if (!SbDrmSystemIsValid(drm_system_)) {
           return false;
         }
+        DumpInputHash(input_buffer);
         SbDrmSystemPrivate::DecryptStatus decrypt_status =
             drm_system_->Decrypt(input_buffer);
         if (decrypt_status == SbDrmSystemPrivate::kRetry) {
@@ -256,6 +293,7 @@
           return false;
         }
       }
+      DumpInputHash(input_buffer);
       audio_renderer_->WriteSample(input_buffer);
     }
   } else {
@@ -278,6 +316,7 @@
         if (!SbDrmSystemIsValid(drm_system_)) {
           return false;
         }
+        DumpInputHash(input_buffer);
         SbDrmSystemPrivate::DecryptStatus decrypt_status =
             drm_system_->Decrypt(input_buffer);
         if (decrypt_status == SbDrmSystemPrivate::kRetry) {
@@ -293,6 +332,7 @@
         media_time_provider_impl_->UpdateVideoDuration(
             input_buffer->timestamp());
       }
+      DumpInputHash(input_buffer);
       video_renderer_->WriteSample(input_buffer);
     }
   }
diff --git a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h
index e8c4d69..20d7e39 100644
--- a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h
+++ b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h
@@ -56,7 +56,8 @@
             UpdateMediaInfoCB update_media_info_cb,
             GetPlayerStateCB get_player_state_cb,
             UpdatePlayerStateCB update_player_state_cb,
-            UpdatePlayerErrorCB update_player_error_cb) override;
+            UpdatePlayerErrorCB update_player_error_cb,
+            std::string* error_message) override;
   bool Seek(SbTime seek_to_time, int ticket) override;
   bool WriteSample(const scoped_refptr<InputBuffer>& input_buffer,
                    bool* written) override;
diff --git a/src/starboard/shared/starboard/player/filter/player_components.cc b/src/starboard/shared/starboard/player/filter/player_components.cc
index 74e3cb3..6753841 100644
--- a/src/starboard/shared/starboard/player/filter/player_components.cc
+++ b/src/starboard/shared/starboard/player/filter/player_components.cc
@@ -14,6 +14,7 @@
 
 #include "starboard/shared/starboard/player/filter/player_components.h"
 
+#include "starboard/common/log.h"
 #include "starboard/shared/starboard/application.h"
 #include "starboard/shared/starboard/command_line.h"
 #include "starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.h"
@@ -30,7 +31,10 @@
 namespace filter {
 
 scoped_ptr<AudioRenderer> PlayerComponents::CreateAudioRenderer(
-    const AudioParameters& audio_parameters) {
+    const AudioParameters& audio_parameters,
+    std::string* error_message) {
+  SB_DCHECK(error_message);
+
   scoped_ptr<AudioDecoder> audio_decoder;
   scoped_ptr<AudioRendererSink> audio_renderer_sink;
 
@@ -39,12 +43,15 @@
     CreateStubAudioComponents(audio_parameters, &audio_decoder,
                               &audio_renderer_sink);
   } else {
-    CreateAudioComponents(audio_parameters, &audio_decoder,
-                          &audio_renderer_sink);
+    if (!CreateAudioComponents(audio_parameters, &audio_decoder,
+                               &audio_renderer_sink, error_message)) {
+      return scoped_ptr<AudioRenderer>();
+    }
   }
-  if (!audio_decoder || !audio_renderer_sink) {
-    return scoped_ptr<AudioRenderer>();
-  }
+
+  SB_DCHECK(audio_decoder);
+  SB_DCHECK(audio_renderer_sink);
+
   int max_cached_frames, max_frames_per_append;
   GetAudioRendererParams(&max_cached_frames, &max_frames_per_append);
   return make_scoped_ptr(
@@ -55,7 +62,10 @@
 
 scoped_ptr<VideoRenderer> PlayerComponents::CreateVideoRenderer(
     const VideoParameters& video_parameters,
-    MediaTimeProvider* media_time_provider) {
+    MediaTimeProvider* media_time_provider,
+    std::string* error_message) {
+  SB_DCHECK(error_message);
+
   scoped_ptr<VideoDecoder> video_decoder;
   scoped_ptr<VideoRenderAlgorithm> video_render_algorithm;
   scoped_refptr<VideoRendererSink> video_renderer_sink;
@@ -65,12 +75,16 @@
     CreateStubVideoComponents(video_parameters, &video_decoder,
                               &video_render_algorithm, &video_renderer_sink);
   } else {
-    CreateVideoComponents(video_parameters, &video_decoder,
-                          &video_render_algorithm, &video_renderer_sink);
+    if (!CreateVideoComponents(video_parameters, &video_decoder,
+                               &video_render_algorithm, &video_renderer_sink,
+                               error_message)) {
+      return scoped_ptr<VideoRenderer>();
+    }
   }
-  if (!video_decoder || !video_render_algorithm) {
-    return scoped_ptr<VideoRenderer>();
-  }
+
+  SB_DCHECK(video_decoder);
+  SB_DCHECK(video_render_algorithm);
+
   return make_scoped_ptr(
       new VideoRenderer(video_decoder.Pass(), media_time_provider,
                         video_render_algorithm.Pass(), video_renderer_sink));
diff --git a/src/starboard/shared/starboard/player/filter/player_components.h b/src/starboard/shared/starboard/player/filter/player_components.h
index a73ac46..6ea8e71 100644
--- a/src/starboard/shared/starboard/player/filter/player_components.h
+++ b/src/starboard/shared/starboard/player/filter/player_components.h
@@ -15,6 +15,8 @@
 #ifndef STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_PLAYER_COMPONENTS_H_
 #define STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_PLAYER_COMPONENTS_H_
 
+#include <string>
+
 #include "starboard/common/ref_counted.h"
 #include "starboard/common/scoped_ptr.h"
 #include "starboard/decode_target.h"
@@ -63,11 +65,13 @@
   static scoped_ptr<PlayerComponents> Create();
 
   scoped_ptr<AudioRenderer> CreateAudioRenderer(
-      const AudioParameters& audio_parameters);
+      const AudioParameters& audio_parameters,
+      std::string* error_message);
 
   scoped_ptr<VideoRenderer> CreateVideoRenderer(
       const VideoParameters& video_parameters,
-      MediaTimeProvider* media_time_provider);
+      MediaTimeProvider* media_time_provider,
+      std::string* error_message);
 
 #if COBALT_BUILD_TYPE_GOLD
  private:
@@ -75,16 +79,18 @@
   // Note that the following functions are exposed in non-Gold build to allow
   // unit tests to run.
 
-  virtual void CreateAudioComponents(
+  virtual bool CreateAudioComponents(
       const AudioParameters& audio_parameters,
       scoped_ptr<AudioDecoder>* audio_decoder,
-      scoped_ptr<AudioRendererSink>* audio_renderer_sink) = 0;
+      scoped_ptr<AudioRendererSink>* audio_renderer_sink,
+      std::string* error_message) = 0;
 
-  virtual void CreateVideoComponents(
+  virtual bool CreateVideoComponents(
       const VideoParameters& video_parameters,
       scoped_ptr<VideoDecoder>* video_decoder,
       scoped_ptr<VideoRenderAlgorithm>* video_render_algorithm,
-      scoped_refptr<VideoRendererSink>* video_renderer_sink) = 0;
+      scoped_refptr<VideoRendererSink>* video_renderer_sink,
+      std::string* error_message) = 0;
 
   // Check AudioRenderer ctor for more details on the parameters.
   virtual void GetAudioRendererParams(int* max_cached_frames,
diff --git a/src/starboard/shared/starboard/player/filter/stub_player_components_impl.h b/src/starboard/shared/starboard/player/filter/stub_player_components_impl.h
index 3e2013a..1d7d8c1 100644
--- a/src/starboard/shared/starboard/player/filter/stub_player_components_impl.h
+++ b/src/starboard/shared/starboard/player/filter/stub_player_components_impl.h
@@ -17,6 +17,10 @@
 
 #include "starboard/shared/starboard/player/filter/player_components.h"
 
+#include <string>
+
+#include "starboard/common/log.h"
+
 namespace starboard {
 namespace shared {
 namespace starboard {
@@ -25,21 +29,28 @@
 
 class StubPlayerComponentsImpl : public PlayerComponents {
  public:
-  void CreateAudioComponents(
-      const AudioParameters& audio_parameters,
-      scoped_ptr<AudioDecoder>* audio_decoder,
-      scoped_ptr<AudioRendererSink>* audio_renderer_sink) override {
+  bool CreateAudioComponents(const AudioParameters& audio_parameters,
+                             scoped_ptr<AudioDecoder>* audio_decoder,
+                             scoped_ptr<AudioRendererSink>* audio_renderer_sink,
+                             std::string* error_message) override {
+    SB_DCHECK(error_message);
+
     CreateStubAudioComponents(audio_parameters, audio_decoder,
                               audio_renderer_sink);
+    return true;
   }
 
-  void CreateVideoComponents(
+  bool CreateVideoComponents(
       const VideoParameters& video_parameters,
       scoped_ptr<VideoDecoder>* video_decoder,
       scoped_ptr<VideoRenderAlgorithm>* video_render_algorithm,
-      scoped_refptr<VideoRendererSink>* video_renderer_sink) override {
+      scoped_refptr<VideoRendererSink>* video_renderer_sink,
+      std::string* error_message) override {
+    SB_DCHECK(error_message);
+
     CreateStubVideoComponents(video_parameters, video_decoder,
                               video_render_algorithm, video_renderer_sink);
+    return true;
   }
 
   void GetAudioRendererParams(int* max_cached_frames,
diff --git a/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc b/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
index c5af2e8..0a67f32 100644
--- a/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
@@ -18,6 +18,7 @@
 
 #include "starboard/common/mutex.h"
 #include "starboard/common/scoped_ptr.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/shared/starboard/media/media_support_internal.h"
 #include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
 #include "starboard/shared/starboard/player/filter/player_components.h"
@@ -70,15 +71,16 @@
 }
 
 string GetTestInputDirectory() {
-  const size_t kPathSize = SB_FILE_MAX_PATH + 1;
+  const size_t kPathSize = kSbFileMaxPath + 1;
 
-  char content_path[kPathSize];
-  SB_CHECK(
-      SbSystemGetPath(kSbSystemPathContentDirectory, content_path, kPathSize));
-  string directory_path =
-      string(content_path) + SB_FILE_SEP_CHAR + "test" + SB_FILE_SEP_CHAR +
-      "starboard" + SB_FILE_SEP_CHAR + "shared" + SB_FILE_SEP_CHAR +
-      "starboard" + SB_FILE_SEP_CHAR + "player" + SB_FILE_SEP_CHAR + "testdata";
+  std::vector<char> content_path(kPathSize);
+  SB_CHECK(SbSystemGetPath(kSbSystemPathContentDirectory, content_path.data(),
+                           kPathSize));
+  string directory_path = string(content_path.data()) + kSbFileSepChar +
+                          "test" + kSbFileSepChar + "starboard" +
+                          kSbFileSepChar + "shared" + kSbFileSepChar +
+                          "starboard" + kSbFileSepChar + "player" +
+                          kSbFileSepChar + "testdata";
 
   SB_CHECK(SbDirectoryCanOpen(directory_path.c_str()))
       << "Cannot open directory " << directory_path;
@@ -86,7 +88,7 @@
 }
 
 string ResolveTestFileName(const char* filename) {
-  return GetTestInputDirectory() + SB_FILE_SEP_CHAR + filename;
+  return GetTestInputDirectory() + kSbFileSepChar + filename;
 }
 
 // TODO: Avoid reading same dmp file repeatly.
@@ -135,8 +137,10 @@
     } else {
       components = PlayerComponents::Create();
     }
-    components->CreateAudioComponents(audio_parameters, &audio_decoder_,
-                                      &audio_renderer_sink);
+    std::string error_message;
+    ASSERT_TRUE(components->CreateAudioComponents(
+        audio_parameters, &audio_decoder_, &audio_renderer_sink,
+        &error_message));
     ASSERT_TRUE(audio_decoder_);
 
     audio_decoder_->Initialize(
@@ -378,11 +382,14 @@
   //   codec: kSbMediaAudioCodecOpus
   //   sampling rate: 48.0k
   //   frames per AU: 960
-  const char* kFilenames[] = {
-      "beneath_the_canopy_aac_stereo.dmp",  "beneath_the_canopy_aac_5_1.dmp",
-      "beneath_the_canopy_aac_mono.dmp",    "beneath_the_canopy_opus_5_1.dmp",
-      "beneath_the_canopy_opus_stereo.dmp", "beneath_the_canopy_opus_mono.dmp",
-  };
+  const char* kFilenames[] = {"beneath_the_canopy_aac_stereo.dmp",
+                              "beneath_the_canopy_aac_5_1.dmp",
+                              "beneath_the_canopy_aac_mono.dmp",
+                              "beneath_the_canopy_opus_5_1.dmp",
+                              "beneath_the_canopy_opus_stereo.dmp",
+                              "beneath_the_canopy_opus_mono.dmp",
+                              "sintel_329_ec3.dmp",
+                              "sintel_381_ac3.dmp"};
 
   static vector<vector<const char*>> test_params;
 
diff --git a/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc b/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
index 179dac1..5810751 100644
--- a/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
@@ -21,6 +21,7 @@
 #include "starboard/common/condition_variable.h"
 #include "starboard/common/mutex.h"
 #include "starboard/common/scoped_ptr.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/media.h"
 #include "starboard/memory.h"
 #include "starboard/shared/starboard/media/media_support_internal.h"
@@ -51,16 +52,16 @@
 const SbTimeMonotonic kWaitForNextEventTimeOut = 5 * kSbTimeSecond;
 
 std::string GetTestInputDirectory() {
-  const size_t kPathSize = SB_FILE_MAX_PATH + 1;
+  const size_t kPathSize = kSbFileMaxPath + 1;
 
-  char content_path[kPathSize];
-  SB_CHECK(SbSystemGetPath(kSbSystemPathContentDirectory, content_path,
+  std::vector<char> content_path(kPathSize);
+  SB_CHECK(SbSystemGetPath(kSbSystemPathContentDirectory, content_path.data(),
                            kPathSize));
   std::string directory_path =
-      std::string(content_path) + SB_FILE_SEP_CHAR + "test" +
-      SB_FILE_SEP_CHAR + "starboard" + SB_FILE_SEP_CHAR + "shared" +
-      SB_FILE_SEP_CHAR + "starboard" + SB_FILE_SEP_CHAR + "player" +
-      SB_FILE_SEP_CHAR + "testdata";
+      std::string(content_path.data()) + kSbFileSepChar + "test" +
+      kSbFileSepChar + "starboard" + kSbFileSepChar + "shared" +
+      kSbFileSepChar + "starboard" + kSbFileSepChar + "player" +
+      kSbFileSepChar + "testdata";
 
   SB_CHECK(SbDirectoryCanOpen(directory_path.c_str()))
       << "Cannot open directory " << directory_path;
@@ -76,7 +77,7 @@
 }
 
 std::string ResolveTestFileName(const char* filename) {
-  return GetTestInputDirectory() + SB_FILE_SEP_CHAR + filename;
+  return GetTestInputDirectory() + kSbFileSepChar + filename;
 }
 
 class AudioDecoderTest
@@ -95,8 +96,6 @@
 
     CreateComponents(dmp_reader_.audio_codec(), dmp_reader_.audio_sample_info(),
                      &audio_decoder_, &audio_renderer_sink_);
-    ASSERT_TRUE(audio_decoder_);
-    ASSERT_TRUE(audio_renderer_sink_);
   }
 
  protected:
@@ -122,8 +121,10 @@
     } else {
       components = PlayerComponents::Create();
     }
+    std::string error_message;
     components->CreateAudioComponents(audio_parameters, audio_decoder,
-                                      audio_renderer_sink);
+                                      audio_renderer_sink, &error_message);
+
     if (*audio_decoder) {
       (*audio_decoder)
           ->Initialize(std::bind(&AudioDecoderTest::OnOutput, this),
@@ -689,10 +690,13 @@
 #endif  // SB_API_VERSION >= 11
 
 std::vector<const char*> GetSupportedTests() {
-  const char* kFilenames[] = {
-      "beneath_the_canopy_aac_5_1.dmp", "beneath_the_canopy_aac_stereo.dmp",
-      "beneath_the_canopy_opus_5_1.dmp", "beneath_the_canopy_opus_stereo.dmp",
-      "heaac.dmp"};
+  const char* kFilenames[] = {"beneath_the_canopy_aac_5_1.dmp",
+                              "beneath_the_canopy_aac_stereo.dmp",
+                              "beneath_the_canopy_opus_5_1.dmp",
+                              "beneath_the_canopy_opus_stereo.dmp",
+                              "heaac.dmp",
+                              "sintel_329_ec3.dmp",
+                              "sintel_381_ac3.dmp"};
 
   static std::vector<const char*> test_params;
 
diff --git a/src/starboard/shared/starboard/player/filter/testing/file_cache_reader_test.cc b/src/starboard/shared/starboard/player/filter/testing/file_cache_reader_test.cc
new file mode 100644
index 0000000..323d0bb
--- /dev/null
+++ b/src/starboard/shared/starboard/player/filter/testing/file_cache_reader_test.cc
@@ -0,0 +1,113 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/starboard/player/file_cache_reader.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "starboard/configuration_constants.h"
+#include "starboard/file.h"
+#include "starboard/memory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace player {
+namespace filter {
+namespace testing {
+namespace {
+
+const char kTestFilename[] = "beneath_the_canopy_aac_stereo.dmp";
+
+std::string GetTestInputDirectory() {
+  using std::string;
+  const size_t kPathSize = kSbFileMaxPath + 1;
+
+  std::vector<char> content_path(kPathSize);
+  SB_CHECK(SbSystemGetPath(kSbSystemPathContentDirectory, content_path.data(),
+                           kPathSize));
+  string directory_path =
+      string(content_path.data()) + kSbFileSepChar + "test" + kSbFileSepChar +
+      "starboard" + kSbFileSepChar + "shared" + kSbFileSepChar + "starboard" +
+      kSbFileSepChar + "player" + kSbFileSepChar + "testdata";
+
+  SB_CHECK(SbDirectoryCanOpen(directory_path.c_str()))
+      << "Cannot open directory " << directory_path;
+  return directory_path;
+}
+
+std::string ResolveTestFileName(const char* filename) {
+  return GetTestInputDirectory() + kSbFileSepChar + filename;
+}
+
+class FileCacheReaderTest : public ::testing::Test {
+ public:
+  FileCacheReaderTest()
+      : file_cache_reader_(ResolveTestFileName(kTestFilename).c_str(),
+                           1024 * 1024) {}
+
+ protected:
+  FileCacheReader file_cache_reader_;
+};
+
+TEST_F(FileCacheReaderTest, FileCacheReader) {
+  const std::vector<int> sizes_to_read = {0, 1, 2, 3, 4, 0, 5, 8, 13};
+
+  std::vector<char> true_contents;
+  {
+    // Use a 5MB snippet from the true file to compare against.
+    const size_t kTestSize = 5 * 1024 * 1024;
+    ScopedFile file(ResolveTestFileName(kTestFilename).c_str(),
+                    kSbFileOpenOnly | kSbFileRead);
+    true_contents.resize(kTestSize);
+    int bytes_read = file.ReadAll(true_contents.data(), kTestSize);
+    SB_CHECK(bytes_read == kTestSize);
+  }
+
+  // Output buffer for file reading, when it is read in chunks.
+  std::vector<char> read_contents;
+
+  int true_offset = 0;
+  int size_index = 0;
+  while (true_offset < true_contents.size()) {
+    auto size_to_read =
+        std::min(sizes_to_read[size_index],
+                 static_cast<int>(true_contents.size()) - true_offset);
+    size_index = (size_index + 1) % sizes_to_read.size();
+
+    read_contents.resize(size_to_read);
+    int bytes_read =
+        file_cache_reader_.Read(read_contents.data(), size_to_read);
+
+    ASSERT_EQ(bytes_read, size_to_read);
+    // Compare the true content of these files, with the chunked contents of
+    // these files to ensure that file I/O is working as expected.
+    int result = SbMemoryCompare(
+        read_contents.data(), true_contents.data() + true_offset, bytes_read);
+    ASSERT_EQ(0, result);
+    true_offset += bytes_read;
+  }
+  EXPECT_EQ(true_offset, true_contents.size());
+}
+
+}  // namespace
+}  // namespace testing
+}  // namespace filter
+}  // namespace player
+}  // namespace starboard
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/starboard/player/filter/testing/player_filter_tests.gyp b/src/starboard/shared/starboard/player/filter/testing/player_filter_tests.gyp
index 60f08fc..5a81320 100644
--- a/src/starboard/shared/starboard/player/filter/testing/player_filter_tests.gyp
+++ b/src/starboard/shared/starboard/player/filter/testing/player_filter_tests.gyp
@@ -23,6 +23,7 @@
         '<(DEPTH)/starboard/shared/starboard/player/filter/testing/audio_channel_layout_mixer_test.cc',
         '<(DEPTH)/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc',
         '<(DEPTH)/starboard/shared/starboard/player/filter/testing/audio_renderer_internal_test.cc',
+        '<(DEPTH)/starboard/shared/starboard/player/filter/testing/file_cache_reader_test.cc',
         '<(DEPTH)/starboard/shared/starboard/player/filter/testing/media_time_provider_impl_test.cc',
         '<(DEPTH)/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc',
         '<(DEPTH)/starboard/shared/starboard/player/filter/testing/video_frame_cadence_pattern_generator_test.cc',
diff --git a/src/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc b/src/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc
index 93c50f6..bc1d828 100644
--- a/src/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc
@@ -24,6 +24,7 @@
 #include "starboard/common/mutex.h"
 #include "starboard/common/scoped_ptr.h"
 #include "starboard/common/string.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/drm.h"
 #include "starboard/media.h"
 #include "starboard/memory.h"
@@ -69,15 +70,16 @@
 const SbTimeMonotonic kDefaultWaitForNextEventTimeOut = 5 * kSbTimeSecond;
 
 std::string GetTestInputDirectory() {
-  const size_t kPathSize = SB_FILE_MAX_PATH + 1;
+  const size_t kPathSize = kSbFileMaxPath + 1;
 
-  char content_path[kPathSize];
-  EXPECT_TRUE(
-      SbSystemGetPath(kSbSystemPathContentDirectory, content_path, kPathSize));
+  std::vector<char> content_path(kPathSize);
+  EXPECT_TRUE(SbSystemGetPath(kSbSystemPathContentDirectory,
+                              content_path.data(), kPathSize));
   std::string directory_path =
-      std::string(content_path) + SB_FILE_SEP_CHAR + "test" + SB_FILE_SEP_CHAR +
-      "starboard" + SB_FILE_SEP_CHAR + "shared" + SB_FILE_SEP_CHAR +
-      "starboard" + SB_FILE_SEP_CHAR + "player" + SB_FILE_SEP_CHAR + "testdata";
+      std::string(content_path.data()) + kSbFileSepChar + "test" +
+      kSbFileSepChar + "starboard" + kSbFileSepChar + "shared" +
+      kSbFileSepChar + "starboard" + kSbFileSepChar + "player" +
+      kSbFileSepChar + "testdata";
 
   SB_CHECK(SbDirectoryCanOpen(directory_path.c_str())) << directory_path;
   return directory_path;
@@ -92,7 +94,7 @@
 }
 
 std::string ResolveTestFileName(const char* filename) {
-  return GetTestInputDirectory() + SB_FILE_SEP_CHAR + filename;
+  return GetTestInputDirectory() + kSbFileSepChar + filename;
 }
 
 AssertionResult AlmostEqualTime(SbTime time1, SbTime time2) {
@@ -140,9 +142,10 @@
     } else {
       components = PlayerComponents::Create();
     }
-    components->CreateVideoComponents(video_parameters, &video_decoder_,
-                                      &video_render_algorithm_,
-                                      &video_renderer_sink_);
+    std::string error_message;
+    ASSERT_TRUE(components->CreateVideoComponents(
+        video_parameters, &video_decoder_, &video_render_algorithm_,
+        &video_renderer_sink_, &error_message));
     ASSERT_TRUE(video_decoder_);
 
     if (video_renderer_sink_) {
@@ -568,9 +571,10 @@
               output_mode,
               fake_graphics_context_provider_.decoder_target_provider()};
 
-          components->CreateVideoComponents(
+          std::string error_message;
+          ASSERT_TRUE(components->CreateVideoComponents(
               video_parameters, &video_decoders[i], &video_render_algorithms[i],
-              &video_renderer_sinks[i]);
+              &video_renderer_sinks[i], &error_message));
           ASSERT_TRUE(video_decoders[i]);
 
           if (video_renderer_sinks[i]) {
@@ -878,7 +882,8 @@
                                        kSbPlayerOutputModePunchOut};
 
   const char* kFilenames[] = {"beneath_the_canopy_137_avc.dmp",
-                              "beneath_the_canopy_248_vp9.dmp"};
+                              "beneath_the_canopy_248_vp9.dmp",
+                              "sintel_399_av1.dmp"};
 
   static std::vector<TestParam> test_params;
 
diff --git a/src/starboard/shared/starboard/player/filter/tools/audio_dmp_player.cc b/src/starboard/shared/starboard/player/filter/tools/audio_dmp_player.cc
index d87e5b1..2750620 100644
--- a/src/starboard/shared/starboard/player/filter/tools/audio_dmp_player.cc
+++ b/src/starboard/shared/starboard/player/filter/tools/audio_dmp_player.cc
@@ -16,6 +16,7 @@
 
 #include "starboard/common/log.h"
 #include "starboard/common/scoped_ptr.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/directory.h"
 #include "starboard/event.h"
 #include "starboard/player.h"
@@ -40,15 +41,16 @@
 // TODO: Merge test file resolving function with the ones used in the player
 // filter tests.
 std::string GetTestInputDirectory() {
-  const size_t kPathSize = SB_FILE_MAX_PATH + 1;
+  const size_t kPathSize = kSbFileMaxPath + 1;
 
-  char content_path[kPathSize];
-  SB_CHECK(
-      SbSystemGetPath(kSbSystemPathContentDirectory, content_path, kPathSize));
+  std::vector<char> content_path(kPathSize);
+  SB_CHECK(SbSystemGetPath(kSbSystemPathContentDirectory, content_path.data(),
+                           kPathSize));
   std::string directory_path =
-      std::string(content_path) + SB_FILE_SEP_CHAR + "test" + SB_FILE_SEP_CHAR +
-      "starboard" + SB_FILE_SEP_CHAR + "shared" + SB_FILE_SEP_CHAR +
-      "starboard" + SB_FILE_SEP_CHAR + "player" + SB_FILE_SEP_CHAR + "testdata";
+      std::string(content_path.data()) + kSbFileSepChar + "test" +
+      kSbFileSepChar + "starboard" + kSbFileSepChar + "shared" +
+      kSbFileSepChar + "starboard" + kSbFileSepChar + "player" +
+      kSbFileSepChar + "testdata";
 
   SB_CHECK(SbDirectoryCanOpen(directory_path.c_str()))
       << "Cannot open directory " << directory_path;
@@ -56,7 +58,7 @@
 }
 
 std::string ResolveTestFileName(const char* filename) {
-  return GetTestInputDirectory() + SB_FILE_SEP_CHAR + filename;
+  return GetTestInputDirectory() + kSbFileSepChar + filename;
 }
 
 scoped_ptr<VideoDmpReader> s_video_dmp_reader;
@@ -131,7 +133,9 @@
   PlayerComponents::AudioParameters audio_parameters = {
       s_video_dmp_reader->audio_codec(),
       s_video_dmp_reader->audio_sample_info(), kSbDrmSystemInvalid};
-  s_audio_renderer = player_components->CreateAudioRenderer(audio_parameters);
+  std::string error_message;
+  s_audio_renderer =
+      player_components->CreateAudioRenderer(audio_parameters, &error_message);
   SB_DCHECK(s_audio_renderer);
 
   using std::placeholders::_1;
diff --git a/src/starboard/shared/starboard/player/filter/tools/tools.gyp b/src/starboard/shared/starboard/player/filter/tools/tools.gyp
index 0a6d0ed..efe5dd1 100644
--- a/src/starboard/shared/starboard/player/filter/tools/tools.gyp
+++ b/src/starboard/shared/starboard/player/filter/tools/tools.gyp
@@ -18,6 +18,8 @@
       'target_name': 'audio_dmp_player',
       'type': '<(final_executable_type)',
       'sources': [
+        '<(DEPTH)/starboard/shared/starboard/player/file_cache_reader.cc',
+        '<(DEPTH)/starboard/shared/starboard/player/file_cache_reader.h',
         '<(DEPTH)/starboard/shared/starboard/player/video_dmp_common.cc',
         '<(DEPTH)/starboard/shared/starboard/player/video_dmp_common.h',
         '<(DEPTH)/starboard/shared/starboard/player/video_dmp_reader.cc',
diff --git a/src/starboard/shared/starboard/player/filter/video_frame_cadence_pattern_generator.cc b/src/starboard/shared/starboard/player/filter/video_frame_cadence_pattern_generator.cc
index 83ccb11..e291f6f 100644
--- a/src/starboard/shared/starboard/player/filter/video_frame_cadence_pattern_generator.cc
+++ b/src/starboard/shared/starboard/player/filter/video_frame_cadence_pattern_generator.cc
@@ -75,9 +75,9 @@
 }
 
 void VideoFrameCadencePatternGenerator::AdvanceToNextFrame() {
-  SB_DCHECK(refresh_rate_ != kInvalidRefreshRate);
-  SB_DCHECK(frame_rate_ != kInvalidFrameRate);
-
+  // It is possible that AdvanceToNextFrame() is called before refresh rate and
+  // frame rate are set.  This can happen when the platform release the frame on
+  // rendering.
   ++frame_index_;
 }
 
diff --git a/src/starboard/shared/starboard/player/player.gyp b/src/starboard/shared/starboard/player/player.gyp
index 625452c..05571b5 100644
--- a/src/starboard/shared/starboard/player/player.gyp
+++ b/src/starboard/shared/starboard/player/player.gyp
@@ -19,6 +19,8 @@
       'target_name': 'video_dmp',
       'type': 'static_library',
       'sources': [
+        '<(DEPTH)/starboard/shared/starboard/player/file_cache_reader.cc',
+        '<(DEPTH)/starboard/shared/starboard/player/file_cache_reader.h',
         '<(DEPTH)/starboard/shared/starboard/player/video_dmp_common.cc',
         '<(DEPTH)/starboard/shared/starboard/player/video_dmp_common.h',
         '<(DEPTH)/starboard/shared/starboard/player/video_dmp_reader.cc',
diff --git a/src/starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc b/src/starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc
new file mode 100644
index 0000000..9e991d7
--- /dev/null
+++ b/src/starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc
@@ -0,0 +1,56 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/player.h"
+
+#include "starboard/configuration.h"
+
+#if SB_HAS(PLAYER_GET_PREFERRED_OUTPUT_MODE)
+
+SbPlayerOutputMode SbPlayerGetPreferredOutputMode(
+    const SbMediaAudioSampleInfo* audio_sample_info,
+    const SbMediaVideoSampleInfo* video_sample_info,
+    SbDrmSystem drm_system,
+    const char* max_video_capabilities) {
+  SB_UNREFERENCED_PARAMETER(max_video_capabilities);
+
+  if (!audio_sample_info) {
+    SB_LOG(ERROR) << "audio_sample_info cannot be NULL";
+    return kSbPlayerOutputModeInvalid;
+  }
+
+  if (!video_sample_info) {
+    SB_LOG(ERROR) << "video_sample_info cannot be NULL";
+    return kSbPlayerOutputModeInvalid;
+  }
+
+  if (!max_video_capabilities) {
+    SB_LOG(ERROR) << "max_video_capabilities cannot be NULL";
+    return kSbPlayerOutputModeInvalid;
+  }
+
+  if (SbPlayerOutputModeSupported(kSbPlayerOutputModePunchOut,
+                                  video_sample_info->codec, drm_system)) {
+    return kSbPlayerOutputModePunchOut;
+  }
+  if (SbPlayerOutputModeSupported(kSbPlayerOutputModeDecodeToTexture,
+                                  video_sample_info->codec, drm_system)) {
+    return kSbPlayerOutputModeDecodeToTexture;
+  }
+
+  SB_NOTREACHED();
+  return kSbPlayerOutputModeInvalid;
+}
+
+#endif  // SB_HAS(PLAYER_GET_PREFERRED_OUTPUT_MODE)
diff --git a/src/starboard/shared/starboard/player/player_worker.cc b/src/starboard/shared/starboard/player/player_worker.cc
index 3300f48..0b1f1c3 100644
--- a/src/starboard/shared/starboard/player/player_worker.cc
+++ b/src/starboard/shared/starboard/player/player_worker.cc
@@ -224,18 +224,21 @@
   update_player_error_cb =
       std::bind(&PlayerWorker::UpdatePlayerError, this, _1, _2);
 #endif  // SB_HAS(PLAYER_ERROR_MESSAGE)
+  std::string error_message;
   if (handler_->Init(
           player_, std::bind(&PlayerWorker::UpdateMediaInfo, this, _1, _2, _3),
           std::bind(&PlayerWorker::player_state, this),
           std::bind(&PlayerWorker::UpdatePlayerState, this, _1),
-          update_player_error_cb)) {
+          update_player_error_cb, &error_message)) {
     UpdatePlayerState(kSbPlayerStateInitialized);
   } else {
 #if SB_HAS(PLAYER_ERROR_MESSAGE)
-    UpdatePlayerError(kSbPlayerErrorDecode,
-                      "Failed to initialize PlayerWorker.");
+    UpdatePlayerError(
+        kSbPlayerErrorDecode,
+        "Failed to initialize PlayerWorker with error " + error_message);
 #else   // SB_HAS(PLAYER_ERROR_MESSAGE)
-    UpdatePlayerError("Failed to initialize PlayerWorker.");
+    UpdatePlayerError("Failed to initialize PlayerWorker with error " +
+                      error_message);
 #endif  // SB_HAS(PLAYER_ERROR_MESSAGE)
   }
 }
diff --git a/src/starboard/shared/starboard/player/player_worker.h b/src/starboard/shared/starboard/player/player_worker.h
index 19b4f43..49d7042 100644
--- a/src/starboard/shared/starboard/player/player_worker.h
+++ b/src/starboard/shared/starboard/player/player_worker.h
@@ -80,7 +80,8 @@
                       UpdateMediaInfoCB update_media_info_cb,
                       GetPlayerStateCB get_player_state_cb,
                       UpdatePlayerStateCB update_player_state_cb,
-                      UpdatePlayerErrorCB update_player_error_cb) = 0;
+                      UpdatePlayerErrorCB update_player_error_cb,
+                      std::string* error_message) = 0;
     virtual bool Seek(SbTime seek_to_time, int ticket) = 0;
     virtual bool WriteSample(const scoped_refptr<InputBuffer>& input_buffer,
                              bool* written) = 0;
diff --git a/src/starboard/shared/starboard/player/testdata/licences/README b/src/starboard/shared/starboard/player/testdata/licences/README
new file mode 100644
index 0000000..245b315
--- /dev/null
+++ b/src/starboard/shared/starboard/player/testdata/licences/README
@@ -0,0 +1,9 @@
+Test Data License
+
+"sintel_329_ec3.dmp", "sintel_381_ac3.dmp" and "sintel_399_av1.dmp" are included
+as test files, under the Creative Commons 3.0 Attribution license. "Sintel" is
+an independently produced short film, initiated by the Blender Foundation as a
+means to further improve and validate the free/open source 3D creation suite
+Blender.
+
+Sintel © copyright Blender Foundation | durian.blender.org
diff --git a/src/starboard/shared/starboard/player/testdata/licences/creative_commons_BY30_licence.txt b/src/starboard/shared/starboard/player/testdata/licences/creative_commons_BY30_licence.txt
new file mode 100644
index 0000000..d1df8c0
--- /dev/null
+++ b/src/starboard/shared/starboard/player/testdata/licences/creative_commons_BY30_licence.txt
@@ -0,0 +1,320 @@
+Creative Commons Legal Code
+
+Attribution 3.0 Unported
+
+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+    LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+    REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
+    DAMAGES RESULTING FROM ITS USE.
+
+License
+
+THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
+COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
+COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
+AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+
+BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE
+TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY
+BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS
+CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
+CONDITIONS.
+
+1. Definitions
+
+ a. "Adaptation" means a work based upon the Work, or upon the Work and
+    other pre-existing works, such as a translation, adaptation,
+    derivative work, arrangement of music or other alterations of a
+    literary or artistic work, or phonogram or performance and includes
+    cinematographic adaptations or any other form in which the Work may be
+    recast, transformed, or adapted including in any form recognizably
+    derived from the original, except that a work that constitutes a
+    Collection will not be considered an Adaptation for the purpose of
+    this License. For the avoidance of doubt, where the Work is a musical
+    work, performance or phonogram, the synchronization of the Work in
+    timed-relation with a moving image ("synching") will be considered an
+    Adaptation for the purpose of this License.
+ b. "Collection" means a collection of literary or artistic works, such as
+    encyclopedias and anthologies, or performances, phonograms or
+    broadcasts, or other works or subject matter other than works listed
+    in Section 1(f) below, which, by reason of the selection and
+    arrangement of their contents, constitute intellectual creations, in
+    which the Work is included in its entirety in unmodified form along
+    with one or more other contributions, each constituting separate and
+    independent works in themselves, which together are assembled into a
+    collective whole. A work that constitutes a Collection will not be
+    considered an Adaptation (as defined above) for the purposes of this
+    License.
+ c. "Distribute" means to make available to the public the original and
+    copies of the Work or Adaptation, as appropriate, through sale or
+    other transfer of ownership.
+ d. "Licensor" means the individual, individuals, entity or entities that
+    offer(s) the Work under the terms of this License.
+ e. "Original Author" means, in the case of a literary or artistic work,
+    the individual, individuals, entity or entities who created the Work
+    or if no individual or entity can be identified, the publisher; and in
+    addition (i) in the case of a performance the actors, singers,
+    musicians, dancers, and other persons who act, sing, deliver, declaim,
+    play in, interpret or otherwise perform literary or artistic works or
+    expressions of folklore; (ii) in the case of a phonogram the producer
+    being the person or legal entity who first fixes the sounds of a
+    performance or other sounds; and, (iii) in the case of broadcasts, the
+    organization that transmits the broadcast.
+ f. "Work" means the literary and/or artistic work offered under the terms
+    of this License including without limitation any production in the
+    literary, scientific and artistic domain, whatever may be the mode or
+    form of its expression including digital form, such as a book,
+    pamphlet and other writing; a lecture, address, sermon or other work
+    of the same nature; a dramatic or dramatico-musical work; a
+    choreographic work or entertainment in dumb show; a musical
+    composition with or without words; a cinematographic work to which are
+    assimilated works expressed by a process analogous to cinematography;
+    a work of drawing, painting, architecture, sculpture, engraving or
+    lithography; a photographic work to which are assimilated works
+    expressed by a process analogous to photography; a work of applied
+    art; an illustration, map, plan, sketch or three-dimensional work
+    relative to geography, topography, architecture or science; a
+    performance; a broadcast; a phonogram; a compilation of data to the
+    extent it is protected as a copyrightable work; or a work performed by
+    a variety or circus performer to the extent it is not otherwise
+    considered a literary or artistic work.
+ g. "You" means an individual or entity exercising rights under this
+    License who has not previously violated the terms of this License with
+    respect to the Work, or who has received express permission from the
+    Licensor to exercise rights under this License despite a previous
+    violation.
+ h. "Publicly Perform" means to perform public recitations of the Work and
+    to communicate to the public those public recitations, by any means or
+    process, including by wire or wireless means or public digital
+    performances; to make available to the public Works in such a way that
+    members of the public may access these Works from a place and at a
+    place individually chosen by them; to perform the Work to the public
+    by any means or process and the communication to the public of the
+    performances of the Work, including by public digital performance; to
+    broadcast and rebroadcast the Work by any means including signs,
+    sounds or images.
+ i. "Reproduce" means to make copies of the Work by any means including
+    without limitation by sound or visual recordings and the right of
+    fixation and reproducing fixations of the Work, including storage of a
+    protected performance or phonogram in digital form or other electronic
+    medium.
+
+2. Fair Dealing Rights. Nothing in this License is intended to reduce,
+limit, or restrict any uses free from copyright or rights arising from
+limitations or exceptions that are provided for in connection with the
+copyright protection under copyright law or other applicable laws.
+
+3. License Grant. Subject to the terms and conditions of this License,
+Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
+perpetual (for the duration of the applicable copyright) license to
+exercise the rights in the Work as stated below:
+
+ a. to Reproduce the Work, to incorporate the Work into one or more
+    Collections, and to Reproduce the Work as incorporated in the
+    Collections;
+ b. to create and Reproduce Adaptations provided that any such Adaptation,
+    including any translation in any medium, takes reasonable steps to
+    clearly label, demarcate or otherwise identify that changes were made
+    to the original Work. For example, a translation could be marked "The
+    original work was translated from English to Spanish," or a
+    modification could indicate "The original work has been modified.";
+ c. to Distribute and Publicly Perform the Work including as incorporated
+    in Collections; and,
+ d. to Distribute and Publicly Perform Adaptations.
+ e. For the avoidance of doubt:
+
+     i. Non-waivable Compulsory License Schemes. In those jurisdictions in
+        which the right to collect royalties through any statutory or
+        compulsory licensing scheme cannot be waived, the Licensor
+        reserves the exclusive right to collect such royalties for any
+        exercise by You of the rights granted under this License;
+    ii. Waivable Compulsory License Schemes. In those jurisdictions in
+        which the right to collect royalties through any statutory or
+        compulsory licensing scheme can be waived, the Licensor waives the
+        exclusive right to collect such royalties for any exercise by You
+        of the rights granted under this License; and,
+   iii. Voluntary License Schemes. The Licensor waives the right to
+        collect royalties, whether individually or, in the event that the
+        Licensor is a member of a collecting society that administers
+        voluntary licensing schemes, via that society, from any exercise
+        by You of the rights granted under this License.
+
+The above rights may be exercised in all media and formats whether now
+known or hereafter devised. The above rights include the right to make
+such modifications as are technically necessary to exercise the rights in
+other media and formats. Subject to Section 8(f), all rights not expressly
+granted by Licensor are hereby reserved.
+
+4. Restrictions. The license granted in Section 3 above is expressly made
+subject to and limited by the following restrictions:
+
+ a. You may Distribute or Publicly Perform the Work only under the terms
+    of this License. You must include a copy of, or the Uniform Resource
+    Identifier (URI) for, this License with every copy of the Work You
+    Distribute or Publicly Perform. You may not offer or impose any terms
+    on the Work that restrict the terms of this License or the ability of
+    the recipient of the Work to exercise the rights granted to that
+    recipient under the terms of the License. You may not sublicense the
+    Work. You must keep intact all notices that refer to this License and
+    to the disclaimer of warranties with every copy of the Work You
+    Distribute or Publicly Perform. When You Distribute or Publicly
+    Perform the Work, You may not impose any effective technological
+    measures on the Work that restrict the ability of a recipient of the
+    Work from You to exercise the rights granted to that recipient under
+    the terms of the License. This Section 4(a) applies to the Work as
+    incorporated in a Collection, but this does not require the Collection
+    apart from the Work itself to be made subject to the terms of this
+    License. If You create a Collection, upon notice from any Licensor You
+    must, to the extent practicable, remove from the Collection any credit
+    as required by Section 4(b), as requested. If You create an
+    Adaptation, upon notice from any Licensor You must, to the extent
+    practicable, remove from the Adaptation any credit as required by
+    Section 4(b), as requested.
+ b. If You Distribute, or Publicly Perform the Work or any Adaptations or
+    Collections, You must, unless a request has been made pursuant to
+    Section 4(a), keep intact all copyright notices for the Work and
+    provide, reasonable to the medium or means You are utilizing: (i) the
+    name of the Original Author (or pseudonym, if applicable) if supplied,
+    and/or if the Original Author and/or Licensor designate another party
+    or parties (e.g., a sponsor institute, publishing entity, journal) for
+    attribution ("Attribution Parties") in Licensor's copyright notice,
+    terms of service or by other reasonable means, the name of such party
+    or parties; (ii) the title of the Work if supplied; (iii) to the
+    extent reasonably practicable, the URI, if any, that Licensor
+    specifies to be associated with the Work, unless such URI does not
+    refer to the copyright notice or licensing information for the Work;
+    and (iv) , consistent with Section 3(b), in the case of an Adaptation,
+    a credit identifying the use of the Work in the Adaptation (e.g.,
+    "French translation of the Work by Original Author," or "Screenplay
+    based on original Work by Original Author"). The credit required by
+    this Section 4 (b) may be implemented in any reasonable manner;
+    provided, however, that in the case of a Adaptation or Collection, at
+    a minimum such credit will appear, if a credit for all contributing
+    authors of the Adaptation or Collection appears, then as part of these
+    credits and in a manner at least as prominent as the credits for the
+    other contributing authors. For the avoidance of doubt, You may only
+    use the credit required by this Section for the purpose of attribution
+    in the manner set out above and, by exercising Your rights under this
+    License, You may not implicitly or explicitly assert or imply any
+    connection with, sponsorship or endorsement by the Original Author,
+    Licensor and/or Attribution Parties, as appropriate, of You or Your
+    use of the Work, without the separate, express prior written
+    permission of the Original Author, Licensor and/or Attribution
+    Parties.
+ c. Except as otherwise agreed in writing by the Licensor or as may be
+    otherwise permitted by applicable law, if You Reproduce, Distribute or
+    Publicly Perform the Work either by itself or as part of any
+    Adaptations or Collections, You must not distort, mutilate, modify or
+    take other derogatory action in relation to the Work which would be
+    prejudicial to the Original Author's honor or reputation. Licensor
+    agrees that in those jurisdictions (e.g. Japan), in which any exercise
+    of the right granted in Section 3(b) of this License (the right to
+    make Adaptations) would be deemed to be a distortion, mutilation,
+    modification or other derogatory action prejudicial to the Original
+    Author's honor and reputation, the Licensor will waive or not assert,
+    as appropriate, this Section, to the fullest extent permitted by the
+    applicable national law, to enable You to reasonably exercise Your
+    right under Section 3(b) of this License (right to make Adaptations)
+    but not otherwise.
+
+5. Representations, Warranties and Disclaimer
+
+UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
+OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY
+KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
+INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
+FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF
+LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS,
+WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION
+OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
+
+6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
+LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR
+ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES
+ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS
+BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. Termination
+
+ a. This License and the rights granted hereunder will terminate
+    automatically upon any breach by You of the terms of this License.
+    Individuals or entities who have received Adaptations or Collections
+    from You under this License, however, will not have their licenses
+    terminated provided such individuals or entities remain in full
+    compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
+    survive any termination of this License.
+ b. Subject to the above terms and conditions, the license granted here is
+    perpetual (for the duration of the applicable copyright in the Work).
+    Notwithstanding the above, Licensor reserves the right to release the
+    Work under different license terms or to stop distributing the Work at
+    any time; provided, however that any such election will not serve to
+    withdraw this License (or any other license that has been, or is
+    required to be, granted under the terms of this License), and this
+    License will continue in full force and effect unless terminated as
+    stated above.
+
+8. Miscellaneous
+
+ a. Each time You Distribute or Publicly Perform the Work or a Collection,
+    the Licensor offers to the recipient a license to the Work on the same
+    terms and conditions as the license granted to You under this License.
+ b. Each time You Distribute or Publicly Perform an Adaptation, Licensor
+    offers to the recipient a license to the original Work on the same
+    terms and conditions as the license granted to You under this License.
+ c. If any provision of this License is invalid or unenforceable under
+    applicable law, it shall not affect the validity or enforceability of
+    the remainder of the terms of this License, and without further action
+    by the parties to this agreement, such provision shall be reformed to
+    the minimum extent necessary to make such provision valid and
+    enforceable.
+ d. No term or provision of this License shall be deemed waived and no
+    breach consented to unless such waiver or consent shall be in writing
+    and signed by the party to be charged with such waiver or consent.
+ e. This License constitutes the entire agreement between the parties with
+    respect to the Work licensed here. There are no understandings,
+    agreements or representations with respect to the Work not specified
+    here. Licensor shall not be bound by any additional provisions that
+    may appear in any communication from You. This License may not be
+    modified without the mutual written agreement of the Licensor and You.
+ f. The rights granted under, and the subject matter referenced, in this
+    License were drafted utilizing the terminology of the Berne Convention
+    for the Protection of Literary and Artistic Works (as amended on
+    September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
+    Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996
+    and the Universal Copyright Convention (as revised on July 24, 1971).
+    These rights and subject matter take effect in the relevant
+    jurisdiction in which the License terms are sought to be enforced
+    according to the corresponding provisions of the implementation of
+    those treaty provisions in the applicable national law. If the
+    standard suite of rights granted under applicable copyright law
+    includes additional rights not granted under this License, such
+    additional rights are deemed to be included in the License; this
+    License is not intended to restrict the license of any rights under
+    applicable law.
+
+
+Creative Commons Notice
+
+    Creative Commons is not a party to this License, and makes no warranty
+    whatsoever in connection with the Work. Creative Commons will not be
+    liable to You or any party on any legal theory for any damages
+    whatsoever, including without limitation any general, special,
+    incidental or consequential damages arising in connection to this
+    license. Notwithstanding the foregoing two (2) sentences, if Creative
+    Commons has expressly identified itself as the Licensor hereunder, it
+    shall have all rights and obligations of Licensor.
+
+    Except for the limited purpose of indicating to the public that the
+    Work is licensed under the CCPL, Creative Commons does not authorize
+    the use by either party of the trademark "Creative Commons" or any
+    related trademark or logo of Creative Commons without the prior
+    written consent of Creative Commons. Any permitted use will be in
+    compliance with Creative Commons' then-current trademark usage
+    guidelines, as may be published on its website or otherwise made
+    available upon request from time to time. For the avoidance of doubt,
+    this trademark restriction does not form part of this License.
+
+    Creative Commons may be contacted at https://creativecommons.org/.
+
diff --git a/src/starboard/shared/starboard/player/testdata/sintel_329_ec3.dmp.sha1 b/src/starboard/shared/starboard/player/testdata/sintel_329_ec3.dmp.sha1
new file mode 100644
index 0000000..1afa457
--- /dev/null
+++ b/src/starboard/shared/starboard/player/testdata/sintel_329_ec3.dmp.sha1
@@ -0,0 +1 @@
+e69024d74c0d49e75e0447ce10b45ac18abbd1cc
diff --git a/src/starboard/shared/starboard/player/testdata/sintel_381_ac3.dmp.sha1 b/src/starboard/shared/starboard/player/testdata/sintel_381_ac3.dmp.sha1
new file mode 100644
index 0000000..f7d8625
--- /dev/null
+++ b/src/starboard/shared/starboard/player/testdata/sintel_381_ac3.dmp.sha1
@@ -0,0 +1 @@
+3ab684539ae21c22b983e167a07d354eed545bc0
diff --git a/src/starboard/shared/starboard/player/testdata/sintel_399_av1.dmp.sha1 b/src/starboard/shared/starboard/player/testdata/sintel_399_av1.dmp.sha1
new file mode 100644
index 0000000..1b7d053
--- /dev/null
+++ b/src/starboard/shared/starboard/player/testdata/sintel_399_av1.dmp.sha1
@@ -0,0 +1 @@
+49eabd9cc00ccec48209c7fbe3b8f2f30649dc5f
\ No newline at end of file
diff --git a/src/starboard/shared/starboard/player/tools/compare_video_hashes.py b/src/starboard/shared/starboard/player/tools/compare_video_hashes.py
new file mode 100644
index 0000000..10c29ee
--- /dev/null
+++ b/src/starboard/shared/starboard/player/tools/compare_video_hashes.py
@@ -0,0 +1,118 @@
+# Copyright 2020 The Cobalt Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tool to verify video input hashes dump by --dump_video_input_hash."""
+
+import sys
+
+
+class VideoHashes(object):
+  """Manages the timestamp to frame hashes.
+
+     The timestamp to frame hashes are loaded from log file generated using
+     --dump_video_input_hash command line parameter.
+  """
+
+  def __init__(self, filename):
+    """Loads the timestamp to frame hashes dictionary from log file."""
+    # A typical log line looks like:
+    #   ... filter_based_player_worker_handler.cc(...)] Dump clear audio input \
+    #       hash @ 23219: 2952221532
+    with open(filename, 'r') as f:
+      lines = [
+          line for line in f.readlines() if line.find('input hash') != -1 and
+          line.find('filter_based_player_worker_handler') != -1
+      ]
+    is_audio_encrypted = False
+    is_video_encrypted = False
+    for line in lines:
+      if line.find('encrypted audio') != -1:
+        is_audio_encrypted = True
+        continue
+      if line.find('encrypted video') != -1:
+        is_video_encrypted = True
+        continue
+
+      tokens = line.split('Dump clear')
+      assert len(tokens) > 1
+
+      tokens = tokens[-1].split()
+      assert len(tokens) == 6
+
+      if tokens[0] == 'audio':
+        self._audio_timestamp_to_hashes[tokens[4]] = [tokens[5]]
+      else:
+        assert tokens[0] == 'video'
+        self._video_timestamp_to_hashes[tokens[4]] = [tokens[5]]
+
+    print '{} contains {} audio samples and {} video samples,'.format(
+        filename, len(self._audio_timestamp_to_hashes),
+        len(self._video_timestamp_to_hashes))
+    print '  its audio stream is {}, its video stream is {}.'.format(
+        'encrypted' if is_audio_encrypted else 'clear',
+        'encrypted' if is_video_encrypted else 'clear')
+
+  def AreHashesMatching(self, other):
+    """Compare if two objects match each other."""
+    self._AreHashesMatching('audio', self._audio_timestamp_to_hashes,
+                            other.GetAudioTimestampToHashes())
+    self._AreHashesMatching('video', self._video_timestamp_to_hashes,
+                            other.GetVideoTimestampToHashes())
+
+  def _AreHashesMatching(self, media_type, timestamp_to_hashes1,
+                         timestamp_to_hashes2):
+    """Compare if two timestamp to frame hashes dictionary match each other."""
+    hashes_to_check = min(len(timestamp_to_hashes1), len(timestamp_to_hashes2))
+
+    all_matches = True
+
+    for timestamp in timestamp_to_hashes1:
+      hashes_to_check = hashes_to_check - 1
+      if hashes_to_check < 0:
+        break
+
+      if timestamp not in timestamp_to_hashes2:
+        print media_type, 'frame @ timestamp', timestamp, ('in file 1 isn\'t in'
+                                                           ' file 2')
+        all_matches = False
+        continue
+      if timestamp_to_hashes1[timestamp] != timestamp_to_hashes2[timestamp]:
+        print media_type, 'frame @ timestamp', timestamp, 'hash mismatches'
+        all_matches = False
+        continue
+
+    if all_matches:
+      print 'All', media_type, 'inputs match'
+
+  def GetAudioTimestampToHashes(self):
+    return self._audio_timestamp_to_hashes
+
+  def GetVideoTimestampToHashes(self):
+    return self._video_timestamp_to_hashes
+
+  _audio_timestamp_to_hashes = {}
+  _video_timestamp_to_hashes = {}
+
+
+def CompareVideoHashes(filename1, filename2):
+  hashes1 = VideoHashes(filename1)
+  hashes2 = VideoHashes(filename2)
+
+  hashes1.AreHashesMatching(hashes2)
+
+
+if len(sys.argv) != 3:
+  print('USAGE: compare_video_timestamp_to_hashes.py <input_file_1>',
+        '<input_file_2>')
+else:
+  CompareVideoHashes(sys.argv[1], sys.argv[2])
diff --git a/src/starboard/shared/starboard/player/video_dmp_reader.cc b/src/starboard/shared/starboard/player/video_dmp_reader.cc
index 6f2de79..f49e1f8 100644
--- a/src/starboard/shared/starboard/player/video_dmp_reader.cc
+++ b/src/starboard/shared/starboard/player/video_dmp_reader.cc
@@ -17,6 +17,8 @@
 #include <algorithm>
 #include <functional>
 
+#include "starboard/shared/starboard/player/file_cache_reader.h"
+
 #if SB_HAS(PLAYER_FILTER_TESTS)
 namespace starboard {
 namespace shared {
@@ -97,11 +99,10 @@
 
 VideoDmpReader::VideoDmpReader(const char* filename)
     : reverse_byte_order_(false) {
-  ScopedFile file(filename, kSbFileOpenOnly | kSbFileRead);
-  SB_CHECK(file.IsValid()) << "Failed to open " << filename;
-  int64_t file_size = file.GetSize();
+  FileCacheReader reader(filename, 1024 * 1024);
+  int64_t file_size = reader.GetSize();
   SB_CHECK(file_size >= 0);
-  read_cb_ = std::bind(&VideoDmpReader::ReadFromFile, this, &file, _1, _2);
+  read_cb_ = std::bind(&FileCacheReader::Read, &reader, _1, _2);
   Parse();
 }
 
@@ -255,12 +256,6 @@
                          std::move(data), video_sample_info);
 }
 
-int VideoDmpReader::ReadFromFile(ScopedFile* file,
-                                 void* buffer,
-                                 int bytes_to_read) {
-  return file->ReadAll(static_cast<char*>(buffer), bytes_to_read);
-}
-
 }  // namespace video_dmp
 }  // namespace player
 }  // namespace starboard
diff --git a/src/starboard/shared/starboard/player/video_dmp_reader.h b/src/starboard/shared/starboard/player/video_dmp_reader.h
index 063eb68..2efd044 100644
--- a/src/starboard/shared/starboard/player/video_dmp_reader.h
+++ b/src/starboard/shared/starboard/player/video_dmp_reader.h
@@ -20,7 +20,6 @@
 
 #include "starboard/common/log.h"
 #include "starboard/common/ref_counted.h"
-#include "starboard/file.h"
 #include "starboard/media.h"
 #include "starboard/player.h"
 #include "starboard/shared/internal_only.h"
@@ -119,7 +118,6 @@
   void Parse();
   AudioAccessUnit ReadAudioAccessUnit();
   VideoAccessUnit ReadVideoAccessUnit();
-  int ReadFromFile(ScopedFile* file, void* buffer, int bytes_to_read);
 
   ReadCB read_cb_;
 
diff --git a/src/starboard/shared/starboard/thread_local_storage_internal.h b/src/starboard/shared/starboard/thread_local_storage_internal.h
index 312b98b..41f8fce 100644
--- a/src/starboard/shared/starboard/thread_local_storage_internal.h
+++ b/src/starboard/shared/starboard/thread_local_storage_internal.h
@@ -19,6 +19,7 @@
 
 #include "starboard/common/mutex.h"
 #include "starboard/common/scoped_ptr.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/shared/internal_only.h"
 #include "starboard/thread.h"
 
@@ -52,8 +53,8 @@
   void ShutdownTLSForThread();
 
  private:
-  // We add 1 to SB_MAX_THREADS here to account for the main thread.
-  static const int kMaxThreads = SB_MAX_THREADS + 1;
+  // We add 1 to kSbMaxThreads here to account for the main thread.
+  static const int kMaxThreads = kSbMaxThreads + 1;
   struct KeyRecord {
     bool valid;
     SbThreadLocalDestructor destructor;
diff --git a/src/starboard/shared/stub/player_get_preferred_output_mode.cc b/src/starboard/shared/stub/player_get_preferred_output_mode.cc
new file mode 100644
index 0000000..db08ce3
--- /dev/null
+++ b/src/starboard/shared/stub/player_get_preferred_output_mode.cc
@@ -0,0 +1,29 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/player.h"
+
+#include "starboard/configuration.h"
+
+#if SB_HAS(PLAYER_GET_PREFERRED_OUTPUT_MODE)
+
+SbPlayerOutputMode SbPlayerGetPreferredOutputMode(
+    const SbMediaAudioSampleInfo* audio_sample_info,
+    const SbMediaVideoSampleInfo* video_sample_info,
+    SbDrmSystem drm_system,
+    const char* max_video_capabilities) {
+  return kSbPlayerOutputModeInvalid;
+}
+
+#endif  // SB_HAS(PLAYER_GET_PREFERRED_OUTPUT_MODE)
diff --git a/src/starboard/shared/stub/thread_create_priority.cc b/src/starboard/shared/stub/thread_create_priority.cc
new file mode 100644
index 0000000..c003edb
--- /dev/null
+++ b/src/starboard/shared/stub/thread_create_priority.cc
@@ -0,0 +1,30 @@
+// Copyright 2019 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/pthread/thread_create_priority.h"
+
+namespace starboard {
+namespace shared {
+namespace pthread {
+
+#if SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION
+
+// Default implementation without thread priority support
+void ThreadSetPriority(SbThreadPriority /* priority */) {}
+
+#endif  // SB_API_VERSION >= SB_FEATURE_RUNTIME_CONFIGS_VERSION
+
+}  // namespace pthread
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/widevine/drm_system_widevine.cc b/src/starboard/shared/widevine/drm_system_widevine.cc
index e5c08ea..95f8a72 100644
--- a/src/starboard/shared/widevine/drm_system_widevine.cc
+++ b/src/starboard/shared/widevine/drm_system_widevine.cc
@@ -22,6 +22,7 @@
 #include "starboard/common/log.h"
 #include "starboard/common/mutex.h"
 #include "starboard/common/string.h"
+#include "starboard/configuration_constants.h"
 #include "starboard/memory.h"
 #include "starboard/once.h"
 #include "starboard/shared/starboard/application.h"
@@ -89,12 +90,13 @@
 SB_ONCE_INITIALIZE_FUNCTION(Registry, GetRegistry);
 
 std::string GetWidevineStoragePath() {
-  char path[SB_FILE_MAX_PATH + 1] = {0};
-  auto path_size = SB_ARRAY_SIZE_INT(path);
-  SB_CHECK(SbSystemGetPath(kSbSystemPathCacheDirectory, path, path_size) &&
-           SbStringConcat(path, SB_FILE_SEP_STRING, path_size) &&
-           SbStringConcat(path, kWidevineStorageFileName, path_size));
-  return path;
+  std::vector<char> path(kSbFileMaxPath + 1, 0);
+  auto path_size = path.size();
+  SB_CHECK(
+      SbSystemGetPath(kSbSystemPathCacheDirectory, path.data(), path_size) &&
+      SbStringConcat(path.data(), kSbFileSepString, path_size) &&
+      SbStringConcat(path.data(), kWidevineStorageFileName, path_size));
+  return std::string(path.data());
 }
 
 // Converts |::widevine::Cdm::KeyStatus| to starboard's |SbDrmKeyStatus|
@@ -423,6 +425,12 @@
   input.iv_length = static_cast<uint32_t>(initialization_vector.size());
   input.is_video = (buffer->sample_type() == kSbMediaTypeVideo);
 
+#if SB_API_VERSION >= SB_DRM_CBCS_SUPPORT_VERSION
+  input.pattern.encrypted_blocks =
+      drm_info->encryption_pattern.crypt_byte_block;
+  input.pattern.clear_blocks = drm_info->encryption_pattern.skip_byte_block;
+#endif  // SB_API_VERSION >= SB_DRM_CBCS_SUPPORT_VERSION
+
   std::vector<uint8_t> output_data(buffer->size());
   wv3cdm::OutputBuffer output;
   output.data = output_data.data();
@@ -463,6 +471,13 @@
     if (subsample.encrypted_byte_count) {
       input.last_subsample = i + 1 == buffer->drm_info()->subsample_count;
       input.encryption_scheme = wv3cdm::EncryptionScheme::kAesCtr;
+#if SB_API_VERSION >= SB_DRM_CBCS_SUPPORT_VERSION
+      if (drm_info->encryption_scheme == kSbDrmEncryptionSchemeAesCbc) {
+        input.encryption_scheme = wv3cdm::EncryptionScheme::kAesCbc;
+      } else {
+        SB_DCHECK(drm_info->encryption_scheme == kSbDrmEncryptionSchemeAesCtr);
+      }
+#endif  // SB_API_VERSION >= SB_DRM_CBCS_SUPPORT_VERSION
       input.data_length = subsample.encrypted_byte_count;
 
       wv3cdm::Status status = cdm_->decrypt(input, output);