Import Cobalt 6.16000
diff --git a/src/starboard/build/convert_i18n_data.py b/src/starboard/build/convert_i18n_data.py
index a34916a..0f56a59 100644
--- a/src/starboard/build/convert_i18n_data.py
+++ b/src/starboard/build/convert_i18n_data.py
@@ -51,7 +51,7 @@
   messages = root[0]
 
   # Write each message to the output file on its own line.
-  with open(output_filename, 'w') as output_file:
+  with open(output_filename, 'wb') as output_file:
     for msg in messages:
       # Use ; as the separator. Which means it better not be in the name.
       assert not (';' in msg.attrib['name'])
diff --git a/src/starboard/client_porting/poem/getenv_stub_poem.h b/src/starboard/client_porting/poem/getenv_stub_poem.h
new file mode 100644
index 0000000..8e4ab81
--- /dev/null
+++ b/src/starboard/client_porting/poem/getenv_stub_poem.h
@@ -0,0 +1,28 @@
+// Copyright 2016 Google Inc. 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.
+
+// A poem (POsix EMulation) stub implementation for getenv.
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_GETENV_STUB_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_GETENV_STUB_POEM_H_
+
+#include <stdlib.h>
+
+#include "starboard/configuration.h"
+
+static SB_C_INLINE const char* getenv(const char* unused) {
+  return NULL;
+}
+
+#endif  // STARBOARD_CLIENT_PORTING_POEM_GETENV_STUB_POEM_H_
diff --git a/src/starboard/client_porting/poem/inet_poem.h b/src/starboard/client_porting/poem/inet_poem.h
new file mode 100644
index 0000000..55cf47a
--- /dev/null
+++ b/src/starboard/client_porting/poem/inet_poem.h
@@ -0,0 +1,27 @@
+// Copyright 2016 Google Inc. 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.
+
+// A poem (POsix EMulation) for functions usually declared in <arpa/inet.h>
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_INET_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_INET_POEM_H_
+
+#include "starboard/byte_swap.h"
+
+#define htonl(x) SB_HOST_TO_NET_U32(x)
+#define htons(x) SB_HOST_TO_NET_U16(x)
+#define ntohl(x) SB_NET_TO_HOST_U32(x)
+#define ntohs(x) SB_NET_TO_HOST_U16(x)
+
+#endif  // STARBOARD_CLIENT_PORTING_POEM_INET_POEM_H_
diff --git a/src/starboard/client_porting/poem/poem.gyp b/src/starboard/client_porting/poem/poem.gyp
index def3f4e..947cc36 100644
--- a/src/starboard/client_porting/poem/poem.gyp
+++ b/src/starboard/client_porting/poem/poem.gyp
@@ -19,10 +19,13 @@
       'type': 'static_library',
       'sources': [
         'eztime_poem.h',
+        'getenv_stub_poem.h',
+        'inet_poem.h',
         'stdio_poem.h',
         'stdlib_poem.h',
         'string_poem.h',
         'strings_poem.h',
+        'strnlen_poem.h',
         'wchar_poem.h',
       ],
       'dependencies': [
@@ -44,5 +47,16 @@
         '<(DEPTH)/starboard/starboard.gyp:starboard',
       ],
     },
+    {
+      'target_name': 'poem_unittests_deploy',
+      'type': 'none',
+      'dependencies': [
+        'poem_unittests',
+      ],
+      'variables': {
+        'executable_name': 'poem_unittests',
+      },
+      'includes': [ '../../build/deploy.gypi' ],
+    },
   ],
 }
diff --git a/src/starboard/client_porting/poem/string_poem_test.cc b/src/starboard/client_porting/poem/string_poem_test.cc
index 2243b48..1a3e899 100644
--- a/src/starboard/client_porting/poem/string_poem_test.cc
+++ b/src/starboard/client_porting/poem/string_poem_test.cc
@@ -17,6 +17,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #include "starboard/client_porting/poem/string_poem.h"
+#include "starboard/client_porting/poem/strnlen_poem.h"
 
 namespace starboard {
 namespace nplb {
@@ -76,6 +77,20 @@
   EXPECT_STREQ(a, "Wu");
 }
 
+TEST(StringPoemTest, PoemStringGetLengthFixed) {
+  char a[] = "abcdef";
+  char b[] = "abc\0def";
+
+  EXPECT_EQ(strnlen(a, 0), 0);
+  EXPECT_EQ(strnlen(a, 3), 3);
+  EXPECT_EQ(strnlen(a, sizeof(a)), 6);
+  EXPECT_EQ(strnlen(a, 256), 6);
+  EXPECT_EQ(strnlen(b, 2), 2);
+  EXPECT_EQ(strnlen(b, 3), 3);
+  EXPECT_EQ(strnlen(b, sizeof(b)), 3);
+  EXPECT_EQ(strnlen(b, 256), 3);
+}
+
 }  // namespace
 }  // namespace nplb
 }  // namespace starboard
diff --git a/src/starboard/client_porting/poem/strnlen_poem.h b/src/starboard/client_porting/poem/strnlen_poem.h
new file mode 100644
index 0000000..fb2d674
--- /dev/null
+++ b/src/starboard/client_porting/poem/strnlen_poem.h
@@ -0,0 +1,33 @@
+// Copyright 2016 Google Inc. 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.
+
+// A poem (POsix EMulation) implementation for strnlen. Usually declared in
+// <string.h>, but may be missing on some platforms (e.g. PS3).
+
+#ifndef STARBOARD_CLIENT_PORTING_POEM_STRNLEN_POEM_H_
+#define STARBOARD_CLIENT_PORTING_POEM_STRNLEN_POEM_H_
+
+#include "starboard/configuration.h"
+
+static SB_C_INLINE size_t StringGetLengthFixed(const char* s, size_t maxlen) {
+  size_t i = 0;
+  while (i < maxlen && s[i]) {
+    ++i;
+  }
+  return i;
+}
+
+#define strnlen(s, maxlen) StringGetLengthFixed(s, maxlen)
+
+#endif  // STARBOARD_CLIENT_PORTING_POEM_STRNLEN_POEM_H_
diff --git a/src/starboard/client_porting/pr_starboard/pr_starboard.cc b/src/starboard/client_porting/pr_starboard/pr_starboard.cc
new file mode 100644
index 0000000..732ea14
--- /dev/null
+++ b/src/starboard/client_porting/pr_starboard/pr_starboard.cc
@@ -0,0 +1,281 @@
+// Copyright 2016 Google Inc. 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/client_porting/pr_starboard/pr_starboard.h"
+
+#include "starboard/condition_variable.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/mutex.h"
+#include "starboard/once.h"
+#include "starboard/queue.h"
+#include "starboard/thread.h"
+#include "starboard/time.h"
+#include "starboard/types.h"
+
+namespace {
+
+typedef starboard::Queue<bool> SetupSignalQueue;
+
+// Utility function to convert a PRInterval to signed 64 bit integer
+// microseconds.
+int64_t PR_IntervalToMicrosecondsInt64(PRIntervalTime ticks) {
+  uint32_t microseconds_as_uint32 = PR_IntervalToMicroseconds(ticks);
+  int64_t microseconds_as_int64 = static_cast<int64_t>(microseconds_as_uint32);
+  return microseconds_as_int64;
+}
+
+// Struct to bundle up arguments to be passed into SbThreadCreate.
+struct ThreadEntryPointWrapperContext {
+  ThreadEntryPointWrapperContext(void* pr_context,
+                                 PRThread* pr_thread,
+                                 PRThreadEntryPoint pr_entry_point,
+                                 SetupSignalQueue* setup_signal_queue)
+      : pr_context(pr_context),
+        pr_thread(pr_thread),
+        pr_entry_point(pr_entry_point),
+        setup_signal_queue(setup_signal_queue) {}
+  void* pr_context;
+  PRThread* pr_thread;
+  PRThreadEntryPoint pr_entry_point;
+  SetupSignalQueue* setup_signal_queue;
+};
+
+// The thread local key that corresponds to where local PRThread* data is held.
+SbThreadLocalKey g_pr_thread_local_key = kSbThreadLocalKeyInvalid;
+// The SbOnceControlStructure to to ensure that the local key is only created
+// once.
+SbOnceControl g_pr_thread_key_once_control = SB_ONCE_INITIALIZER;
+
+void PrThreadDtor(void* value) {
+  PRThread* pr_thread = reinterpret_cast<PRThread*>(value);
+  delete pr_thread;
+}
+
+void InitPrThreadKey() {
+  g_pr_thread_local_key = SbThreadCreateLocalKey(PrThreadDtor);
+}
+
+SbThreadLocalKey GetPrThreadKey() {
+  SB_CHECK(SbOnce(&g_pr_thread_key_once_control, InitPrThreadKey));
+  return g_pr_thread_local_key;
+}
+
+void* ThreadEntryPointWrapper(void* context_as_void_pointer) {
+  ThreadEntryPointWrapperContext* context =
+      reinterpret_cast<ThreadEntryPointWrapperContext*>(
+          context_as_void_pointer);
+  void* pr_context = context->pr_context;
+  PRThreadEntryPoint pr_entry_point = context->pr_entry_point;
+  PRThread* pr_thread = context->pr_thread;
+  SetupSignalQueue* setup_signal_queue = context->setup_signal_queue;
+
+  delete context;
+
+  pr_thread->sb_thread = SbThreadGetCurrent();
+  SbThreadLocalKey key = GetPrThreadKey();
+  SB_CHECK(SbThreadIsValidLocalKey(key));
+  SbThreadSetLocalValue(key, pr_thread);
+
+  setup_signal_queue->Put(true);
+  pr_entry_point(pr_context);
+
+  return NULL;
+}
+
+}  // namespace
+
+PRLock* PR_NewLock() {
+  PRLock* lock = new PRLock();
+  if (!SbMutexCreate(lock)) {
+    delete lock;
+    return NULL;
+  }
+  return lock;
+}
+
+void PR_DestroyLock(PRLock* lock) {
+  SB_DCHECK(lock);
+  SbMutexDestroy(lock);
+  delete lock;
+}
+
+PRCondVar* PR_NewCondVar(PRLock* lock) {
+  SB_DCHECK(lock);
+  PRCondVar* cvar = new PRCondVar();
+  if (!SbConditionVariableCreate(&cvar->sb_condition_variable, lock)) {
+    delete cvar;
+    return NULL;
+  }
+  cvar->lock = lock;
+  return cvar;
+}
+
+void PR_DestroyCondVar(PRCondVar* cvar) {
+  SbConditionVariableDestroy(&cvar->sb_condition_variable);
+  delete cvar;
+}
+
+PRStatus PR_WaitCondVar(PRCondVar* cvar, PRIntervalTime timeout) {
+  SbConditionVariableResult result;
+  if (timeout == PR_INTERVAL_NO_WAIT) {
+    result = SbConditionVariableWaitTimed(&cvar->sb_condition_variable,
+                                          cvar->lock, 0);
+  } else if (timeout == PR_INTERVAL_NO_TIMEOUT) {
+    result = SbConditionVariableWait(&cvar->sb_condition_variable, cvar->lock);
+  } else {
+    int64_t microseconds = PR_IntervalToMicrosecondsInt64(timeout);
+    result = SbConditionVariableWaitTimed(&cvar->sb_condition_variable,
+                                          cvar->lock, microseconds);
+  }
+  return pr_starboard::ToPRStatus(result != kSbConditionVariableFailed);
+}
+
+PRThread* PR_GetCurrentThread() {
+  SbThreadLocalKey key = GetPrThreadKey();
+  SB_CHECK(SbThreadIsValidLocalKey(key));
+
+  PRThread* value = static_cast<PRThread*>(SbThreadGetLocalValue(key));
+  // We could potentially be a thread that was not created through
+  // PR_CreateThread.  In this case, we must allocate a PRThread and do the
+  // setup that would normally have been done in PR_CreateThread.
+  if (!value) {
+    PRThread* pr_thread = new PRThread(SbThreadGetCurrent());
+    SbThreadSetLocalValue(key, pr_thread);
+    value = pr_thread;
+  }
+
+  return value;
+}
+
+uint32_t PR_snprintf(char* out, uint32_t outlen, const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  uint32_t ret = PR_vsnprintf(out, outlen, fmt, args);
+  va_end(args);
+  return ret;
+}
+
+PRThread* PR_CreateThread(PRThreadType type,
+                          PRThreadEntryPoint start,
+                          void* arg,
+                          PRThreadPriority priority,
+                          PRThreadScope scope,
+                          PRThreadState state,
+                          PRUint32 stackSize) {
+  int64_t sb_stack_size = static_cast<int64_t>(stackSize);
+
+  SbThreadPriority sb_priority;
+  switch (priority) {
+    case PR_PRIORITY_LOW:
+      sb_priority = kSbThreadPriorityLow;
+      break;
+    case PR_PRIORITY_NORMAL:
+      sb_priority = kSbThreadPriorityNormal;
+      break;
+    case PR_PRIORITY_HIGH:
+      sb_priority = kSbThreadPriorityHigh;
+      break;
+    case PR_PRIORITY_LAST:
+      sb_priority = kSbThreadPriorityHighest;
+      break;
+    default:
+      sb_priority = kSbThreadNoPriority;
+  }
+
+  SbThreadAffinity sb_affinity = kSbThreadNoAffinity;
+
+  SB_DCHECK(state == PR_JOINABLE_THREAD || state == PR_UNJOINABLE_THREAD);
+  bool sb_joinable = (state == PR_JOINABLE_THREAD);
+
+  // This heap allocated PRThread object will have a pointer to it stored in
+  // the newly created child thread's thread local storage.  Once the newly
+  // created child thread finishes, it will be freed in the destructor
+  // associated with it through thread local storage.
+  PRThread* pr_thread = new PRThread(kSbThreadInvalid);
+
+  // Utility queue for the ThreadEntryWrapper to signal us once it's done
+  // running its initial setup and we can safely exit.
+  SetupSignalQueue setup_signal_queue;
+
+  // This heap allocated context object is freed after
+  // ThreadEntryPointWrapper's initial setup is complete, right before the
+  // nspr level entry point is run.
+  ThreadEntryPointWrapperContext* context = new ThreadEntryPointWrapperContext(
+      arg, pr_thread, start, &setup_signal_queue);
+
+  // Note that pr_thread->sb_thread will be set to the correct value in the
+  // setup section of ThreadEntryPointWrapper.  It is done there rather than
+  // here to account for the unlikely but possible case in which we enter the
+  // newly created child thread, and then the child thread passes references
+  // to itself off into its potential children or co-threads that interact
+  // with it before we can copy what SbThreadCreate returns into
+  // pr_thread->sb_thread from this current thread.
+  SbThreadCreate(sb_stack_size, sb_priority, sb_affinity, sb_joinable, NULL,
+                 ThreadEntryPointWrapper, context);
+
+  // Now we must wait for the setup section of ThreadEntryPointWrapper to run
+  // and initialize pr_thread (both the struct itself and the corresponding
+  // new thread's private data) before we can safely return.  We expect to
+  // receive true rather than false by convention.
+  bool setup_signal = setup_signal_queue.Get();
+  SB_DCHECK(setup_signal);
+
+  return pr_thread;
+}
+
+PRStatus PR_CallOnceWithArg(PRCallOnceType* once,
+                            PRCallOnceWithArgFN func,
+                            void* arg) {
+  SB_NOTREACHED() << "Not implemented";
+  return PR_FAILURE;
+}
+
+PRStatus PR_NewThreadPrivateIndex(PRTLSIndex* newIndex,
+                                  PRThreadPrivateDTOR destructor) {
+  SbThreadLocalKey key = SbThreadCreateLocalKey(destructor);
+  if (!SbThreadIsValidLocalKey(key)) {
+    return pr_starboard::ToPRStatus(false);
+  }
+  *newIndex = key;
+  return pr_starboard::ToPRStatus(true);
+}
+
+PRIntervalTime PR_MillisecondsToInterval(PRUint32 milli) {
+  PRUint64 tock = static_cast<PRUint64>(milli);
+  PRUint64 msecPerSec = static_cast<PRInt64>(PR_MSEC_PER_SEC);
+  PRUint64 rounding = static_cast<PRInt64>(PR_MSEC_PER_SEC >> 1);
+  PRUint64 tps = static_cast<PRInt64>(PR_TicksPerSecond());
+
+  tock *= tps;
+  tock += rounding;
+  tock /= msecPerSec;
+
+  PRUint64 ticks = static_cast<PRUint64>(tock);
+  return ticks;
+}
+
+PRUint32 PR_IntervalToMicroseconds(PRIntervalTime ticks) {
+  PRUint64 tock = static_cast<PRInt64>(ticks);
+  PRUint64 usecPerSec = static_cast<PRInt64>(PR_USEC_PER_SEC);
+  PRUint64 tps = static_cast<PRInt64>(PR_TicksPerSecond());
+  PRUint64 rounding = static_cast<PRUint64>(tps) >> 1;
+
+  tock *= usecPerSec;
+  tock += rounding;
+  tock /= tps;
+
+  PRUint32 micro = static_cast<PRUint32>(tock);
+  return micro;
+}
diff --git a/src/starboard/client_porting/pr_starboard/pr_starboard.gyp b/src/starboard/client_porting/pr_starboard/pr_starboard.gyp
new file mode 100644
index 0000000..0874b65
--- /dev/null
+++ b/src/starboard/client_porting/pr_starboard/pr_starboard.gyp
@@ -0,0 +1,29 @@
+# Copyright 2016 Google Inc. 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.
+
+{
+  'targets': [
+    {
+      'target_name': 'pr_starboard',
+      'type': 'static_library',
+      'sources': [
+        'pr_starboard.cc',
+        'pr_starboard.h',
+      ],
+      'dependencies': [
+        '<(DEPTH)/starboard/starboard.gyp:starboard',
+      ],
+    },
+  ],
+}
diff --git a/src/starboard/client_porting/pr_starboard/pr_starboard.h b/src/starboard/client_porting/pr_starboard/pr_starboard.h
new file mode 100644
index 0000000..63e5c4d
--- /dev/null
+++ b/src/starboard/client_porting/pr_starboard/pr_starboard.h
@@ -0,0 +1,189 @@
+// Copyright 2016 Google Inc. 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.
+
+// This header defines the interface for a starboard based implementation of
+// the subset of nspr that SpiderMonkey depends on.  It directly matches the
+// NSPR API, with the exception that accessing thread local data should use
+// PRTLSIndex, rather than PRUintn.
+
+#ifndef STARBOARD_CLIENT_PORTING_PR_STARBOARD_PR_STARBOARD_H_
+#define STARBOARD_CLIENT_PORTING_PR_STARBOARD_PR_STARBOARD_H_
+
+#include "starboard/condition_variable.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/mutex.h"
+#include "starboard/string.h"
+#include "starboard/thread.h"
+#include "starboard/types.h"
+
+#define PR_CALLBACK
+
+#define PR_MSEC_PER_SEC 1000L
+#define PR_USEC_PER_SEC 1000000L
+#define PR_NSEC_PER_SEC 1000000000L
+#define PR_USEC_PER_MSEC 1000L
+#define PR_NSEC_PER_MSEC 1000000L
+
+typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus;
+
+namespace pr_starboard {
+
+// Utility function to map true to PR_SUCCESS and false to PR_FAILURE.
+static inline PRStatus ToPRStatus(bool result) {
+  return result ? PR_SUCCESS : PR_FAILURE;
+}
+
+}  // namespace pr_starboard
+
+typedef enum PRThreadPriority {
+  PR_PRIORITY_FIRST = 0,
+  PR_PRIORITY_LOW = 0,
+  PR_PRIORITY_NORMAL = 1,
+  PR_PRIORITY_HIGH = 2,
+  PR_PRIORITY_URGENT = 3,
+  PR_PRIORITY_LAST = 3
+} PRThreadPriority;
+
+typedef enum PRThreadScope {
+  PR_LOCAL_THREAD,
+  PR_GLOBAL_THREAD,
+  PR_GLOBAL_BOUND_THREAD
+} PRThreadScope;
+
+typedef enum PRThreadState {
+  PR_JOINABLE_THREAD,
+  PR_UNJOINABLE_THREAD
+} PRThreadState;
+
+typedef enum PRThreadType { PR_USER_THREAD, PR_SYSTEM_THREAD } PRThreadType;
+
+typedef SbThreadLocalKey PRTLSIndex;
+typedef uint32_t PRIntervalTime;
+
+typedef int32_t PRInt32;
+typedef uint32_t PRUint32;
+
+typedef int64_t PRInt64;
+typedef uint64_t PRUint64;
+
+typedef void(PR_CALLBACK* PRThreadPrivateDTOR)(void* priv);
+
+struct PRThread {
+  explicit PRThread(SbThread sb_thread) : sb_thread(sb_thread) {}
+  SbThread sb_thread;
+};
+
+typedef SbMutex PRLock;
+
+#define PR_INTERVAL_NO_WAIT 0UL
+#define PR_INTERVAL_NO_TIMEOUT 0xffffffffUL
+
+struct PRCondVar {
+  SbConditionVariable sb_condition_variable;
+  SbMutex* lock;
+};
+
+PRLock* PR_NewLock();
+
+static inline void PR_Lock(PRLock* lock) {
+  SbMutexAcquire(lock);
+}
+
+static inline void PR_Unlock(PRLock* lock) {
+  SbMutexRelease(lock);
+}
+
+void PR_DestroyLock(PRLock* lock);
+
+PRCondVar* PR_NewCondVar(PRLock* lock);
+
+void PR_DestroyCondVar(PRCondVar* cvar);
+
+PRStatus PR_WaitCondVar(PRCondVar* cvar, PRIntervalTime timeout);
+
+static inline PRStatus PR_NotifyCondVar(PRCondVar* cvar) {
+  return pr_starboard::ToPRStatus(
+      SbConditionVariableSignal(&cvar->sb_condition_variable));
+}
+
+static inline PRStatus PR_NotifyAllCondVar(PRCondVar* cvar) {
+  return pr_starboard::ToPRStatus(
+      SbConditionVariableBroadcast(&cvar->sb_condition_variable));
+}
+
+typedef void (*PRThreadEntryPoint)(void*);
+
+PRThread* PR_CreateThread(PRThreadType type,
+                          PRThreadEntryPoint start,
+                          void* arg,
+                          PRThreadPriority priority,
+                          PRThreadScope scope,
+                          PRThreadState state,
+                          PRUint32 stackSize);
+
+static inline PRStatus PR_JoinThread(PRThread* pr_thread) {
+  SB_DCHECK(pr_thread);
+  SB_DCHECK(SbThreadIsValid(pr_thread->sb_thread));
+  return pr_starboard::ToPRStatus(SbThreadJoin(pr_thread->sb_thread, NULL));
+}
+
+PRThread* PR_GetCurrentThread();
+
+void PR_DetachThread();
+
+PRStatus PR_NewThreadPrivateIndex(PRTLSIndex* newIndex,
+                                  PRThreadPrivateDTOR destructor);
+
+static inline PRStatus PR_SetThreadPrivate(PRTLSIndex index, void* priv) {
+  return pr_starboard::ToPRStatus(SbThreadSetLocalValue(index, priv));
+}
+
+static inline void* PR_GetThreadPrivate(PRTLSIndex index) {
+  return SbThreadGetLocalValue(index);
+}
+
+static inline void PR_SetCurrentThreadName(const char* name) {
+  SbThreadSetName(name);
+}
+
+static inline PRUint32 PR_vsnprintf(char* out,
+                                    PRUint32 outlen,
+                                    const char* fmt,
+                                    va_list ap) {
+  return static_cast<PRUint32>(SbStringFormat(out, outlen, fmt, ap));
+}
+
+PRUint32 PR_snprintf(char* out, PRUint32 outlen, const char* fmt, ...);
+
+PRIntervalTime PR_MillisecondsToInterval(PRUint32 milli);
+
+static inline PRIntervalTime PR_MicrosecondsToInterval(PRUint32 micro) {
+  return (micro + 999) / 1000;
+}
+
+PRUint32 PR_IntervalToMicroseconds(PRIntervalTime ticks);
+
+struct PRCallOnceType {};
+typedef PRStatus(PR_CALLBACK* PRCallOnceWithArgFN)(void* arg);
+
+PRStatus PR_CallOnceWithArg(PRCallOnceType* once,
+                            PRCallOnceWithArgFN func,
+                            void* arg);
+
+static inline PRUint32 PR_TicksPerSecond() {
+  return 1000;
+}
+
+#endif  // STARBOARD_CLIENT_PORTING_PR_STARBOARD_PR_STARBOARD_H_
diff --git a/src/starboard/client_porting/wrap_main/wrap_main.h b/src/starboard/client_porting/wrap_main/wrap_main.h
index e4879d3..4734772 100644
--- a/src/starboard/client_porting/wrap_main/wrap_main.h
+++ b/src/starboard/client_porting/wrap_main/wrap_main.h
@@ -50,6 +50,11 @@
 }  // namespace client_porting
 }  // namespace starboard
 
+#if defined(_WIN32)
+// Today there is no Starboard win32. Make sure those who create it know
+// the _CrtSet* functions below should be moved to starboard win32 main.
+#error For starboard win32, please move _CrtSet* to main
+#endif
 #define STARBOARD_WRAP_SIMPLE_MAIN(main_function)                \
   void SbEventHandle(const SbEvent* event) {                     \
     ::starboard::client_porting::wrap_main::SimpleEventHandler<  \
@@ -57,10 +62,26 @@
   }
 
 #else
+#if defined(_WIN32)
+#include <windows.h>
+
+// TODO this case should be removed when win32 is starboardized
+#define STARBOARD_WRAP_SIMPLE_MAIN(main_function)                             \
+  int main(int argc, char** argv) {                                           \
+    if (!IsDebuggerPresent()) {                                               \
+      _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); \
+      _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);  \
+      _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);   \
+      _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);                    \
+    }                                                                         \
+    return main_function(argc, argv);                                         \
+  }
+#else  // defined(_WIN32)
 #define STARBOARD_WRAP_SIMPLE_MAIN(main_function) \
   int main(int argc, char** argv) {               \
     return main_function(argc, argv);             \
   }
+#endif
 
 #endif  // STARBOARD
 #endif  // STARBOARD_CLIENT_PORTING_WRAP_MAIN_WRAP_MAIN_H_
diff --git a/src/starboard/condition_variable.h b/src/starboard/condition_variable.h
index 673b7d9..4c519ba 100644
--- a/src/starboard/condition_variable.h
+++ b/src/starboard/condition_variable.h
@@ -56,10 +56,6 @@
 // placing the newly created condition variable in |out_condition|.
 //
 // The return value indicates whether the condition variable could be created.
-//
-// TODO: It looks like WTF does not have the mutex available when creating
-// the condition variable, and pthreads doesn't appear to require the mutex on
-// condvar creation, so we should just remove the parameter.
 SB_EXPORT bool SbConditionVariableCreate(SbConditionVariable* out_condition,
                                          SbMutex* opt_mutex);
 
diff --git a/src/starboard/examples/window/main.cc b/src/starboard/examples/window/main.cc
index 381d428..bb5bc83 100644
--- a/src/starboard/examples/window/main.cc
+++ b/src/starboard/examples/window/main.cc
@@ -35,7 +35,7 @@
                     << ", window=" << data->window
                     << ", device_type=" << data->device_type
                     << ", device_id=" << data->device_id
-                    << ", key=" << data->key
+                    << ", key=0x" << std::hex << data->key
                     << ", character=" << data->character
                     << ", modifiers=0x" << std::hex << data->key_modifiers
                     << ", location=" << std::dec << data->key_location;
diff --git a/src/starboard/linux/x64directfb/sanitizer_options.cc b/src/starboard/linux/x64directfb/sanitizer_options.cc
new file mode 100644
index 0000000..e85d451
--- /dev/null
+++ b/src/starboard/linux/x64directfb/sanitizer_options.cc
@@ -0,0 +1,42 @@
+// Copyright 2016 Google Inc. 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.
+
+// Removes gallium leak warnings from x11 GL code, but defines it as a weak
+// symbol, so other code can override it if they want to.
+
+#if defined(ADDRESS_SANITIZER)
+
+// Functions returning default options are declared weak in the tools' runtime
+// libraries. To make the linker pick the strong replacements for those
+// functions from this module, we explicitly force its inclusion by passing
+// -Wl,-u_sanitizer_options_link_helper
+extern "C" void _sanitizer_options_link_helper() { }
+
+#define SANITIZER_HOOK_ATTRIBUTE          \
+  extern "C"                              \
+  __attribute__((no_sanitize_address))    \
+  __attribute__((no_sanitize_memory))     \
+  __attribute__((no_sanitize_thread))     \
+  __attribute__((visibility("default")))  \
+  __attribute__((weak))                   \
+  __attribute__((used))
+
+// Newline separated list of issues to suppress, see
+// http://clang.llvm.org/docs/AddressSanitizer.html#issue-suppression
+// http://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_suppressions.cc
+SANITIZER_HOOK_ATTRIBUTE const char* __lsan_default_suppressions() {
+  return "leak:*eglibc-2.19*\n";
+}
+
+#endif  // defined(ADDRESS_SANITIZER)
diff --git a/src/starboard/linux/x64directfb/starboard_platform.gypi b/src/starboard/linux/x64directfb/starboard_platform.gypi
index f5d40ad..d38e23c 100644
--- a/src/starboard/linux/x64directfb/starboard_platform.gypi
+++ b/src/starboard/linux/x64directfb/starboard_platform.gypi
@@ -17,6 +17,7 @@
   'variables': {
     'starboard_platform_sources': [
         '<(DEPTH)/starboard/linux/x64directfb/main.cc',
+        '<(DEPTH)/starboard/linux/x64directfb/sanitizer_options.cc',
         '<(DEPTH)/starboard/linux/x64directfb/system_get_property.cc',
         '<(DEPTH)/starboard/shared/directfb/application_directfb.cc',
         '<(DEPTH)/starboard/shared/directfb/blitter_blit_rect_to_rect.cc',
diff --git a/src/starboard/nplb/decode_target_create_test.cc b/src/starboard/nplb/decode_target_create_test.cc
index e8f3ea4..287dc21 100644
--- a/src/starboard/nplb/decode_target_create_test.cc
+++ b/src/starboard/nplb/decode_target_create_test.cc
@@ -44,7 +44,6 @@
 
   SbDecodeTarget target =
       SbDecodeTargetCreate(kSbDecodeTargetFormat1PlaneRGBA, &surface);
-  EXPECT_TRUE(SbDecodeTargetIsValid(target));
   if (SbDecodeTargetIsValid(target)) {
     SbBlitterSurface plane =
         SbDecodeTargetGetPlane(target, kSbDecodeTargetPlaneRGBA);
diff --git a/src/starboard/nplb/storage_helpers.h b/src/starboard/nplb/storage_helpers.h
index 56b4fc2..efc422e 100644
--- a/src/starboard/nplb/storage_helpers.h
+++ b/src/starboard/nplb/storage_helpers.h
@@ -27,12 +27,12 @@
 const int64_t kStorageSize2 = kStorageSize * 2 + kStorageOffset;
 
 // Deletes the storage for the current user.
-SB_C_INLINE void ClearStorageRecord() {
+static SB_C_INLINE void ClearStorageRecord() {
   SbStorageDeleteRecord(SbUserGetCurrent());
 }
 
 // Opens the storage record for the current user, validating that it is valid.
-SB_C_INLINE SbStorageRecord OpenStorageRecord() {
+static SB_C_INLINE SbStorageRecord OpenStorageRecord() {
   SbStorageRecord record = SbStorageOpenRecord(SbUserGetCurrent());
   EXPECT_TRUE(SbStorageIsValidRecord(record));
   return record;
@@ -40,7 +40,8 @@
 
 // Writes a standard pattern of |size| bytes into the given open storage
 // |record|.
-SB_C_INLINE void WriteStorageRecord(SbStorageRecord record, int64_t size) {
+static SB_C_INLINE void WriteStorageRecord(SbStorageRecord record,
+                                           int64_t size) {
   char* data = new char[size];
   for (int64_t i = 0; i < size; ++i) {
     data[i] = static_cast<char>(i + 2 % 0xFF);
@@ -52,7 +53,8 @@
 
 // Ensures that the storage record for the current user is initialized with the
 // standard pattern for exactly |length| bytes.
-SB_C_INLINE void InitializeStorageRecord(int64_t length) {
+
+static SB_C_INLINE void InitializeStorageRecord(int64_t length) {
   ClearStorageRecord();
   SbStorageRecord record = OpenStorageRecord();
   WriteStorageRecord(record, length);
@@ -62,7 +64,7 @@
 // Checks a buffer of |total| size for the expected pattern (written in
 // WriteStorageRecord) to start at |offset| and continue for |length|, and the
 // rest of the buffer, before and after, should be set to 0.
-SB_C_INLINE void CheckStorageBuffer(char* data,
+static SB_C_INLINE void CheckStorageBuffer(char* data,
                                     int64_t offset,
                                     int64_t length,
                                     int64_t total) {
@@ -83,7 +85,7 @@
 // |offset| and reporting the buffer size as |length|, checks that the number of
 // read bytes is |expected_length| and then checks the buffer for the expected
 // pattern written in WriteStorageRecord over the expected range of the buffer.
-SB_C_INLINE void ReadAndCheckStorage(SbStorageRecord record,
+static SB_C_INLINE void ReadAndCheckStorage(SbStorageRecord record,
                                      int64_t offset,
                                      int64_t expected_length,
                                      int64_t length,
diff --git a/src/starboard/player.h b/src/starboard/player.h
index 6fbc381..cbd1ff3 100644
--- a/src/starboard/player.h
+++ b/src/starboard/player.h
@@ -173,7 +173,7 @@
 #define kSbPlayerInvalid ((SbPlayer)NULL)
 
 // Returns whether the given player handle is valid.
-SB_C_INLINE bool SbPlayerIsValid(SbPlayer player) {
+static SB_C_INLINE bool SbPlayerIsValid(SbPlayer player) {
   return player != kSbPlayerInvalid;
 }
 
diff --git a/src/starboard/raspi/1/gyp_configuration.gypi b/src/starboard/raspi/1/gyp_configuration.gypi
index fbccc08..040ca1e 100644
--- a/src/starboard/raspi/1/gyp_configuration.gypi
+++ b/src/starboard/raspi/1/gyp_configuration.gypi
@@ -32,7 +32,8 @@
     # This should have a default value in cobalt/base.gypi. See the comment
     # there for acceptable values for this variable.
     'javascript_engine': 'mozjs',
-    'cobalt_enable_jit': 1,
+    'cobalt_enable_jit': 0,
+    'cobalt_minimum_frame_time_in_milliseconds': '33',
 
     # RasPi 1 is ARMv6
     'arm_version': 6,
diff --git a/src/starboard/raspi/1/starboard_platform.gyp b/src/starboard/raspi/1/starboard_platform.gyp
index fb203a6..c39d4e3 100644
--- a/src/starboard/raspi/1/starboard_platform.gyp
+++ b/src/starboard/raspi/1/starboard_platform.gyp
@@ -39,6 +39,8 @@
         '<(DEPTH)/starboard/raspi/shared/main.cc',
         '<(DEPTH)/starboard/raspi/shared/open_max/open_max_component.cc',
         '<(DEPTH)/starboard/raspi/shared/open_max/open_max_component.h',
+        '<(DEPTH)/starboard/raspi/shared/open_max/open_max_video_decode_component.cc',
+        '<(DEPTH)/starboard/raspi/shared/open_max/open_max_video_decode_component.h',
         '<(DEPTH)/starboard/raspi/shared/open_max/video_decoder.cc',
         '<(DEPTH)/starboard/raspi/shared/open_max/video_decoder.h',
         '<(DEPTH)/starboard/raspi/shared/thread_create_priority.cc',
diff --git a/src/starboard/raspi/shared/application_dispmanx.cc b/src/starboard/raspi/shared/application_dispmanx.cc
index fcaf43f..4f9dddf 100644
--- a/src/starboard/raspi/shared/application_dispmanx.cc
+++ b/src/starboard/raspi/shared/application_dispmanx.cc
@@ -51,9 +51,7 @@
   window_ = new SbWindowPrivate(*display_, options);
   input_ = DevInput::Create(window_);
 
-  // Create the dispmanx element to display video frames.
-  int result = 0;
-  uint32_t vc_image_ptr;
+  video_renderer_.reset(new DispmanxVideoRenderer(*display_, kVideoLayer));
 
   return window_;
 }
@@ -86,14 +84,11 @@
 }
 
 void ApplicationDispmanx::AcceptFrame(SbPlayer player,
-                                      const VideoFrame& frame,
+                                      const scoped_refptr<VideoFrame>& frame,
                                       int x,
                                       int y,
                                       int width,
                                       int height) {
-  if (!video_renderer_) {
-    video_renderer_.reset(new DispmanxVideoRenderer(*display_, kVideoLayer));
-  }
   video_renderer_->Update(frame);
 }
 
diff --git a/src/starboard/raspi/shared/application_dispmanx.h b/src/starboard/raspi/shared/application_dispmanx.h
index ba49ff5..d08c406 100644
--- a/src/starboard/raspi/shared/application_dispmanx.h
+++ b/src/starboard/raspi/shared/application_dispmanx.h
@@ -49,7 +49,7 @@
   void Initialize() SB_OVERRIDE;
   void Teardown() SB_OVERRIDE;
   void AcceptFrame(SbPlayer player,
-                   const VideoFrame& frame,
+                   const scoped_refptr<VideoFrame>& frame,
                    int x,
                    int y,
                    int width,
diff --git a/src/starboard/raspi/shared/dispmanx_util.cc b/src/starboard/raspi/shared/dispmanx_util.cc
index 88c7f52..f33a441 100644
--- a/src/starboard/raspi/shared/dispmanx_util.cc
+++ b/src/starboard/raspi/shared/dispmanx_util.cc
@@ -23,6 +23,8 @@
 
 namespace {
 
+const int kElementChangeAttributesFlagSrcRect = 1 << 3;
+
 class DispmanxAutoUpdate {
  public:
   DispmanxAutoUpdate() {
@@ -52,10 +54,61 @@
 
 }  // namespace
 
+DispmanxResource::DispmanxResource(VC_IMAGE_TYPE_T image_type,
+                                   uint32_t width,
+                                   uint32_t height,
+                                   uint32_t visible_width,
+                                   uint32_t visible_height)
+    : width_(width),
+      height_(height),
+      visible_width_(visible_width),
+      visible_height_(visible_height) {
+  static const uint32_t kMaxDimension = 1 << 16;
+
+  SB_DCHECK(width_ > 0 && width_ < kMaxDimension);
+  SB_DCHECK(height_ > 0 && height_ < kMaxDimension);
+  SB_DCHECK(visible_width_ > 0 && visible_width_ < kMaxDimension);
+  SB_DCHECK(visible_height > 0 && visible_height < kMaxDimension);
+  SB_DCHECK(width_ >= visible_width_);
+  SB_DCHECK(height_ >= visible_height);
+
+  uint32_t vc_image_ptr;
+
+  handle_ = vc_dispmanx_resource_create(
+      image_type, visible_width_ | (width_ << 16),
+      visible_height | (height_ << 16), &vc_image_ptr);
+  SB_DCHECK(handle_ != DISPMANX_NO_HANDLE);
+}
+
+void DispmanxYUV420Resource::WriteData(const void* data) {
+  SB_DCHECK(handle() != DISPMANX_NO_HANDLE);
+
+  DispmanxRect dst_rect(0, 0, width(), height() * 3 / 2);
+  int32_t result = vc_dispmanx_resource_write_data(
+      handle(), VC_IMAGE_YUV420, width(), const_cast<void*>(data), &dst_rect);
+  SB_DCHECK(result == 0);
+}
+
 void DispmanxYUV420Resource::ClearWithBlack() {
-  scoped_array<uint8_t> data(new uint8_t[width_ * height_ * 3 / 2]);
-  SbMemorySet(data.get(), width_ * height_, 0);
-  SbMemorySet(data.get() + width_ * height_, width_ * height_ / 2, 0x80);
+  scoped_array<uint8_t> data(new uint8_t[width() * height() * 3 / 2]);
+  SbMemorySet(data.get(), width() * height(), 0);
+  SbMemorySet(data.get() + width() * height(), width() * height() / 2, 0x80);
+  WriteData(data.get());
+}
+
+void DispmanxRGB565Resource::WriteData(const void* data) {
+  SB_DCHECK(handle() != DISPMANX_NO_HANDLE);
+
+  DispmanxRect dst_rect(0, 0, width(), height());
+  int32_t result =
+      vc_dispmanx_resource_write_data(handle(), VC_IMAGE_RGB565, width() * 2,
+                                      const_cast<void*>(data), &dst_rect);
+  SB_DCHECK(result == 0);
+}
+
+void DispmanxRGB565Resource::ClearWithBlack() {
+  scoped_array<uint8_t> data(new uint8_t[width() * height() * 2]);
+  SbMemorySet(data.get(), width() * height() * 2, 0);
   WriteData(data.get());
 }
 
@@ -78,26 +131,37 @@
   SB_DCHECK(result == 0) << " result=" << result;
 }
 
-void DispmanxVideoRenderer::Update(const VideoFrame& video_frame) {
-  if (video_frame.IsEndOfStream()) {
-    element_.reset();
-    resource_.reset();
+void DispmanxElement::ChangeSource(const DispmanxResource& new_src) {
+  DispmanxAutoUpdate update;
+  vc_dispmanx_element_change_source(update.handle(), handle_, new_src.handle());
+}
+
+DispmanxVideoRenderer::DispmanxVideoRenderer(const DispmanxDisplay& display,
+                                             int32_t layer)
+    : black_frame_(256, 256, 256, 256) {
+  black_frame_.ClearWithBlack();
+  element_.reset(new DispmanxElement(display, layer, DispmanxRect(),
+                                     black_frame_, DispmanxRect()));
+}
+
+void DispmanxVideoRenderer::Update(
+    const scoped_refptr<VideoFrame>& video_frame) {
+  SB_DCHECK(video_frame);
+
+  if (frame_ == video_frame) {
     return;
   }
-  if (!resource_ || resource_->width() != video_frame.width() ||
-      resource_->height() != video_frame.height()) {
-    element_.reset();
-    resource_.reset();
 
-    DispmanxRect src_rect(0, 0, video_frame.width() << 16,
-                          video_frame.height() << 16);
-    resource_.reset(
-        new DispmanxYUV420Resource(video_frame.width(), video_frame.height()));
-    element_.reset(new DispmanxElement(display_, layer_, DispmanxRect(),
-                                       *resource_, src_rect));
+  if (video_frame->IsEndOfStream()) {
+    element_->ChangeSource(black_frame_);
+    frame_ = video_frame;
+    return;
   }
 
-  resource_->WriteData(video_frame.GetPlane(0).data);
+  DispmanxYUV420Resource* resource =
+      reinterpret_cast<DispmanxYUV420Resource*>(video_frame->native_texture());
+  element_->ChangeSource(*resource);
+  frame_ = video_frame;
 }
 
 }  // namespace shared
diff --git a/src/starboard/raspi/shared/dispmanx_util.h b/src/starboard/raspi/shared/dispmanx_util.h
index c4b65f6..f051e86 100644
--- a/src/starboard/raspi/shared/dispmanx_util.h
+++ b/src/starboard/raspi/shared/dispmanx_util.h
@@ -69,38 +69,57 @@
   }
 
   DISPMANX_RESOURCE_HANDLE_T handle() const { return handle_; }
+  uint32_t visible_width() const { return visible_width_; }
+  uint32_t visible_height() const { return visible_height_; }
   uint32_t width() const { return width_; }
   uint32_t height() const { return height_; }
 
  protected:
-  DispmanxResource(VC_IMAGE_TYPE_T image_type, uint32_t width, uint32_t height)
-      : width_(width), height_(height) {
-    uint32_t vc_image_ptr;
+  DispmanxResource(VC_IMAGE_TYPE_T image_type,
+                   uint32_t width,
+                   uint32_t height,
+                   uint32_t visible_width,
+                   uint32_t visible_height);
 
-    handle_ =
-        vc_dispmanx_resource_create(image_type, width, height, &vc_image_ptr);
-    SB_DCHECK(handle_ != DISPMANX_NO_HANDLE);
-  }
-
+ private:
   DISPMANX_RESOURCE_HANDLE_T handle_;
   uint32_t width_;
   uint32_t height_;
+  uint32_t visible_width_;
+  uint32_t visible_height_;
 
   SB_DISALLOW_COPY_AND_ASSIGN(DispmanxResource);
 };
 
 class DispmanxYUV420Resource : public DispmanxResource {
  public:
-  DispmanxYUV420Resource(uint32_t width, uint32_t height)
-      : DispmanxResource(VC_IMAGE_YUV420, width, height) {}
+  DispmanxYUV420Resource(uint32_t width,
+                         uint32_t height,
+                         uint32_t visible_width,
+                         uint32_t visible_height)
+      : DispmanxResource(VC_IMAGE_YUV420,
+                         width,
+                         height,
+                         visible_width,
+                         visible_height) {}
 
-  void WriteData(const void* data) {
-    SB_DCHECK(handle_ != DISPMANX_NO_HANDLE);
-    DispmanxRect dst_rect(0, 0, width(), height() * 3 / 2);
-    int32_t result = vc_dispmanx_resource_write_data(
-        handle_, VC_IMAGE_YUV420, width(), const_cast<void*>(data), &dst_rect);
-    SB_DCHECK(result == 0);
-  }
+  void WriteData(const void* data);
+  void ClearWithBlack();
+};
+
+class DispmanxRGB565Resource : public DispmanxResource {
+ public:
+  DispmanxRGB565Resource(uint32_t width,
+                         uint32_t height,
+                         uint32_t visible_width,
+                         uint32_t visible_height)
+      : DispmanxResource(VC_IMAGE_RGB565,
+                         width,
+                         height,
+                         visible_width,
+                         visible_height) {}
+
+  void WriteData(const void* data);
   void ClearWithBlack();
 };
 
@@ -114,6 +133,7 @@
   ~DispmanxElement();
 
   DISPMANX_ELEMENT_HANDLE_T handle() const { return handle_; }
+  void ChangeSource(const DispmanxResource& new_src);
 
  private:
   DISPMANX_ELEMENT_HANDLE_T handle_;
@@ -124,16 +144,18 @@
 class DispmanxVideoRenderer {
  public:
   typedef starboard::shared::starboard::player::VideoFrame VideoFrame;
-  DispmanxVideoRenderer(const DispmanxDisplay& display, int32_t layer)
-      : display_(display), layer_(layer) {}
 
-  void Update(const VideoFrame& video_frame);
+  DispmanxVideoRenderer(const DispmanxDisplay& display, int32_t layer);
+
+  void Update(const scoped_refptr<VideoFrame>& video_frame);
 
  private:
-  const DispmanxDisplay& display_;
-  int32_t layer_;
-  scoped_ptr<DispmanxYUV420Resource> resource_;
   scoped_ptr<DispmanxElement> element_;
+  scoped_refptr<VideoFrame> frame_;
+
+  // Used to fill the background with black if no video is playing so that the
+  // console does not show through.
+  DispmanxRGB565Resource black_frame_;
 
   SB_DISALLOW_COPY_AND_ASSIGN(DispmanxVideoRenderer);
 };
diff --git a/src/starboard/raspi/shared/open_max/open_max_component.cc b/src/starboard/raspi/shared/open_max/open_max_component.cc
index eb05825..bb814f6c 100644
--- a/src/starboard/raspi/shared/open_max/open_max_component.cc
+++ b/src/starboard/raspi/shared/open_max/open_max_component.cc
@@ -47,15 +47,13 @@
 
 }  // namespace
 
-OpenMaxComponent::OpenMaxComponent(const char* name, size_t minimum_output_size)
+OpenMaxComponent::OpenMaxComponent(const char* name)
     : condition_variable_(mutex_),
-      minimum_output_size_(minimum_output_size),
       handle_(NULL),
       input_port_(kInvalidPort),
       output_port_(kInvalidPort),
       output_setting_changed_(false),
-      output_buffer_(NULL),
-      output_buffer_filled_(false) {
+      output_port_enabled_(false) {
   InitializeOpenMax();
 
   OMX_CALLBACKTYPE callbacks;
@@ -99,18 +97,20 @@
   SendCommandAndWaitForCompletion(OMX_CommandFlush, output_port_);
 
   SendCommand(OMX_CommandPortDisable, input_port_);
-  for (BufferHeaders::iterator iter = unused_buffers_.begin();
-       iter != unused_buffers_.end(); ++iter) {
-    OMX_ERRORTYPE error = OMX_FreeBuffer(handle_, input_port_, *iter);
+  for (size_t i = 0; i < input_buffers_.size(); ++i) {
+    OMX_ERRORTYPE error =
+        OMX_FreeBuffer(handle_, input_port_, input_buffers_[i]);
     SB_DCHECK(error == OMX_ErrorNone);
   }
   WaitForCommandCompletion();
 
   SendCommand(OMX_CommandPortDisable, output_port_);
-  if (output_buffer_) {
-    OMX_ERRORTYPE error = OMX_FreeBuffer(handle_, output_port_, output_buffer_);
+  for (size_t i = 0; i < output_buffers_.size(); ++i) {
+    OMX_ERRORTYPE error =
+        OMX_FreeBuffer(handle_, output_port_, output_buffers_[i]);
     SB_DCHECK(error == OMX_ErrorNone);
   }
+  output_buffers_.clear();
   WaitForCommandCompletion();
 
   SendCommandAndWaitForCompletion(OMX_CommandStateSet, OMX_StateLoaded);
@@ -162,45 +162,34 @@
   SB_DCHECK(error == OMX_ErrorNone);
 }
 
-bool OpenMaxComponent::ReadVideoFrame(VideoFrame* frame) {
+OMX_BUFFERHEADERTYPE* OpenMaxComponent::PeekNextOutputBuffer() {
   {
     ScopedLock scoped_lock(mutex_);
-    if (output_buffer_ && !output_buffer_filled_) {
-      return false;
-    }
+
     if (!output_setting_changed_) {
-      return false;
+      return NULL;
     }
   }
-  SB_DCHECK(output_setting_changed_);
-  if (!output_buffer_) {
-    GetOutputPortParam(&output_port_definition_);
-    SB_DCHECK(output_port_definition_.format.video.eColorFormat ==
-              OMX_COLOR_FormatYUV420PackedPlanar);
-    EnableOutputPortAndAllocateBuffer();
-    return false;
-  }
 
-  if (output_buffer_->nFlags & OMX_BUFFERFLAG_EOS) {
-    *frame = VideoFrame();
-    return true;
+  if (!output_port_enabled_) {
+    EnableOutputPortAndAllocateBuffer();
   }
-  SbMediaTime timestamp =
-      ((output_buffer_->nTimeStamp.nHighPart * 0x100000000ull) +
-       output_buffer_->nTimeStamp.nLowPart) *
-      kSbMediaTimeSecond / kSbTimeSecond;
-  int width = output_port_definition_.format.video.nFrameWidth;
-  int height = output_port_definition_.format.video.nSliceHeight;
-  int pitch = output_port_definition_.format.video.nStride;
-  *frame = VideoFrame::CreateYV12Frame(
-      width, height, pitch, timestamp, output_buffer_->pBuffer,
-      output_buffer_->pBuffer + pitch * height,
-      output_buffer_->pBuffer + pitch * height * 5 / 4);
-  output_buffer_filled_ = false;
-  output_buffer_->nFilledLen = 0;
-  OMX_ERRORTYPE error = OMX_FillThisBuffer(handle_, output_buffer_);
+
+  ScopedLock scoped_lock(mutex_);
+  return filled_output_buffers_.empty() ? NULL : filled_output_buffers_.front();
+}
+
+void OpenMaxComponent::DropNextOutputBuffer() {
+  OMX_BUFFERHEADERTYPE* buffer = NULL;
+  {
+    ScopedLock scoped_lock(mutex_);
+    SB_DCHECK(!filled_output_buffers_.empty());
+    buffer = filled_output_buffers_.front();
+    filled_output_buffers_.pop();
+  }
+  buffer->nFilledLen = 0;
+  OMX_ERRORTYPE error = OMX_FillThisBuffer(handle_, buffer);
   SB_DCHECK(error == OMX_ErrorNone);
-  return true;
 }
 
 void OpenMaxComponent::SendCommand(OMX_COMMANDTYPE command, int param) {
@@ -234,48 +223,68 @@
 }
 
 void OpenMaxComponent::EnableInputPortAndAllocateBuffers() {
-  SB_DCHECK(unused_buffers_.empty());
+  SB_DCHECK(input_buffers_.empty());
 
   OMXParamPortDefinition port_definition;
   GetInputPortParam(&port_definition);
+  if (OnEnableInputPort(&port_definition)) {
+    SetPortParam(port_definition);
+  }
 
   SendCommand(OMX_CommandPortEnable, input_port_);
 
-  unused_buffers_.resize(port_definition.nBufferCountActual);
-  for (int i = 0; i != port_definition.nBufferCountActual; ++i) {
-    OMX_ERRORTYPE error =
-        OMX_AllocateBuffer(handle_, &unused_buffers_[i], input_port_, NULL,
-                           port_definition.nBufferSize);
+  for (int i = 0; i < port_definition.nBufferCountActual; ++i) {
+    OMX_BUFFERHEADERTYPE* buffer;
+    OMX_ERRORTYPE error = OMX_AllocateBuffer(handle_, &buffer, input_port_,
+                                             NULL, port_definition.nBufferSize);
     SB_DCHECK(error == OMX_ErrorNone);
+    input_buffers_.push_back(buffer);
+    unused_input_buffers_.push(buffer);
   }
 
   WaitForCommandCompletion();
 }
 
 void OpenMaxComponent::EnableOutputPortAndAllocateBuffer() {
-  if (output_buffer_ != NULL) {
-    return;
+  SB_DCHECK(!output_port_enabled_);
+
+  GetOutputPortParam(&output_port_definition_);
+  if (OnEnableOutputPort(&output_port_definition_)) {
+    SetPortParam(output_port_definition_);
   }
 
   SendCommand(OMX_CommandPortEnable, output_port_);
 
-  OMX_ERRORTYPE error = OMX_AllocateBuffer(
-      handle_, &output_buffer_, output_port_, NULL,
-      std::max(output_port_definition_.nBufferSize, minimum_output_size_));
-  SB_DCHECK(error == OMX_ErrorNone);
+  output_buffers_.reserve(output_port_definition_.nBufferCountActual);
+  for (int i = 0; i < output_port_definition_.nBufferCountActual; ++i) {
+    OMX_BUFFERHEADERTYPE* buffer;
+    OMX_ERRORTYPE error =
+        OMX_AllocateBuffer(handle_, &buffer, output_port_, NULL,
+                           output_port_definition_.nBufferSize);
+    SB_DCHECK(error == OMX_ErrorNone);
+    output_buffers_.push_back(buffer);
+  }
+
   WaitForCommandCompletion();
 
-  error = OMX_FillThisBuffer(handle_, output_buffer_);
-  SB_DCHECK(error == OMX_ErrorNone);
+  output_port_enabled_ = true;
+
+  for (size_t i = 0; i < output_buffers_.size(); ++i) {
+    output_buffers_[i]->nFilledLen = 0;
+    OMX_ERRORTYPE error = OMX_FillThisBuffer(handle_, output_buffers_[i]);
+    SB_DCHECK(error == OMX_ErrorNone);
+  }
 }
 
 OMX_BUFFERHEADERTYPE* OpenMaxComponent::GetUnusedInputBuffer() {
   for (;;) {
-    ScopedLock scoped_lock(mutex_);
-    if (!unused_buffers_.empty()) {
-      OMX_BUFFERHEADERTYPE* buffer_header = unused_buffers_.back();
-      unused_buffers_.pop_back();
-      return buffer_header;
+    {
+      ScopedLock scoped_lock(mutex_);
+      if (!unused_input_buffers_.empty()) {
+        OMX_BUFFERHEADERTYPE* buffer_header = unused_input_buffers_.front();
+        unused_input_buffers_.pop();
+        return buffer_header;
+      }
     }
     SbThreadSleep(kSbTimeMillisecond);
   }
@@ -312,13 +321,12 @@
 OMX_ERRORTYPE OpenMaxComponent::OnEmptyBufferDone(
     OMX_BUFFERHEADERTYPE* buffer) {
   ScopedLock scoped_lock(mutex_);
-  unused_buffers_.push_back(buffer);
+  unused_input_buffers_.push(buffer);
 }
 
 void OpenMaxComponent::OnFillBufferDone(OMX_BUFFERHEADERTYPE* buffer) {
   ScopedLock scoped_lock(mutex_);
-  SB_DCHECK(!output_buffer_filled_);
-  output_buffer_filled_ = true;
+  filled_output_buffers_.push(buffer);
 }
 
 // static
diff --git a/src/starboard/raspi/shared/open_max/open_max_component.h b/src/starboard/raspi/shared/open_max/open_max_component.h
index 9085c1b..d9b5295 100644
--- a/src/starboard/raspi/shared/open_max/open_max_component.h
+++ b/src/starboard/raspi/shared/open_max/open_max_component.h
@@ -22,13 +22,14 @@
 #include <interface/vcos/vcos.h>
 #include <interface/vcos/vcos_logging.h>
 #include <interface/vmcs_host/vchost.h>
+
+#include <queue>
 #include <vector>
 
 #include "starboard/condition_variable.h"
 #include "starboard/log.h"
 #include "starboard/mutex.h"
 #include "starboard/shared/internal_only.h"
-#include "starboard/shared/starboard/player/video_frame_internal.h"
 #include "starboard/time.h"
 
 namespace starboard {
@@ -53,10 +54,8 @@
 
 class OpenMaxComponent {
  public:
-  typedef starboard::shared::starboard::player::VideoFrame VideoFrame;
-
-  explicit OpenMaxComponent(const char* name, size_t minimum_output_size = 0);
-  ~OpenMaxComponent();
+  explicit OpenMaxComponent(const char* name);
+  virtual ~OpenMaxComponent();
 
   void Start();
   void Flush();
@@ -64,7 +63,8 @@
   void WriteData(const void* data, size_t size, SbTime timestamp);
   void WriteEOS();
 
-  bool ReadVideoFrame(VideoFrame* frame);
+  OMX_BUFFERHEADERTYPE* PeekNextOutputBuffer();
+  void DropNextOutputBuffer();
 
   template <typename ParamType>
   void GetInputPortParam(ParamType* param) const {
@@ -94,8 +94,6 @@
   }
 
  private:
-  typedef std::vector<OMX_BUFFERHEADERTYPE*> BufferHeaders;
-
   struct EventDescription {
     OMX_EVENTTYPE event;
     OMX_U32 data1;
@@ -105,6 +103,13 @@
 
   typedef std::vector<EventDescription> EventDescriptions;
 
+  virtual bool OnEnableInputPort(OMXParamPortDefinition* port_definition) {
+    return false;
+  }
+  virtual bool OnEnableOutputPort(OMXParamPortDefinition* port_definition) {
+    return false;
+  }
+
   void SendCommand(OMX_COMMANDTYPE command, int param);
   void WaitForCommandCompletion();
   void SendCommandAndWaitForCompletion(OMX_COMMANDTYPE command, int param);
@@ -134,16 +139,18 @@
 
   Mutex mutex_;
   ConditionVariable condition_variable_;
-  const size_t minimum_output_size_;
   OMX_HANDLETYPE handle_;
   int input_port_;
   int output_port_;
   bool output_setting_changed_;
   EventDescriptions event_descriptions_;
-  BufferHeaders unused_buffers_;
-  OMX_BUFFERHEADERTYPE* output_buffer_;
+  std::vector<OMX_BUFFERHEADERTYPE*> input_buffers_;
+  std::queue<OMX_BUFFERHEADERTYPE*> unused_input_buffers_;
+  std::vector<OMX_BUFFERHEADERTYPE*> output_buffers_;
+  std::queue<OMX_BUFFERHEADERTYPE*> filled_output_buffers_;
+
   OMXParamPortDefinition output_port_definition_;
-  bool output_buffer_filled_;
+  bool output_port_enabled_;
 };
 
 }  // namespace open_max
diff --git a/src/starboard/raspi/shared/open_max/open_max_video_decode_component.cc b/src/starboard/raspi/shared/open_max/open_max_video_decode_component.cc
new file mode 100644
index 0000000..0520c36
--- /dev/null
+++ b/src/starboard/raspi/shared/open_max/open_max_video_decode_component.cc
@@ -0,0 +1,165 @@
+// Copyright 2016 Google Inc. 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/raspi/shared/open_max/open_max_video_decode_component.h"
+
+#include <algorithm>
+
+#include "starboard/configuration.h"
+
+namespace starboard {
+namespace raspi {
+namespace shared {
+namespace open_max {
+
+namespace {
+
+const char kVideoDecodeComponentName[] = "OMX.broadcom.video_decode";
+const size_t kResourcePoolSize = 12;
+const size_t kOMXOutputBufferCount = 4;
+const int kMaxFrameWidth = 1920;
+const int kMaxFrameHeight = 1088;
+const size_t kMaxVideoFrameSize = kMaxFrameWidth * kMaxFrameHeight * 3 / 2;
+
+}  // namespace
+
+typedef OpenMaxVideoDecodeComponent::VideoFrame VideoFrame;
+
+VideoFrameResourcePool::VideoFrameResourcePool(size_t max_number_of_resources)
+    : max_number_of_resources_(max_number_of_resources),
+      number_of_resources_(0),
+      last_frame_height_(0) {}
+
+VideoFrameResourcePool::~VideoFrameResourcePool() {
+  for (ResourceMap::iterator iter = resource_map_.begin();
+       iter != resource_map_.end(); ++iter) {
+    while (!iter->second.empty()) {
+      delete iter->second.front();
+      iter->second.pop();
+      --number_of_resources_;
+    }
+  }
+  SB_DCHECK(number_of_resources_ == 0) << number_of_resources_;
+}
+
+DispmanxYUV420Resource* VideoFrameResourcePool::Alloc(int width,
+                                                      int height,
+                                                      int visible_width,
+                                                      int visible_height) {
+  ScopedLock scoped_lock(mutex_);
+
+  last_frame_height_ = height;
+
+  ResourceMap::iterator iter = resource_map_.find(height);
+  if (iter != resource_map_.end() && !iter->second.empty()) {
+    DispmanxYUV420Resource* resource = iter->second.front();
+    iter->second.pop();
+    return resource;
+  }
+
+  if (number_of_resources_ >= max_number_of_resources_) {
+    return NULL;
+  }
+
+  ++number_of_resources_;
+  return new DispmanxYUV420Resource(width, height, visible_width,
+                                    visible_height);
+}
+
+void VideoFrameResourcePool::Free(DispmanxYUV420Resource* resource) {
+  ScopedLock scoped_lock(mutex_);
+  if (resource->height() != last_frame_height_) {
+    // The video has adapted, free the resource as it won't be reused any soon.
+    delete resource;
+    --number_of_resources_;
+    return;
+  }
+  resource_map_[resource->height()].push(resource);
+}
+
+// static
+void VideoFrameResourcePool::DisposeDispmanxYUV420Resource(
+    void* context,
+    void* dispmanx_resource) {
+  SB_DCHECK(context != NULL);
+  SB_DCHECK(dispmanx_resource != NULL);
+  VideoFrameResourcePool* pool =
+      reinterpret_cast<VideoFrameResourcePool*>(context);
+  pool->Free(reinterpret_cast<DispmanxYUV420Resource*>(dispmanx_resource));
+  pool->Release();
+}
+
+OpenMaxVideoDecodeComponent::OpenMaxVideoDecodeComponent()
+    : OpenMaxComponent(kVideoDecodeComponentName),
+      resource_pool_(new VideoFrameResourcePool(kResourcePoolSize)) {}
+
+scoped_refptr<VideoFrame> OpenMaxVideoDecodeComponent::ReadVideoFrame() {
+  if (OMX_BUFFERHEADERTYPE* buffer = PeekNextOutputBuffer()) {
+    if (scoped_refptr<VideoFrame> frame = CreateVideoFrame(buffer)) {
+      DropNextOutputBuffer();
+      return frame;
+    }
+  }
+  return NULL;
+}
+
+scoped_refptr<VideoFrame> OpenMaxVideoDecodeComponent::CreateVideoFrame(
+    OMX_BUFFERHEADERTYPE* buffer) {
+  scoped_refptr<VideoFrame> frame;
+  if (buffer->nFlags & OMX_BUFFERFLAG_EOS) {
+    frame = VideoFrame::CreateEOSFrame();
+  } else {
+    OMX_VIDEO_PORTDEFINITIONTYPE& video_definition =
+        output_port_definition_.format.video;
+    DispmanxYUV420Resource* resource = resource_pool_->Alloc(
+        video_definition.nStride, video_definition.nSliceHeight,
+        video_definition.nFrameWidth, video_definition.nFrameHeight);
+    if (!resource) {
+      return NULL;
+    }
+
+    resource->WriteData(buffer->pBuffer);
+
+    SbMediaTime timestamp = ((buffer->nTimeStamp.nHighPart * 0x100000000ull) +
+                             buffer->nTimeStamp.nLowPart) *
+                            kSbMediaTimeSecond / kSbTimeSecond;
+
+    resource_pool_->AddRef();
+    frame = new VideoFrame(
+        video_definition.nFrameWidth, video_definition.nFrameHeight, timestamp,
+        resource, resource_pool_,
+        &VideoFrameResourcePool::DisposeDispmanxYUV420Resource);
+  }
+  return frame;
+}
+
+bool OpenMaxVideoDecodeComponent::OnEnableOutputPort(
+    OMXParamPortDefinition* port_definition) {
+  SB_DCHECK(port_definition);
+
+  output_port_definition_ = *port_definition;
+  SB_DCHECK(port_definition->format.video.eColorFormat ==
+            OMX_COLOR_FormatYUV420PackedPlanar);
+  port_definition->format.video.eColorFormat =
+      OMX_COLOR_FormatYUV420PackedPlanar;
+  port_definition->nBufferCountActual = kOMXOutputBufferCount;
+  port_definition->nBufferSize =
+      std::max(port_definition->nBufferSize, kMaxVideoFrameSize);
+  return true;
+}
+
+}  // namespace open_max
+}  // namespace shared
+}  // namespace raspi
+}  // namespace starboard
diff --git a/src/starboard/raspi/shared/open_max/open_max_video_decode_component.h b/src/starboard/raspi/shared/open_max/open_max_video_decode_component.h
new file mode 100644
index 0000000..94b9cda
--- /dev/null
+++ b/src/starboard/raspi/shared/open_max/open_max_video_decode_component.h
@@ -0,0 +1,84 @@
+// Copyright 2016 Google Inc. 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_RASPI_SHARED_OPEN_MAX_OPEN_MAX_VIDEO_DECODE_COMPONENT_H_
+#define STARBOARD_RASPI_SHARED_OPEN_MAX_OPEN_MAX_VIDEO_DECODE_COMPONENT_H_
+
+#include <map>
+#include <queue>
+
+#include "starboard/common/ref_counted.h"
+#include "starboard/raspi/shared/dispmanx_util.h"
+#include "starboard/raspi/shared/open_max/open_max_component.h"
+
+namespace starboard {
+namespace raspi {
+namespace shared {
+namespace open_max {
+
+class VideoFrameResourcePool
+    : public RefCountedThreadSafe<VideoFrameResourcePool> {
+ public:
+  explicit VideoFrameResourcePool(size_t max_number_of_resources);
+  ~VideoFrameResourcePool();
+
+  DispmanxYUV420Resource* Alloc(int width,
+                                int height,
+                                int visible_width,
+                                int visible_height);
+  void Free(DispmanxYUV420Resource* resource);
+
+  static void DisposeDispmanxYUV420Resource(void* context,
+                                            void* dispmanx_resource);
+
+ private:
+  typedef std::queue<DispmanxYUV420Resource*> ResourceQueue;
+  // Map frame height to resource handles.
+  typedef std::map<int, ResourceQueue> ResourceMap;
+
+  const size_t max_number_of_resources_;
+
+  Mutex mutex_;
+  size_t number_of_resources_;
+  int last_frame_height_;
+  ResourceMap resource_map_;
+};
+
+// Encapsulate a "OMX.broadcom.video_decode" component.  Note that member
+// functions of this class is expected to be called from ANY threads as this
+// class works with the VideoDecoder filter, the OpenMAX component, and also
+// manages the disposition of Dispmanx resource.
+class OpenMaxVideoDecodeComponent : public OpenMaxComponent {
+ public:
+  typedef starboard::shared::starboard::player::VideoFrame VideoFrame;
+
+  OpenMaxVideoDecodeComponent();
+
+  scoped_refptr<VideoFrame> ReadVideoFrame();
+
+ private:
+  scoped_refptr<VideoFrame> CreateVideoFrame(OMX_BUFFERHEADERTYPE* buffer);
+
+  bool OnEnableOutputPort(OMXParamPortDefinition* port_definition) SB_OVERRIDE;
+
+  scoped_refptr<VideoFrameResourcePool> resource_pool_;
+  OMXParamPortDefinition output_port_definition_;
+};
+
+}  // namespace open_max
+}  // namespace shared
+}  // namespace raspi
+}  // namespace starboard
+
+#endif  // STARBOARD_RASPI_SHARED_OPEN_MAX_OPEN_MAX_VIDEO_DECODE_COMPONENT_H_
diff --git a/src/starboard/raspi/shared/open_max/video_decoder.cc b/src/starboard/raspi/shared/open_max/video_decoder.cc
index 702a9f8..a238db7 100644
--- a/src/starboard/raspi/shared/open_max/video_decoder.cc
+++ b/src/starboard/raspi/shared/open_max/video_decoder.cc
@@ -23,17 +23,8 @@
 
 using starboard::shared::starboard::player::VideoFrame;
 
-namespace {
-
-const char kVideoDecodeComponentName[] = "OMX.broadcom.video_decode";
-const size_t kMaxVideoFrameSize = 1920 * 1088 * 3 / 2;
-
-}  // namespace
-
 VideoDecoder::VideoDecoder(SbMediaVideoCodec video_codec)
-    : component_(kVideoDecodeComponentName, kMaxVideoFrameSize),
-      host_(NULL),
-      stream_ended_(false) {
+    : host_(NULL), stream_ended_(false) {
   SB_DCHECK(video_codec == kSbMediaVideoCodecH264);
 
   OMXVideoParamPortFormat port_format;
@@ -61,11 +52,11 @@
   }
   component_.WriteData(input_buffer.data(), input_buffer.size(),
                        input_buffer.pts() * kSbTimeSecond / kSbMediaTimeSecond);
-
-  VideoFrame frame;
-  if (component_.ReadVideoFrame(&frame)) {
-    host_->OnDecoderStatusUpdate(kNeedMoreInput, &frame);
+  if (scoped_refptr<VideoFrame> frame = component_.ReadVideoFrame()) {
+    host_->OnDecoderStatusUpdate(kNeedMoreInput, frame);
   } else {
+    // Call the callback with NULL frame to ensure that the host know that more
+    // data is expected.
     host_->OnDecoderStatusUpdate(kNeedMoreInput, NULL);
   }
 }
diff --git a/src/starboard/raspi/shared/open_max/video_decoder.h b/src/starboard/raspi/shared/open_max/video_decoder.h
index 92850da..de684af 100644
--- a/src/starboard/raspi/shared/open_max/video_decoder.h
+++ b/src/starboard/raspi/shared/open_max/video_decoder.h
@@ -16,7 +16,7 @@
 #define STARBOARD_RASPI_SHARED_OPEN_MAX_VIDEO_DECODER_H_
 
 #include "starboard/media.h"
-#include "starboard/raspi/shared/open_max/open_max_component.h"
+#include "starboard/raspi/shared/open_max/open_max_video_decode_component.h"
 #include "starboard/shared/internal_only.h"
 #include "starboard/shared/starboard/player/filter/video_decoder_internal.h"
 
@@ -39,7 +39,7 @@
   void Reset() SB_OVERRIDE;
 
  private:
-  OpenMaxComponent component_;
+  OpenMaxVideoDecodeComponent component_;
 
   // These variables will be initialized inside ctor or SetHost() and will not
   // be changed during the life time of this class.
diff --git a/src/starboard/shared/directfb/blitter_destroy_swap_chain.cc b/src/starboard/shared/directfb/blitter_destroy_swap_chain.cc
index ba9d317..2f9505b 100644
--- a/src/starboard/shared/directfb/blitter_destroy_swap_chain.cc
+++ b/src/starboard/shared/directfb/blitter_destroy_swap_chain.cc
@@ -26,5 +26,7 @@
 
   swap_chain->render_target.surface->Release(swap_chain->render_target.surface);
 
+  delete swap_chain;
+
   return true;
 }
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
index 7b9efed..2e05ee8 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
@@ -197,8 +197,7 @@
         packet.pts = 0;
       } while (DecodePacket(&packet));
 
-      VideoFrame frame = VideoFrame::CreateEOSFrame();
-      host_->OnDecoderStatusUpdate(kBufferFull, &frame);
+      host_->OnDecoderStatusUpdate(kBufferFull, VideoFrame::CreateEOSFrame());
     }
   }
 }
@@ -223,11 +222,11 @@
 
   int pitch = AlignUp(av_frame_->width, kAlignment * 2);
 
-  VideoFrame frame = VideoFrame::CreateYV12Frame(
+  scoped_refptr<VideoFrame> frame = VideoFrame::CreateYV12Frame(
       av_frame_->width, av_frame_->height, pitch,
       codec_context_->reordered_opaque, av_frame_->data[0], av_frame_->data[1],
       av_frame_->data[2]);
-  host_->OnDecoderStatusUpdate(kBufferFull, &frame);
+  host_->OnDecoderStatusUpdate(kBufferFull, frame);
   return true;
 }
 
diff --git a/src/starboard/shared/posix/socket_receive_from.cc b/src/starboard/shared/posix/socket_receive_from.cc
index c4819b6..ca0cb04 100644
--- a/src/starboard/shared/posix/socket_receive_from.cc
+++ b/src/starboard/shared/posix/socket_receive_from.cc
@@ -27,11 +27,7 @@
                         char* out_data,
                         int data_size,
                         SbSocketAddress* out_source) {
-#if defined(MSG_NOSIGNAL)
-  const int kRecvFlags = MSG_NOSIGNAL;
-#else
   const int kRecvFlags = 0;
-#endif
 
   if (!SbSocketIsValid(socket)) {
     errno = EBADF;
diff --git a/src/starboard/shared/signal/crash_signals.cc b/src/starboard/shared/signal/crash_signals.cc
index 0d74011..78b3ab2 100644
--- a/src/starboard/shared/signal/crash_signals.cc
+++ b/src/starboard/shared/signal/crash_signals.cc
@@ -32,7 +32,7 @@
 };
 
 const int kStopSignalsToTrap[] = {
-    SIGTERM, SIGINT, SIGHUP,
+    SIGHUP,
 };
 
 void Crash(int signal_id) {
diff --git a/src/starboard/shared/signal/crash_signals_sigaction.cc b/src/starboard/shared/signal/crash_signals_sigaction.cc
index 5273ab1..da318a8 100644
--- a/src/starboard/shared/signal/crash_signals_sigaction.cc
+++ b/src/starboard/shared/signal/crash_signals_sigaction.cc
@@ -32,7 +32,7 @@
 };
 
 const int kStopSignalsToTrap[] = {
-    SIGTERM, SIGINT, SIGHUP,
+    SIGHUP,
 };
 
 void SetSignalHandler(int signal_id, SignalHandlerFunction handler) {
diff --git a/src/starboard/shared/signal/suspend_signals.cc b/src/starboard/shared/signal/suspend_signals.cc
index 6bb42d8..4048a3b 100644
--- a/src/starboard/shared/signal/suspend_signals.cc
+++ b/src/starboard/shared/signal/suspend_signals.cc
@@ -15,6 +15,7 @@
 #include "starboard/shared/signal/suspend_signals.h"
 
 #include <signal.h>
+#include <sys/socket.h>
 
 #include "starboard/configuration.h"
 #include "starboard/log.h"
@@ -71,19 +72,34 @@
 
 }  // namespace
 
+#if !defined(MSG_NOSIGNAL) && defined(SO_NOSIGPIPE)
+// See "#if !defined(MSG_NOSIGNAL)" below.
+// OS X, which we do not build for today, has another mechanism which
+// should be used.
+#error On this platform, please use SO_NOSIGPIPE and leave the SIGPIPE \
+       handler at default.
+#endif
+
 void InstallSuspendSignalHandlers() {
   SetSignalHandler(SIGTSTP, &Suspend);
   UnblockSignal(SIGTSTP);
   SetSignalHandler(SIGCONT, &Resume);
 
-  // We might receive SIGPIPE after resuming. We should not terminate.
+#if !defined(MSG_NOSIGNAL)
+  // By default in POSIX, sending to a closed socket causes a SIGPIPE
+  // If we cannot disable that behavior, we must ignore SIGPIPE.
+  // Ignoring SIGPIPE means cases that use pipes to redirect the stdio
+  // log messages may behave in surprising ways, so it's not desirable.
   SetSignalHandler(SIGPIPE, &Ignore);
+#endif
 }
 
 void UninstallSuspendSignalHandlers() {
   SetSignalHandler(SIGCONT, SIG_DFL);
   SetSignalHandler(SIGTSTP, SIG_DFL);
+#if !defined(MSG_NOSIGNAL)
   SetSignalHandler(SIGPIPE, SIG_DFL);
+#endif
 }
 
 }  // namespace signal
diff --git a/src/starboard/shared/starboard/application.cc b/src/starboard/shared/starboard/application.cc
index 96efbdb..4f2e850 100644
--- a/src/starboard/shared/starboard/application.cc
+++ b/src/starboard/shared/starboard/application.cc
@@ -130,7 +130,7 @@
 
 #if SB_HAS(PLAYER) && SB_IS(PLAYER_PUNCHED_OUT)
 void Application::HandleFrame(SbPlayer player,
-                              const VideoFrame& frame,
+                              const scoped_refptr<VideoFrame>& frame,
                               int x,
                               int y,
                               int width,
diff --git a/src/starboard/shared/starboard/application.h b/src/starboard/shared/starboard/application.h
index f8609ce..4387bed 100644
--- a/src/starboard/shared/starboard/application.h
+++ b/src/starboard/shared/starboard/application.h
@@ -202,7 +202,7 @@
   // used when the application needs to composite video frames with punch-out
   // video manually (should be rare). Will be called from an external thread.
   void HandleFrame(SbPlayer player,
-                   const VideoFrame& frame,
+                   const scoped_refptr<VideoFrame>& frame,
                    int x,
                    int y,
                    int width,
@@ -224,7 +224,7 @@
   // Subclasses may override this method to accept video frames from the media
   // system. Will be called from an external thread.
   virtual void AcceptFrame(SbPlayer player,
-                           const VideoFrame& frame,
+                           const scoped_refptr<VideoFrame>& frame,
                            int x,
                            int y,
                            int width,
diff --git a/src/starboard/shared/starboard/blitter_blit_rect_to_rect_tiled.cc b/src/starboard/shared/starboard/blitter_blit_rect_to_rect_tiled.cc
index 3317806..8648663 100644
--- a/src/starboard/shared/starboard/blitter_blit_rect_to_rect_tiled.cc
+++ b/src/starboard/shared/starboard/blitter_blit_rect_to_rect_tiled.cc
@@ -248,9 +248,11 @@
     }
   }
 
-  return SbBlitterBlitRectsToRects(context, source_surface, src_rects,
-                                   dst_rects, num_tiles);
+  bool result = SbBlitterBlitRectsToRects(context, source_surface, src_rects,
+                                          dst_rects, num_tiles);
 
   delete[] src_rects;
   delete[] dst_rects;
+
+  return result;
 }
diff --git a/src/starboard/shared/starboard/file_storage/storage_internal.h b/src/starboard/shared/starboard/file_storage/storage_internal.h
index ea322b8..6bb3362 100644
--- a/src/starboard/shared/starboard/file_storage/storage_internal.h
+++ b/src/starboard/shared/starboard/file_storage/storage_internal.h
@@ -33,9 +33,9 @@
 namespace shared {
 namespace starboard {
 // Gets the path to the storage file for the given user.
-SB_C_INLINE bool GetUserStorageFilePath(SbUser user,
-                                        char* out_path,
-                                        int path_size) {
+static SB_C_INLINE bool GetUserStorageFilePath(SbUser user,
+                                               char* out_path,
+                                               int path_size) {
   bool success = SbUserGetProperty(user, kSbUserPropertyHomeDirectory, out_path,
                                    path_size);
   if (!success) {
diff --git a/src/starboard/shared/starboard/localized_strings.cc b/src/starboard/shared/starboard/localized_strings.cc
index 2639c53..0f802e6 100644
--- a/src/starboard/shared/starboard/localized_strings.cc
+++ b/src/starboard/shared/starboard/localized_strings.cc
@@ -116,7 +116,7 @@
     return false;
   }
   SB_DCHECK(file_contents.length() > 0);
-  SB_DCHECK(file_contents.back() == '\n');
+  SB_DCHECK(file_contents[file_contents.length() - 1] == '\n');
 
   // Each line of the file corresponds to one message (key/value).
   size_t pos = 0;
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 54477cf..b73cbb2 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
@@ -210,7 +210,7 @@
       (*player_worker_.*update_player_state_cb_)(kSbPlayerStateEndOfStream);
     }
 
-    const VideoFrame& frame =
+    scoped_refptr<VideoFrame> frame =
         video_renderer_->GetCurrentFrame(audio_renderer_->GetCurrentTime());
 
 #if SB_IS(PLAYER_PUNCHED_OUT)
@@ -230,8 +230,8 @@
 
 #if SB_IS(PLAYER_PUNCHED_OUT)
   // Clear the video frame as we terminate.
-  shared::starboard::Application::Get()->HandleFrame(player_, VideoFrame(), 0,
-                                                     0, 0, 0);
+  shared::starboard::Application::Get()->HandleFrame(
+      player_, VideoFrame::CreateEOSFrame(), 0, 0, 0, 0);
 #endif  // SB_IS(PLAYER_PUNCHED_OUT)
 }
 
diff --git a/src/starboard/shared/starboard/player/filter/video_decoder_internal.h b/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
index fd32c9f..e55c685 100644
--- a/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
@@ -37,7 +37,9 @@
     // user should only call WriteInputFrame() when |status| is kNeedMoreInput
     // or when the instance is just created.  Also note that calling Reset() or
     // dtor from this callback will result in deadlock.
-    virtual void OnDecoderStatusUpdate(Status status, VideoFrame* frame) = 0;
+    virtual void OnDecoderStatusUpdate(
+        Status status,
+        const scoped_refptr<VideoFrame>& frame) = 0;
 
    protected:
     ~Host() {}
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc b/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc
index 65ee800..35b6bf0 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_internal.cc
@@ -79,7 +79,8 @@
   frames_.clear();
 }
 
-const VideoFrame& VideoRenderer::GetCurrentFrame(SbMediaTime media_time) {
+scoped_refptr<VideoFrame> VideoRenderer::GetCurrentFrame(
+    SbMediaTime media_time) {
   SB_DCHECK(thread_checker_.CalledOnValidThread());
 
   if (frames_.empty()) {
@@ -87,7 +88,7 @@
   }
   // Remove any frames with timestamps earlier than |media_time|, but always
   // keep at least one of the frames.
-  while (frames_.size() > 1 && frames_.front().pts() < media_time) {
+  while (frames_.size() > 1 && frames_.front()->pts() < media_time) {
     frames_.pop_front();
   }
 
@@ -101,6 +102,7 @@
 
 bool VideoRenderer::CanAcceptMoreData() const {
   SB_DCHECK(thread_checker_.CalledOnValidThread());
+  ScopedLock lock(mutex_);
   return frames_.size() < kMaxCachedFrames && !end_of_stream_written_ &&
          need_more_input_;
 }
@@ -110,8 +112,9 @@
   return seeking_;
 }
 
-void VideoRenderer::OnDecoderStatusUpdate(VideoDecoder::Status status,
-                                          VideoFrame* frame) {
+void VideoRenderer::OnDecoderStatusUpdate(
+    VideoDecoder::Status status,
+    const scoped_refptr<VideoFrame>& frame) {
   ScopedLock lock(mutex_);
 
   if (frame) {
@@ -124,7 +127,7 @@
       }
     }
     if (!frame_too_early) {
-      frames_.push_back(*frame);
+      frames_.push_back(frame);
     }
 
     if (seeking_ && frames_.size() >= kPrerollFrames) {
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_internal.h b/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
index 8450e59..6cc4cad 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
@@ -44,7 +44,7 @@
 
   void Seek(SbMediaTime seek_to_pts);
 
-  const VideoFrame& GetCurrentFrame(SbMediaTime media_time);
+  scoped_refptr<VideoFrame> GetCurrentFrame(SbMediaTime media_time);
 
   bool IsEndOfStreamWritten() const { return end_of_stream_written_; }
   bool IsEndOfStreamPlayed() const;
@@ -52,7 +52,7 @@
   bool IsSeekingInProgress() const;
 
  private:
-  typedef std::list<VideoFrame> Frames;
+  typedef std::list<scoped_refptr<VideoFrame> > Frames;
 
   // Preroll considered finished after either kPrerollFrames is cached or EOS
   // is reached.
@@ -65,7 +65,8 @@
 
   // VideoDecoder::Host method.
   void OnDecoderStatusUpdate(VideoDecoder::Status status,
-                             VideoFrame* frame) SB_OVERRIDE;
+                             const scoped_refptr<VideoFrame>& frame)
+      SB_OVERRIDE;
 
   ThreadChecker thread_checker_;
   ::starboard::Mutex mutex_;
@@ -77,7 +78,7 @@
   // should still display the last frame it is rendering.  This frame will be
   // kept inside |seeking_frame_|.  It is an empty/black frame before the video
   // is started.
-  VideoFrame seeking_frame_;
+  scoped_refptr<VideoFrame> seeking_frame_;
 
   SbMediaTime seeking_to_pts_;
   bool end_of_stream_written_;
diff --git a/src/starboard/shared/starboard/player/video_frame_internal.cc b/src/starboard/shared/starboard/player/video_frame_internal.cc
index 793066d..7bee2c4 100644
--- a/src/starboard/shared/starboard/player/video_frame_internal.cc
+++ b/src/starboard/shared/starboard/player/video_frame_internal.cc
@@ -73,53 +73,76 @@
 

 }  // namespace

 

-VideoFrame::VideoFrame(const VideoFrame& that) {

-  *this = that;

+VideoFrame::VideoFrame() {

+  InitializeToInvalidFrame();

 }

 

-VideoFrame& VideoFrame::operator=(const VideoFrame& that) {

-  this->format_ = that.format_;

+VideoFrame::VideoFrame(int width,

+                       int height,

+                       SbMediaTime pts,

+                       void* native_texture,

+                       void* native_texture_context,

+                       FreeNativeTextureFunc free_native_texture_func) {

+  SB_DCHECK(native_texture != NULL);

+  SB_DCHECK(free_native_texture_func != NULL);

 

-  this->pts_ = that.pts_;

-  this->planes_ = that.planes_;

-  this->pixel_buffer_ = that.pixel_buffer_;

+  InitializeToInvalidFrame();

 

-  for (int i = 0; i < GetPlaneCount(); ++i) {

-    const uint8_t* data = that.GetPlane(i).data;

-    const uint8_t* base = &that.pixel_buffer_[0];

-    ptrdiff_t offset = data - base;

-    SB_DCHECK(offset >= 0);

-    SB_DCHECK(offset < static_cast<ptrdiff_t>(that.pixel_buffer_.size()));

-    planes_[i].data = &pixel_buffer_[0] + offset;

+  format_ = kNativeTexture;

+  width_ = width;

+  height_ = height;

+  pts_ = pts;

+  native_texture_ = native_texture;

+  native_texture_context_ = native_texture_context;

+  free_native_texture_func_ = free_native_texture_func;

+}

+

+VideoFrame::~VideoFrame() {

+  if (format_ == kNativeTexture) {

+    free_native_texture_func_(native_texture_context_, native_texture_);

   }

+}

 

-  return *this;

+int VideoFrame::GetPlaneCount() const {

+  SB_DCHECK(format_ != kInvalid);

+  SB_DCHECK(format_ != kNativeTexture);

+

+  return static_cast<int>(planes_.size());

 }

 

 const VideoFrame::Plane& VideoFrame::GetPlane(int index) const {

+  SB_DCHECK(format_ != kInvalid);

+  SB_DCHECK(format_ != kNativeTexture);

   SB_DCHECK(index >= 0 && index < GetPlaneCount()) << "Invalid index: "

                                                    << index;

   return planes_[index];

 }

 

-VideoFrame VideoFrame::ConvertTo(Format target_format) const {

+void* VideoFrame::native_texture() const {

+  SB_DCHECK(format_ == kNativeTexture);

+  return native_texture_;

+}

+

+scoped_refptr<VideoFrame> VideoFrame::ConvertTo(Format target_format) const {

   SB_DCHECK(format_ == kYV12);

   SB_DCHECK(target_format == kBGRA32);

 

   EnsureYUVToRGBLookupTableInitialized();

 

-  VideoFrame target_frame;

+  scoped_refptr<VideoFrame> target_frame(new VideoFrame);

 

-  target_frame.format_ = target_format;

-  target_frame.pts_ = pts_;

-  target_frame.pixel_buffer_.resize(width() * height() * 4);

-  target_frame.planes_.push_back(

-      Plane(width(), height(), width() * 4, &target_frame.pixel_buffer_[0]));

+  target_frame->format_ = target_format;

+  target_frame->width_ = width();

+  target_frame->height_ = height();

+  target_frame->pts_ = pts_;

+  target_frame->pixel_buffer_.reset(new uint8_t[width() * height() * 4]);

+  target_frame->planes_.push_back(

+      Plane(width(), height(), width() * 4, target_frame->pixel_buffer_.get()));

 

   const uint8_t* y_data = GetPlane(0).data;

   const uint8_t* u_data = GetPlane(1).data;

   const uint8_t* v_data = GetPlane(2).data;

-  uint8_t* bgra_data = &target_frame.pixel_buffer_[0];

+  uint8_t* bgra_data = target_frame->pixel_buffer_.get();

 

   int height = this->height();

   int width = this->width();

@@ -158,21 +181,23 @@
 }

 

 // static

-VideoFrame VideoFrame::CreateEOSFrame() {

-  return VideoFrame();

+scoped_refptr<VideoFrame> VideoFrame::CreateEOSFrame() {

+  return new VideoFrame;

 }

 

 // static

-VideoFrame VideoFrame::CreateYV12Frame(int width,

-                                       int height,

-                                       int pitch_in_bytes,

-                                       SbMediaTime pts,

-                                       const uint8_t* y,

-                                       const uint8_t* u,

-                                       const uint8_t* v) {

-  VideoFrame frame;

-  frame.format_ = kYV12;

-  frame.pts_ = pts;

+scoped_refptr<VideoFrame> VideoFrame::CreateYV12Frame(int width,

+                                                      int height,

+                                                      int pitch_in_bytes,

+                                                      SbMediaTime pts,

+                                                      const uint8_t* y,

+                                                      const uint8_t* u,

+                                                      const uint8_t* v) {

+  scoped_refptr<VideoFrame> frame(new VideoFrame);

+  frame->format_ = kYV12;

+  frame->width_ = width;

+  frame->height_ = height;

+  frame->pts_ = pts;

 

   // U/V planes generally have half resolution of the Y plane.  However, in the

   // extreme case that any dimension of Y plane is odd, we want to have an

@@ -183,26 +208,38 @@
 

   int y_plane_size_in_bytes = height * pitch_in_bytes;

   int uv_plane_size_in_bytes = uv_height * uv_pitch_in_bytes;

-  frame.pixel_buffer_.reserve(y_plane_size_in_bytes +

-                              uv_plane_size_in_bytes * 2);

-  frame.pixel_buffer_.assign(y, y + y_plane_size_in_bytes);

-  frame.pixel_buffer_.insert(frame.pixel_buffer_.end(), u,

-                             u + uv_plane_size_in_bytes);

-  frame.pixel_buffer_.insert(frame.pixel_buffer_.end(), v,

-                             v + uv_plane_size_in_bytes);

+  frame->pixel_buffer_.reset(

+      new uint8_t[y_plane_size_in_bytes + uv_plane_size_in_bytes * 2]);

+  SbMemoryCopy(frame->pixel_buffer_.get(), y, y_plane_size_in_bytes);

+  SbMemoryCopy(frame->pixel_buffer_.get() + y_plane_size_in_bytes, u,

+               uv_plane_size_in_bytes);

+  SbMemoryCopy(frame->pixel_buffer_.get() + y_plane_size_in_bytes +

+                   uv_plane_size_in_bytes,

+               v, uv_plane_size_in_bytes);

 

-  frame.planes_.push_back(

-      Plane(width, height, pitch_in_bytes, &frame.pixel_buffer_[0]));

-  frame.planes_.push_back(

+  frame->planes_.push_back(

+      Plane(width, height, pitch_in_bytes, frame->pixel_buffer_.get()));

+  frame->planes_.push_back(

       Plane(uv_width, uv_height, uv_pitch_in_bytes,

-            &frame.pixel_buffer_[0] + y_plane_size_in_bytes));

-  frame.planes_.push_back(Plane(uv_width, uv_height, uv_pitch_in_bytes,

-                                &frame.pixel_buffer_[0] +

-                                    y_plane_size_in_bytes +

-                                    uv_plane_size_in_bytes));

+            frame->pixel_buffer_.get() + y_plane_size_in_bytes));

+  frame->planes_.push_back(Plane(uv_width, uv_height, uv_pitch_in_bytes,

+                                 frame->pixel_buffer_.get() +

+                                     y_plane_size_in_bytes +

+                                     uv_plane_size_in_bytes));

   return frame;

 }

 

+void VideoFrame::InitializeToInvalidFrame() {

+  format_ = kInvalid;

+  width_ = 0;

+  height_ = 0;

+

+  pts_ = 0;

+  native_texture_ = NULL;

+  native_texture_context_ = NULL;

+  free_native_texture_func_ = NULL;

+}

+

 }  // namespace player

 }  // namespace starboard

 }  // namespace shared

diff --git a/src/starboard/shared/starboard/player/video_frame_internal.h b/src/starboard/shared/starboard/player/video_frame_internal.h
index 745ec31..c956e90 100644
--- a/src/starboard/shared/starboard/player/video_frame_internal.h
+++ b/src/starboard/shared/starboard/player/video_frame_internal.h
@@ -17,6 +17,9 @@
 

 #include <vector>

 

+#include "starboard/common/ref_counted.h"

+#include "starboard/common/scoped_ptr.h"

+#include "starboard/configuration.h"

 #include "starboard/media.h"

 #include "starboard/shared/internal_only.h"

 

@@ -26,10 +29,12 @@
 namespace player {

 

 // A video frame produced by a video decoder.

-class VideoFrame {

+class VideoFrame : public RefCountedThreadSafe<VideoFrame> {

  public:

+  typedef void (*FreeNativeTextureFunc)(void* context, void* textue);

+

   enum Format {

-    kInvalid,

+    kInvalid,  // A VideoFrame in this format can be used to indicate EOS.

     // This is the native format supported by XComposite (PictStandardARGB32

     // with bytes swapped).  Remove this once we are able to pass out frames

     // as YV12 textures.

@@ -50,37 +55,55 @@
     const uint8_t* data;

   };

 

-  VideoFrame() : format_(kInvalid) {}

-  VideoFrame(const VideoFrame& that);

-

-  VideoFrame& operator=(const VideoFrame& that);

+  VideoFrame();  // Create an EOS frame.

+  VideoFrame(int width,

+             int height,

+             SbMediaTime pts,

+             void* native_texture,

+             void* native_texture_context,

+             FreeNativeTextureFunc free_native_texture_func);

+  ~VideoFrame();

 

   Format format() const { return format_; }

-  int width() const { return GetPlaneCount() == 0 ? 0 : GetPlane(0).width; }

-  int height() const { return GetPlaneCount() == 0 ? 0 : GetPlane(0).height; }

-

   bool IsEndOfStream() const { return format_ == kInvalid; }

   SbMediaTime pts() const { return pts_; }

-  int GetPlaneCount() const { return static_cast<int>(planes_.size()); }

+  int width() const { return width_; }

+  int height() const { return height_; }

+

+  int GetPlaneCount() const;

   const Plane& GetPlane(int index) const;

 

-  VideoFrame ConvertTo(Format target_format) const;

+  void* native_texture() const;

 

-  static VideoFrame CreateEOSFrame();

-  static VideoFrame CreateYV12Frame(int width,

-                                    int height,

-                                    int pitch_in_bytes,

-                                    SbMediaTime pts,

-                                    const uint8_t* y,

-                                    const uint8_t* u,

-                                    const uint8_t* v);

+  scoped_refptr<VideoFrame> ConvertTo(Format target_format) const;

+

+  static scoped_refptr<VideoFrame> CreateEOSFrame();

+  static scoped_refptr<VideoFrame> CreateYV12Frame(int width,

+                                                   int height,

+                                                   int pitch_in_bytes,

+                                                   SbMediaTime pts,

+                                                   const uint8_t* y,

+                                                   const uint8_t* u,

+                                                   const uint8_t* v);

 

  private:

-  Format format_;

+  void InitializeToInvalidFrame();

 

+  Format format_;

+  int width_;

+  int height_;

   SbMediaTime pts_;

+

+  // The following two variables are valid when the frame contains pixel data.

   std::vector<Plane> planes_;

-  std::vector<uint8_t> pixel_buffer_;

+  scoped_array<uint8_t> pixel_buffer_;

+

+  // The following three variables are valid when |format_| is `kNativeTexture`.

+  void* native_texture_;

+  void* native_texture_context_;

+  FreeNativeTextureFunc free_native_texture_func_;

+

+  SB_DISALLOW_COPY_AND_ASSIGN(VideoFrame);

 };

 

 }  // namespace player

diff --git a/src/starboard/shared/x11/application_x11.cc b/src/starboard/shared/x11/application_x11.cc
index 1457e73..797c807 100644
--- a/src/starboard/shared/x11/application_x11.cc
+++ b/src/starboard/shared/x11/application_x11.cc
@@ -679,7 +679,7 @@
         ScopedLock lock(frame_mutex_);
         if (frame_written_) {
           // Clear the old frame, now that we are done with it.
-          frame_infos_[frame_read_index_].frame = VideoFrame();
+          frame_infos_[frame_read_index_].frame = NULL;
 
           // Increment the index to the next frame, which has been written.
           frame_read_index_ = (frame_read_index_ + 1) % kNumFrames;
@@ -692,12 +692,12 @@
       }
       FrameInfo& frame_info = frame_infos_[frame_read_index_];
 
-      if (!frame_info.frame.IsEndOfStream() &&
-          frame_info.frame.format() != VideoFrame::kBGRA32) {
-        frame_info.frame = frame_info.frame.ConvertTo(VideoFrame::kBGRA32);
+      if (frame_info.frame && !frame_info.frame->IsEndOfStream() &&
+          frame_info.frame->format() != VideoFrame::kBGRA32) {
+        frame_info.frame = frame_info.frame->ConvertTo(VideoFrame::kBGRA32);
       }
       window->Composite(frame_info.x, frame_info.y, frame_info.width,
-                        frame_info.height, &frame_info.frame);
+                        frame_info.height, frame_info.frame);
     }
   }
   composite_event_id_ =
@@ -705,7 +705,7 @@
 }
 
 void ApplicationX11::AcceptFrame(SbPlayer player,
-                                 const VideoFrame& frame,
+                                 const scoped_refptr<VideoFrame>& frame,
                                  int x,
                                  int y,
                                  int width,
diff --git a/src/starboard/shared/x11/application_x11.h b/src/starboard/shared/x11/application_x11.h
index 8bd9940..efe2a24 100644
--- a/src/starboard/shared/x11/application_x11.h
+++ b/src/starboard/shared/x11/application_x11.h
@@ -49,7 +49,7 @@
 
  protected:
   void AcceptFrame(SbPlayer player,
-                   const shared::starboard::player::VideoFrame& frame,
+                   const scoped_refptr<VideoFrame>& frame,
                    int x,
                    int y,
                    int width,
@@ -71,7 +71,7 @@
 
 #if SB_IS(PLAYER_PUNCHED_OUT)
   struct FrameInfo {
-    shared::starboard::player::VideoFrame frame;
+    scoped_refptr<VideoFrame> frame;
     int x;
     int y;
     int width;
diff --git a/src/starboard/shared/x11/window_internal.cc b/src/starboard/shared/x11/window_internal.cc
index b17082a..70daeb3 100644
--- a/src/starboard/shared/x11/window_internal.cc
+++ b/src/starboard/shared/x11/window_internal.cc
@@ -30,8 +30,6 @@
 #include <X11/extensions/Xrender.h>
 #endif  // SB_IS(PLAYER_PUNCHED_OUT)
 
-using starboard::shared::starboard::player::VideoFrame;
-
 namespace {
 
 const int kWindowWidth = 1920;
@@ -148,11 +146,12 @@
 }
 
 #if SB_IS(PLAYER_PUNCHED_OUT)
-void SbWindowPrivate::Composite(int bounds_x,
-                                int bounds_y,
-                                int bounds_width,
-                                int bounds_height,
-                                VideoFrame* frame) {
+void SbWindowPrivate::Composite(
+    int bounds_x,
+    int bounds_y,
+    int bounds_width,
+    int bounds_height,
+    const starboard::scoped_refptr<VideoFrame>& frame) {
   XSynchronize(display, True);
   XWindowAttributes window_attributes;
   XGetWindowAttributes(display, window, &window_attributes);
diff --git a/src/starboard/shared/x11/window_internal.h b/src/starboard/shared/x11/window_internal.h
index 7c55cb3..e96ffdc 100644
--- a/src/starboard/shared/x11/window_internal.h
+++ b/src/starboard/shared/x11/window_internal.h
@@ -33,6 +33,8 @@
   Window window;
 
 #if SB_IS(PLAYER_PUNCHED_OUT)
+  typedef ::starboard::shared::starboard::player::VideoFrame VideoFrame;
+
   // Composites graphics and the given video frame video for this window. In
   // PLAYER_PUNCHED_OUT mode, this is the only way any graphics or video is
   // presented in the window.  The video frame will be rendered according to
@@ -41,7 +43,7 @@
                  int bounds_y,
                  int bounds_width,
                  int bounds_height,
-                 ::starboard::shared::starboard::player::VideoFrame* frame);
+                 const starboard::scoped_refptr<VideoFrame>& frame);
 
   // The cached XRender Picture that represents the window that is the
   // destination of the composition.
diff --git a/src/starboard/thread.h b/src/starboard/thread.h
index d2138e0..f642f28 100644
--- a/src/starboard/thread.h
+++ b/src/starboard/thread.h
@@ -255,7 +255,7 @@
 // Returns whether |thread| is the current thread.
 //
 // |thread|: The thread to check.
-SB_C_INLINE bool SbThreadIsCurrent(SbThread thread) {
+static SB_C_INLINE bool SbThreadIsCurrent(SbThread thread) {
   return SbThreadGetCurrent() == thread;
 }