diff --git a/DEPS b/DEPS
index 933ef268..a5170906 100644
--- a/DEPS
+++ b/DEPS
@@ -39,7 +39,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '56f152b53f911b578e305d3461fb001585984a67',
+  'skia_revision': '77a2e52c7d5c77de73ecab5fec79072ee4460706',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 2449788d..55c37af 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1416,10 +1416,18 @@
     }
   }
 
-  if (external_transform_ != transform || external_viewport_ != viewport ||
-      resourceless_software_draw_ != resourceless_software_draw ||
+  const bool transform_changed = external_transform_ != transform;
+  const bool viewport_changed = external_viewport_ != viewport;
+  const bool clip_changed = external_clip_ != clip;
+  const bool resourceless_software_draw_changed =
+      resourceless_software_draw_ != resourceless_software_draw;
+  const bool tile_priority_params_changed =
       viewport_rect_for_tile_priority_ !=
-          viewport_rect_for_tile_priority_in_view_space) {
+      viewport_rect_for_tile_priority_in_view_space;
+
+  // UpdateDrawProperties does not depend on clip.
+  if (transform_changed || viewport_changed ||
+      resourceless_software_draw_changed || tile_priority_params_changed) {
     active_tree_->set_needs_update_draw_properties();
   }
 
@@ -1429,6 +1437,16 @@
   viewport_rect_for_tile_priority_ =
       viewport_rect_for_tile_priority_in_view_space;
   resourceless_software_draw_ = resourceless_software_draw;
+
+  // When not toggling resourceless software draw, need to set redraw for
+  // all changes to draw parameters. Damage will be set externally by Android
+  // WebView for resourceless software draw toggles, so ignored here.
+  const bool draw_params_changed = transform_changed || viewport_changed ||
+                                   clip_changed || tile_priority_params_changed;
+  if (!resourceless_software_draw_changed && draw_params_changed) {
+    SetFullRootLayerDamage();
+    SetNeedsRedraw();
+  }
 }
 
 void LayerTreeHostImpl::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
@@ -2797,13 +2815,16 @@
 
 void LayerTreeHostImpl::SetSynchronousInputHandlerRootScrollOffset(
     const gfx::ScrollOffset& root_offset) {
-  active_tree_->DistributeRootScrollOffset(root_offset);
+  bool changed = active_tree_->DistributeRootScrollOffset(root_offset);
+  if (!changed)
+    return;
+
   client_->SetNeedsCommitOnImplThread();
   // After applying the synchronous input handler's scroll offset, tell it what
   // we ended up with.
   UpdateRootLayerStateForSynchronousInputHandler();
-  // No need to SetNeedsRedraw, this is for WebView and every frame has redraw
-  // requested by the WebView embedder already.
+  SetFullRootLayerDamage();
+  SetNeedsRedraw();
 }
 
 void LayerTreeHostImpl::ClearCurrentlyScrollingLayer() {
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 6f69b5f..9232c5a6 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -8177,6 +8177,74 @@
       external_transform, layer->draw_properties().target_space_transform);
 }
 
+TEST_F(LayerTreeHostImplTest, ExternalTransformSetNeedsRedraw) {
+  SetupRootLayerImpl(LayerImpl::Create(host_impl_->active_tree(), 1));
+
+  const gfx::Size layer_size(100, 100);
+  const gfx::Transform external_transform;
+  const gfx::Rect external_viewport(layer_size);
+  const gfx::Rect external_clip1(layer_size);
+  const gfx::Rect external_clip2(50, 50);
+  bool resourceless_software_draw = false;
+
+  resourceless_software_draw = false;
+  host_impl_->SetExternalDrawConstraints(
+      external_transform, external_viewport, external_clip1, external_viewport,
+      external_transform, resourceless_software_draw);
+  {
+    // Clear any damage.
+    LayerTreeHostImpl::FrameData frame;
+    EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame));
+    host_impl_->DrawLayers(&frame);
+    host_impl_->DidDrawAllLayers(frame);
+    host_impl_->SwapBuffers(frame);
+  }
+
+  // Setting new constraints needs redraw.
+  did_request_redraw_ = false;
+  host_impl_->SetExternalDrawConstraints(
+      external_transform, external_viewport, external_clip2, external_viewport,
+      external_transform, resourceless_software_draw);
+  EXPECT_TRUE(did_request_redraw_);
+  {
+    LayerTreeHostImpl::FrameData frame;
+    EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame));
+    EXPECT_FALSE(frame.has_no_damage);
+    host_impl_->DrawLayers(&frame);
+    host_impl_->DidDrawAllLayers(frame);
+    host_impl_->SwapBuffers(frame);
+  }
+
+  // Resourceless software draw toggles do not need redraw. Damage is
+  // set externally by SynchronousCompositorOutputSurface in this case.
+
+  // Setting resourceless_software_draw do not need redraw.
+  did_request_redraw_ = false;
+  resourceless_software_draw = true;
+  host_impl_->SetExternalDrawConstraints(
+      external_transform, external_viewport, external_clip1, external_viewport,
+      external_transform, resourceless_software_draw);
+  EXPECT_FALSE(did_request_redraw_);
+  {
+    LayerTreeHostImpl::FrameData frame;
+    EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame));
+    EXPECT_TRUE(frame.has_no_damage);
+  }
+
+  // Unsetting resourceless_software_draw do not need redraw.
+  did_request_redraw_ = false;
+  resourceless_software_draw = false;
+  host_impl_->SetExternalDrawConstraints(
+      external_transform, external_viewport, external_clip2, external_viewport,
+      external_transform, resourceless_software_draw);
+  EXPECT_FALSE(did_request_redraw_);
+  {
+    LayerTreeHostImpl::FrameData frame;
+    EXPECT_EQ(DRAW_SUCCESS, PrepareToDrawFrame(&frame));
+    EXPECT_TRUE(frame.has_no_damage);
+  }
+}
+
 TEST_F(LayerTreeHostImplTest, ScrollAnimated) {
   SetupScrollAndContentsLayers(gfx::Size(100, 200));
   DrawFrame();
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index a77e517..35b6818 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -1075,10 +1075,10 @@
   state->EndArray();
 }
 
-void LayerTreeImpl::DistributeRootScrollOffset(
+bool LayerTreeImpl::DistributeRootScrollOffset(
     const gfx::ScrollOffset& root_offset) {
   if (!InnerViewportScrollLayer())
-    return;
+    return false;
 
   DCHECK(OuterViewportScrollLayer());
 
@@ -1092,7 +1092,7 @@
   // It may be nothing has changed.
   DCHECK(inner_viewport_offset + outer_viewport_offset == TotalScrollOffset());
   if (inner_viewport_offset + outer_viewport_offset == root_offset)
-    return;
+    return false;
 
   gfx::ScrollOffset max_outer_viewport_scroll_offset =
       OuterViewportScrollLayer()->MaxScrollOffset();
@@ -1104,6 +1104,7 @@
   OuterViewportScrollLayer()->SetCurrentScrollOffset(outer_viewport_offset);
   inner_viewport_offset = root_offset - outer_viewport_offset;
   InnerViewportScrollLayer()->SetCurrentScrollOffset(inner_viewport_offset);
+  return true;
 }
 
 void LayerTreeImpl::QueueSwapPromise(scoped_ptr<SwapPromise> swap_promise) {
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 10a2748..6d544387 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -271,7 +271,7 @@
 
   // Distribute the root scroll between outer and inner viewport scroll layer.
   // The outer viewport scroll layer scrolls first.
-  void DistributeRootScrollOffset(const gfx::ScrollOffset& root_offset);
+  bool DistributeRootScrollOffset(const gfx::ScrollOffset& root_offset);
 
   void ApplyScroll(LayerImpl* layer, ScrollState* scroll_state) {
     layer_tree_host_impl_->ApplyScroll(layer, scroll_state);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
index 264d041..804aa30 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -285,19 +285,17 @@
 
             @Override
             public void didFirstVisuallyNonEmptyPaint(Tab tab) {
-                if (mSplashScreen == null) return;
+                hideSplashScreen();
+            }
 
-                mSplashScreen.animate()
-                        .alpha(0f)
-                        .withEndAction(new Runnable() {
-                            @Override
-                            public void run() {
-                                ViewGroup contentView =
-                                        (ViewGroup) findViewById(android.R.id.content);
-                                contentView.removeView(mSplashScreen);
-                                mSplashScreen = null;
-                            }
-                        });
+            @Override
+            public void onPageLoadFinished(Tab tab) {
+                hideSplashScreen();
+            }
+
+            @Override
+            public void onPageLoadFailed(Tab tab, int errorCode) {
+                hideSplashScreen();
             }
         };
     }
@@ -384,6 +382,23 @@
         }
     }
 
+    private void hideSplashScreen() {
+        if (mSplashScreen == null) return;
+
+        mSplashScreen.animate()
+                .alpha(0f)
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        ViewGroup contentView =
+                                (ViewGroup) findViewById(android.R.id.content);
+                        if (mSplashScreen == null) return;
+                        contentView.removeView(mSplashScreen);
+                        mSplashScreen = null;
+                    }
+                });
+    }
+
     @VisibleForTesting
     WebappUrlBar getUrlBarForTests() {
         return mUrlBar;
diff --git a/chromecast/common/media/cma_param_traits.cc b/chromecast/common/media/cma_param_traits.cc
index ab0f62a3..2ae4fd9 100644
--- a/chromecast/common/media/cma_param_traits.cc
+++ b/chromecast/common/media/cma_param_traits.cc
@@ -34,13 +34,7 @@
   WriteParam(m, p.channel_layout());
   WriteParam(m, p.samples_per_second());
   WriteParam(m, p.is_encrypted());
-  std::vector<uint8> extra_data;
-  if (p.extra_data_size() > 0) {
-    extra_data =
-        std::vector<uint8>(p.extra_data(),
-                           p.extra_data() + p.extra_data_size());
-  }
-  WriteParam(m, extra_data);
+  WriteParam(m, p.extra_data());
 }
 
 bool ParamTraits<media::AudioDecoderConfig>::Read(
@@ -58,13 +52,8 @@
       !ReadParam(m, iter, &samples_per_second) ||
       !ReadParam(m, iter, &is_encrypted) || !ReadParam(m, iter, &extra_data))
     return false;
-  const uint8* extra_data_ptr = nullptr;
-  if (!extra_data.empty())
-    extra_data_ptr = &extra_data[0];
   *r = media::AudioDecoderConfig(codec, sample_format, channel_layout,
-                                 samples_per_second,
-                                 extra_data_ptr, extra_data.size(),
-                                 is_encrypted);
+                                 samples_per_second, extra_data, is_encrypted);
   return true;
 }
 
@@ -83,13 +72,7 @@
   WriteParam(m, p.visible_rect());
   WriteParam(m, p.natural_size());
   WriteParam(m, p.is_encrypted());
-  std::vector<uint8> extra_data;
-  if (p.extra_data_size() > 0) {
-    extra_data =
-        std::vector<uint8>(p.extra_data(),
-                           p.extra_data() + p.extra_data_size());
-  }
-  WriteParam(m, extra_data);
+  WriteParam(m, p.extra_data());
 }
 
 bool ParamTraits<media::VideoDecoderConfig>::Read(
@@ -111,13 +94,9 @@
       !ReadParam(m, iter, &natural_size) ||
       !ReadParam(m, iter, &is_encrypted) || !ReadParam(m, iter, &extra_data))
     return false;
-  const uint8* extra_data_ptr = nullptr;
-  if (!extra_data.empty())
-    extra_data_ptr = &extra_data[0];
   *r = media::VideoDecoderConfig(codec, profile, format, color_space,
                                  coded_size, visible_rect, natural_size,
-                                 extra_data_ptr, extra_data.size(),
-                                 is_encrypted);
+                                 extra_data, is_encrypted);
   return true;
 }
 
diff --git a/chromecast/media/audio/cast_audio_output_stream.cc b/chromecast/media/audio/cast_audio_output_stream.cc
index e55f127..69eda32d 100644
--- a/chromecast/media/audio/cast_audio_output_stream.cc
+++ b/chromecast/media/audio/cast_audio_output_stream.cc
@@ -42,8 +42,6 @@
   audio_config.bytes_per_channel = audio_params.bits_per_sample() / 8;
   audio_config.channel_number = audio_params.channels();
   audio_config.samples_per_second = audio_params.sample_rate();
-  audio_config.extra_data = nullptr;
-  audio_config.extra_data_size = 0;
   audio_config.is_encrypted = false;
 
   if (!decoder->SetConfig(audio_config))
diff --git a/chromecast/media/cma/base/decoder_config_adapter.cc b/chromecast/media/cma/base/decoder_config_adapter.cc
index b75d5f2b..248edd02 100644
--- a/chromecast/media/cma/base/decoder_config_adapter.cc
+++ b/chromecast/media/cma/base/decoder_config_adapter.cc
@@ -182,8 +182,8 @@
       ::media::ChannelLayoutToChannelCount(config.channel_layout()),
   audio_config.samples_per_second = config.samples_per_second();
   audio_config.extra_data =
-      (config.extra_data_size() > 0) ? config.extra_data() : nullptr;
-  audio_config.extra_data_size = config.extra_data_size();
+      (config.extra_data().empty()) ? nullptr : &config.extra_data()[0];
+  audio_config.extra_data_size = config.extra_data().size();
   audio_config.is_encrypted = config.is_encrypted();
   return audio_config;
 }
@@ -191,11 +191,16 @@
 // static
 ::media::AudioDecoderConfig DecoderConfigAdapter::ToMediaAudioDecoderConfig(
     const AudioConfig& config) {
+  std::vector<uint8_t> extra_data;
+  if (config.extra_data_size > 0)
+    extra_data.assign(config.extra_data,
+                      config.extra_data + config.extra_data_size);
+
   return ::media::AudioDecoderConfig(
       ToMediaAudioCodec(config.codec),
       ToMediaSampleFormat(config.sample_format),
       ToMediaChannelLayout(config.channel_number), config.samples_per_second,
-      config.extra_data, config.extra_data_size, config.is_encrypted);
+      extra_data, config.is_encrypted);
 }
 
 // static
@@ -210,9 +215,9 @@
   video_config.id = id;
   video_config.codec = ToVideoCodec(config.codec());
   video_config.profile = ToVideoProfile(config.profile());
-  video_config.extra_data = (config.extra_data_size() > 0) ?
-      config.extra_data() : nullptr;
-  video_config.extra_data_size = config.extra_data_size();
+  video_config.extra_data = (config.extra_data().empty()) ?
+      nullptr : &config.extra_data()[0];
+  video_config.extra_data_size = config.extra_data().size();
   video_config.is_encrypted = config.is_encrypted();
   return video_config;
 }
diff --git a/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc b/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc
index d595bdaa..2bc40f4 100644
--- a/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc
+++ b/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc
@@ -4,6 +4,8 @@
 
 #include "chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.h"
 
+#include <vector>
+
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "chromecast/media/cma/ipc/media_message.h"
@@ -24,9 +26,10 @@
   CHECK(msg->WritePod(config.samples_per_second()));
   CHECK(msg->WritePod(config.sample_format()));
   CHECK(msg->WritePod(config.is_encrypted()));
-  CHECK(msg->WritePod(config.extra_data_size()));
-  if (config.extra_data_size() > 0)
-    CHECK(msg->WriteBuffer(config.extra_data(), config.extra_data_size()));
+  CHECK(msg->WritePod(config.extra_data().size()));
+  if (!config.extra_data().empty())
+    CHECK(msg->WriteBuffer(&config.extra_data()[0],
+                           config.extra_data().size()));
 }
 
 // static
@@ -38,7 +41,7 @@
   int samples_per_second;
   bool is_encrypted;
   size_t extra_data_size;
-  scoped_ptr<uint8[]> extra_data;
+  std::vector<uint8_t> extra_data;
 
   CHECK(msg->ReadPod(&codec));
   CHECK(msg->ReadPod(&channel_layout));
@@ -55,15 +58,14 @@
   CHECK_LE(sample_format, ::media::kSampleFormatMax);
   CHECK_LT(extra_data_size, kMaxExtraDataSize);
   if (extra_data_size > 0) {
-    extra_data.reset(new uint8[extra_data_size]);
-    CHECK(msg->ReadBuffer(extra_data.get(), extra_data_size));
+    extra_data.resize(extra_data_size);
+    CHECK(msg->ReadBuffer(&extra_data[0], extra_data.size()));
   }
 
   return ::media::AudioDecoderConfig(
       codec, sample_format,
       channel_layout, samples_per_second,
-      extra_data.get(), extra_data_size,
-      is_encrypted);
+      extra_data, is_encrypted);
 }
 
 }  // namespace media
diff --git a/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc b/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc
index 1c07352e..8cd28ae 100644
--- a/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc
+++ b/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc
@@ -4,6 +4,8 @@
 
 #include "chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.h"
 
+#include <vector>
+
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "chromecast/media/cma/ipc/media_message.h"
@@ -64,9 +66,10 @@
   RectMarshaller::Write(config.visible_rect(), msg);
   SizeMarshaller::Write(config.natural_size(), msg);
   CHECK(msg->WritePod(config.is_encrypted()));
-  CHECK(msg->WritePod(config.extra_data_size()));
-  if (config.extra_data_size() > 0)
-    CHECK(msg->WriteBuffer(config.extra_data(), config.extra_data_size()));
+  CHECK(msg->WritePod(config.extra_data().size()));
+  if (!config.extra_data().empty())
+    CHECK(msg->WriteBuffer(&config.extra_data()[0],
+                           config.extra_data().size()));
 }
 
 // static
@@ -81,7 +84,7 @@
   gfx::Size natural_size;
   bool is_encrypted;
   size_t extra_data_size;
-  scoped_ptr<uint8[]> extra_data;
+  std::vector<uint8_t> extra_data;
 
   CHECK(msg->ReadPod(&codec));
   CHECK(msg->ReadPod(&profile));
@@ -103,15 +106,14 @@
   CHECK_LE(color_space, ::media::COLOR_SPACE_MAX);
   CHECK_LT(extra_data_size, kMaxExtraDataSize);
   if (extra_data_size > 0) {
-    extra_data.reset(new uint8[extra_data_size]);
-    CHECK(msg->ReadBuffer(extra_data.get(), extra_data_size));
+    extra_data.resize(extra_data_size);
+    CHECK(msg->ReadBuffer(&extra_data[0], extra_data.size()));
   }
 
   return ::media::VideoDecoderConfig(
       codec, profile, format, color_space,
       coded_size, visible_rect, natural_size,
-      extra_data.get(), extra_data_size,
-      is_encrypted);
+      extra_data, is_encrypted);
 }
 
 }  // namespace media
diff --git a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
index 040f96e..981247c 100644
--- a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
+++ b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
@@ -25,6 +25,7 @@
 #include "chromecast/media/cma/test/mock_frame_provider.h"
 #include "media/base/audio_decoder_config.h"
 #include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
 #include "media/base/video_decoder_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -80,13 +81,13 @@
       ::media::kSampleFormatS16,
       ::media::CHANNEL_LAYOUT_STEREO,
       44100,
-      NULL, 0, false);
+      ::media::EmptyExtraData(), false);
   std::vector<::media::VideoDecoderConfig> video_configs;
   video_configs.push_back(::media::VideoDecoderConfig(
       ::media::kCodecH264, ::media::H264PROFILE_MAIN,
       ::media::PIXEL_FORMAT_I420, ::media::COLOR_SPACE_UNSPECIFIED,
-      gfx::Size(640, 480), gfx::Rect(0, 0, 640, 480), gfx::Size(640, 480), NULL,
-      0, false));
+      gfx::Size(640, 480), gfx::Rect(0, 0, 640, 480), gfx::Size(640, 480),
+      ::media::EmptyExtraData(), false));
 
   // Frame generation on the producer side.
   std::vector<FrameGeneratorForTest::FrameSpec> frame_specs;
diff --git a/chromecast/media/cma/test/mock_frame_provider.cc b/chromecast/media/cma/test/mock_frame_provider.cc
index 27649a7..fdab889 100644
--- a/chromecast/media/cma/test/mock_frame_provider.cc
+++ b/chromecast/media/cma/test/mock_frame_provider.cc
@@ -13,6 +13,7 @@
 #include "chromecast/media/cma/test/frame_generator_for_test.h"
 #include "media/base/audio_decoder_config.h"
 #include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
 #include "media/base/video_decoder_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/rect.h"
@@ -80,14 +81,15 @@
     video_config = ::media::VideoDecoderConfig(
         ::media::kCodecH264, ::media::VIDEO_CODEC_PROFILE_UNKNOWN,
         ::media::PIXEL_FORMAT_YV12, ::media::COLOR_SPACE_UNSPECIFIED,
-        coded_size, visible_rect, natural_size, NULL, 0, false);
+        coded_size, visible_rect, natural_size, ::media::EmptyExtraData(),
+        false);
 
     audio_config = ::media::AudioDecoderConfig(
       ::media::kCodecAAC,
       ::media::kSampleFormatS16,
       ::media::CHANNEL_LAYOUT_STEREO,
       44100,
-      NULL, 0,
+      ::media::EmptyExtraData(),
       false);
   }
 
diff --git a/chromecast/renderer/media/demuxer_stream_for_test.cc b/chromecast/renderer/media/demuxer_stream_for_test.cc
index 228f1de7..89b45ea 100644
--- a/chromecast/renderer/media/demuxer_stream_for_test.cc
+++ b/chromecast/renderer/media/demuxer_stream_for_test.cc
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/threading/thread.h"
 #include "chromecast/renderer/media/demuxer_stream_for_test.h"
 
+#include "base/threading/thread.h"
+#include "media/base/media_util.h"
+
 namespace chromecast {
 namespace media {
 
@@ -60,8 +62,7 @@
                                      coded_size,
                                      visible_rect,
                                      natural_size,
-                                     NULL,
-                                     0,
+                                     ::media::EmptyExtraData(),
                                      false);
 }
 
diff --git a/content/common/gpu/media/video_encode_accelerator_unittest.cc b/content/common/gpu/media/video_encode_accelerator_unittest.cc
index b612bd8..e22bd429 100644
--- a/content/common/gpu/media/video_encode_accelerator_unittest.cc
+++ b/content/common/gpu/media/video_encode_accelerator_unittest.cc
@@ -28,6 +28,7 @@
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/bitstream_buffer.h"
 #include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
 #include "media/base/test_data_util.h"
 #include "media/base/video_decoder.h"
 #include "media/base/video_frame.h"
@@ -659,11 +660,11 @@
   if (IsVP8(profile_))
     config.Initialize(media::kCodecVP8, media::VP8PROFILE_ANY, kInputFormat,
                       media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_size,
-                      natural_size, NULL, 0, false);
+                      natural_size, media::EmptyExtraData(), false);
   else if (IsH264(profile_))
     config.Initialize(media::kCodecH264, media::H264PROFILE_MAIN, kInputFormat,
                       media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_size,
-                      natural_size, NULL, 0, false);
+                      natural_size, media::EmptyExtraData(), false);
   else
     LOG_ASSERT(0) << "Invalid profile " << profile_;
 
diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc
index 139be4a..4c0477b6 100644
--- a/content/renderer/media/android/media_source_delegate.cc
+++ b/content/renderer/media/android/media_source_delegate.cc
@@ -736,8 +736,7 @@
         media::ChannelLayoutToChannelCount(config.channel_layout());
     configs->audio_sampling_rate = config.samples_per_second();
     configs->is_audio_encrypted = config.is_encrypted();
-    configs->audio_extra_data = std::vector<uint8>(
-        config.extra_data(), config.extra_data() + config.extra_data_size());
+    configs->audio_extra_data = config.extra_data();
     configs->audio_codec_delay_ns = static_cast<int64_t>(
         config.codec_delay()  *
         (static_cast<double>(base::Time::kNanosecondsPerSecond) /
@@ -752,8 +751,7 @@
     configs->video_codec = config.codec();
     configs->video_size = config.natural_size();
     configs->is_video_encrypted = config.is_encrypted();
-    configs->video_extra_data = std::vector<uint8>(
-        config.extra_data(), config.extra_data() + config.extra_data_size());
+    configs->video_extra_data = config.extra_data();
     return true;
   }
   return false;
diff --git a/content/renderer/pepper/content_decryptor_delegate.cc b/content/renderer/pepper/content_decryptor_delegate.cc
index a3596c85..2efb849 100644
--- a/content/renderer/pepper/content_decryptor_delegate.cc
+++ b/content/renderer/pepper/content_decryptor_delegate.cc
@@ -4,6 +4,8 @@
 
 #include "content/renderer/pepper/content_decryptor_delegate.h"
 
+#include <vector>
+
 #include "base/callback_helpers.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/numerics/safe_conversions.h"
@@ -53,27 +55,25 @@
 // reference-count of 0. If |data| is NULL, sets |*resource| to NULL. Returns
 // true upon success and false if any error happened.
 bool MakeBufferResource(PP_Instance instance,
-                        const uint8_t* data,
-                        uint32_t size,
+                        const std::vector<uint8_t>& data,
                         scoped_refptr<PPB_Buffer_Impl>* resource) {
   TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource");
   DCHECK(resource);
 
-  if (!data || !size) {
-    DCHECK(!data && !size);
+  if (data.empty()) {
     resource = NULL;
     return true;
   }
 
   scoped_refptr<PPB_Buffer_Impl> buffer(
-      PPB_Buffer_Impl::CreateResource(instance, size));
+      PPB_Buffer_Impl::CreateResource(instance, data.size()));
   if (!buffer.get())
     return false;
 
   BufferAutoMapper mapper(buffer.get());
-  if (!mapper.data() || mapper.size() < size)
+  if (!mapper.data() || mapper.size() < data.size())
     return false;
-  memcpy(mapper.data(), data, size);
+  memcpy(mapper.data(), &data[0], data.size());
 
   *resource = buffer;
   return true;
@@ -592,7 +592,6 @@
   scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
   if (!MakeBufferResource(pp_instance_,
                           decoder_config.extra_data(),
-                          decoder_config.extra_data_size(),
                           &extra_data_resource)) {
     return false;
   }
@@ -621,7 +620,6 @@
   scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
   if (!MakeBufferResource(pp_instance_,
                           decoder_config.extra_data(),
-                          decoder_config.extra_data_size(),
                           &extra_data_resource)) {
     return false;
   }
diff --git a/content/renderer/pepper/video_decoder_shim.cc b/content/renderer/pepper/video_decoder_shim.cc
index d84ac81f..d3c3d1b 100644
--- a/content/renderer/pepper/video_decoder_shim.cc
+++ b/content/renderer/pepper/video_decoder_shim.cc
@@ -23,6 +23,7 @@
 #include "gpu/command_buffer/client/gles2_implementation.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/limits.h"
+#include "media/base/media_util.h"
 #include "media/base/video_decoder.h"
 #include "media/blink/skcanvas_video_renderer.h"
 #include "media/filters/ffmpeg_video_decoder.h"
@@ -882,8 +883,8 @@
       codec, profile, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_UNSPECIFIED,
       gfx::Size(32, 24),  // Small sizes that won't fail.
       gfx::Rect(32, 24), gfx::Size(32, 24),
-      NULL /* extra_data */,  // TODO(bbudge) Verify this isn't needed.
-      0 /* extra_data_size */, false /* decryption */);
+      // TODO(bbudge): Verify extra data isn't needed.
+      media::EmptyExtraData(), false /* decryption */);
 
   media_task_runner_->PostTask(
       FROM_HERE,
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index 691e130..8ca0edf 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -122,6 +122,8 @@
     "media_resources.h",
     "media_switches.cc",
     "media_switches.h",
+    "media_util.cc",
+    "media_util.h",
     "mime_util.cc",
     "mime_util.h",
     "moving_average.cc",
diff --git a/media/base/audio_decoder_config.cc b/media/base/audio_decoder_config.cc
index 6dc5b2f..213cb10 100644
--- a/media/base/audio_decoder_config.cc
+++ b/media/base/audio_decoder_config.cc
@@ -24,30 +24,26 @@
                                        SampleFormat sample_format,
                                        ChannelLayout channel_layout,
                                        int samples_per_second,
-                                       const uint8* extra_data,
-                                       size_t extra_data_size,
+                                       const std::vector<uint8_t>& extra_data,
                                        bool is_encrypted) {
   Initialize(codec, sample_format, channel_layout, samples_per_second,
-             extra_data, extra_data_size, is_encrypted, base::TimeDelta(), 0);
+             extra_data, is_encrypted, base::TimeDelta(), 0);
 }
 
 void AudioDecoderConfig::Initialize(AudioCodec codec,
                                     SampleFormat sample_format,
                                     ChannelLayout channel_layout,
                                     int samples_per_second,
-                                    const uint8* extra_data,
-                                    size_t extra_data_size,
+                                    const std::vector<uint8_t>& extra_data,
                                     bool is_encrypted,
                                     base::TimeDelta seek_preroll,
                                     int codec_delay) {
-  CHECK((extra_data_size != 0) == (extra_data != NULL));
-
   codec_ = codec;
   channel_layout_ = channel_layout;
   samples_per_second_ = samples_per_second;
   sample_format_ = sample_format;
   bytes_per_channel_ = SampleFormatToBytesPerChannel(sample_format);
-  extra_data_.assign(extra_data, extra_data + extra_data_size);
+  extra_data_ = extra_data;
   is_encrypted_ = is_encrypted;
   seek_preroll_ = seek_preroll;
   codec_delay_ = codec_delay;
@@ -75,9 +71,7 @@
           (bytes_per_channel() == config.bytes_per_channel()) &&
           (channel_layout() == config.channel_layout()) &&
           (samples_per_second() == config.samples_per_second()) &&
-          (extra_data_size() == config.extra_data_size()) &&
-          (!extra_data() || !memcmp(extra_data(), config.extra_data(),
-                                    extra_data_size())) &&
+          (extra_data() == config.extra_data()) &&
           (is_encrypted() == config.is_encrypted()) &&
           (sample_format() == config.sample_format()) &&
           (seek_preroll() == config.seek_preroll()) &&
@@ -94,7 +88,7 @@
     << " bytes_per_frame: " << bytes_per_frame()
     << " seek_preroll: " << seek_preroll().InMilliseconds() << "ms"
     << " codec_delay: " << codec_delay()
-    << " has extra data? " << (extra_data() ? "true" : "false")
+    << " has extra data? " << (extra_data().empty() ? "false" : "true")
     << " encrypted? " << (is_encrypted() ? "true" : "false");
   return s.str();
 }
diff --git a/media/base/audio_decoder_config.h b/media/base/audio_decoder_config.h
index c9c85938..ae72383 100644
--- a/media/base/audio_decoder_config.h
+++ b/media/base/audio_decoder_config.h
@@ -55,22 +55,22 @@
   // appropriate values before using.
   AudioDecoderConfig();
 
-  // Constructs an initialized object. It is acceptable to pass in NULL for
-  // |extra_data|, otherwise the memory is copied.
-  AudioDecoderConfig(AudioCodec codec, SampleFormat sample_format,
-                     ChannelLayout channel_layout, int samples_per_second,
-                     const uint8* extra_data, size_t extra_data_size,
+  // Constructs an initialized object.
+  AudioDecoderConfig(AudioCodec codec,
+                     SampleFormat sample_format,
+                     ChannelLayout channel_layout,
+                     int samples_per_second,
+                     const std::vector<uint8_t>& extra_data,
                      bool is_encrypted);
 
   ~AudioDecoderConfig();
 
-  // Resets the internal state of this object.  |codec_delay| is in frames.
+  // Resets the internal state of this object. |codec_delay| is in frames.
   void Initialize(AudioCodec codec,
                   SampleFormat sample_format,
                   ChannelLayout channel_layout,
                   int samples_per_second,
-                  const uint8* extra_data,
-                  size_t extra_data_size,
+                  const std::vector<uint8>& extra_data,
                   bool is_encrypted,
                   base::TimeDelta seek_preroll,
                   int codec_delay);
@@ -101,10 +101,7 @@
 
   // Optional byte data required to initialize audio decoders such as Vorbis
   // codebooks.
-  const uint8* extra_data() const {
-    return extra_data_.empty() ? NULL : &extra_data_[0];
-  }
-  size_t extra_data_size() const { return extra_data_.size(); }
+  const std::vector<uint8_t>& extra_data() const { return extra_data_; }
 
   // Whether the audio stream is potentially encrypted.
   // Note that in a potentially encrypted audio stream, individual buffers
@@ -118,7 +115,7 @@
   ChannelLayout channel_layout_;
   int samples_per_second_;
   int bytes_per_frame_;
-  std::vector<uint8> extra_data_;
+  std::vector<uint8_t> extra_data_;
   bool is_encrypted_;
 
   // |seek_preroll_| is the duration of the data that the decoder must decode
diff --git a/media/base/fake_demuxer_stream.cc b/media/base/fake_demuxer_stream.cc
index 30ff406f..fab0396 100644
--- a/media/base/fake_demuxer_stream.cc
+++ b/media/base/fake_demuxer_stream.cc
@@ -4,6 +4,8 @@
 
 #include "media/base/fake_demuxer_stream.h"
 
+#include <vector>
+
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/location.h"
@@ -12,6 +14,7 @@
 #include "base/thread_task_runner_handle.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
 #include "media/base/test_helpers.h"
 #include "media/base/timestamp_constants.h"
 #include "media/base/video_frame.h"
@@ -146,7 +149,8 @@
   video_decoder_config_.Initialize(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
                                    PIXEL_FORMAT_YV12, COLOR_SPACE_UNSPECIFIED,
                                    next_coded_size_, kVisibleRect,
-                                   next_coded_size_, NULL, 0, is_encrypted_);
+                                   next_coded_size_, EmptyExtraData(),
+                                   is_encrypted_);
   next_coded_size_.Enlarge(kWidthDelta, kHeightDelta);
 }
 
diff --git a/media/base/media_util.cc b/media/base/media_util.cc
new file mode 100644
index 0000000..bd7929f5
--- /dev/null
+++ b/media/base/media_util.cc
@@ -0,0 +1,13 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/media_util.h"
+
+namespace media {
+
+std::vector<uint8_t> EmptyExtraData() {
+  return std::vector<uint8_t>();
+}
+
+}  // namespace media
diff --git a/media/base/media_util.h b/media/base/media_util.h
new file mode 100644
index 0000000..4e53c9a0
--- /dev/null
+++ b/media/base/media_util.h
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_UTIL_H_
+#define MEDIA_BASE_UTIL_H_
+
+#include <stdint.h>
+#include <vector>
+
+#include "media/base/media_export.h"
+
+namespace media {
+
+// Simply returns an empty vector. {Audio|Video}DecoderConfig are often
+// constructed with empty extra data.
+MEDIA_EXPORT std::vector<uint8_t> EmptyExtraData();
+
+}  // namespace media
+
+#endif  // MEDIA_BASE_UTIL_H_
diff --git a/media/base/test_helpers.cc b/media/base/test_helpers.cc
index 5da16ad..84074bf 100644
--- a/media/base/test_helpers.cc
+++ b/media/base/test_helpers.cc
@@ -15,6 +15,7 @@
 #include "media/base/audio_buffer.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
 #include "ui/gfx/geometry/rect.h"
 
 using ::testing::_;
@@ -127,8 +128,8 @@
 
   return VideoDecoderConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN,
                             PIXEL_FORMAT_YV12, COLOR_SPACE_UNSPECIFIED,
-                            coded_size, visible_rect, natural_size, NULL, 0,
-                            is_encrypted);
+                            coded_size, visible_rect, natural_size,
+                            EmptyExtraData(), is_encrypted);
 }
 
 static const gfx::Size kNormalSize(320, 240);
diff --git a/media/base/video_decoder_config.cc b/media/base/video_decoder_config.cc
index f867ad1..84058e4 100644
--- a/media/base/video_decoder_config.cc
+++ b/media/base/video_decoder_config.cc
@@ -4,6 +4,8 @@
 
 #include "media/base/video_decoder_config.h"
 
+#include <vector>
+
 #include "base/logging.h"
 #include "media/base/video_frame.h"
 
@@ -34,13 +36,11 @@
   return kUnknownVideoCodec;
 }
 
-
 VideoDecoderConfig::VideoDecoderConfig()
     : codec_(kUnknownVideoCodec),
       profile_(VIDEO_CODEC_PROFILE_UNKNOWN),
       format_(PIXEL_FORMAT_UNKNOWN),
-      is_encrypted_(false) {
-}
+      is_encrypted_(false) {}
 
 VideoDecoderConfig::VideoDecoderConfig(VideoCodec codec,
                                        VideoCodecProfile profile,
@@ -49,11 +49,10 @@
                                        const gfx::Size& coded_size,
                                        const gfx::Rect& visible_rect,
                                        const gfx::Size& natural_size,
-                                       const uint8* extra_data,
-                                       size_t extra_data_size,
+                                       const std::vector<uint8_t>& extra_data,
                                        bool is_encrypted) {
   Initialize(codec, profile, format, color_space, coded_size, visible_rect,
-             natural_size, extra_data, extra_data_size, is_encrypted);
+             natural_size, extra_data, is_encrypted);
 }
 
 VideoDecoderConfig::~VideoDecoderConfig() {}
@@ -65,11 +64,8 @@
                                     const gfx::Size& coded_size,
                                     const gfx::Rect& visible_rect,
                                     const gfx::Size& natural_size,
-                                    const uint8* extra_data,
-                                    size_t extra_data_size,
+                                    const std::vector<uint8_t>& extra_data,
                                     bool is_encrypted) {
-  CHECK((extra_data_size != 0) == (extra_data != NULL));
-
   codec_ = codec;
   profile_ = profile;
   format_ = format;
@@ -77,7 +73,7 @@
   coded_size_ = coded_size;
   visible_rect_ = visible_rect;
   natural_size_ = natural_size;
-  extra_data_.assign(extra_data, extra_data + extra_data_size);
+  extra_data_ = extra_data;
   is_encrypted_ = is_encrypted;
 }
 
@@ -96,9 +92,7 @@
           (coded_size() == config.coded_size()) &&
           (visible_rect() == config.visible_rect()) &&
           (natural_size() == config.natural_size()) &&
-          (extra_data_size() == config.extra_data_size()) &&
-          (!extra_data() || !memcmp(extra_data(), config.extra_data(),
-                                    extra_data_size())) &&
+          (extra_data() == config.extra_data()) &&
           (is_encrypted() == config.is_encrypted()));
 }
 
@@ -115,7 +109,7 @@
     << "," << visible_rect().height() << "]"
     << " natural size: [" << natural_size().width()
     << "," << natural_size().height() << "]"
-    << " has extra data? " << (extra_data() ? "true" : "false")
+    << " has extra data? " << (extra_data().empty() ? "false" : "true")
     << " encrypted? " << (is_encrypted() ? "true" : "false");
   return s.str();
 }
@@ -146,10 +140,4 @@
   return "";
 }
 
-const uint8* VideoDecoderConfig::extra_data() const {
-  if (extra_data_.empty())
-    return NULL;
-  return &extra_data_[0];
-}
-
 }  // namespace media
diff --git a/media/base/video_decoder_config.h b/media/base/video_decoder_config.h
index 0dae77c8..3de0d2f 100644
--- a/media/base/video_decoder_config.h
+++ b/media/base/video_decoder_config.h
@@ -35,8 +35,7 @@
                      const gfx::Size& coded_size,
                      const gfx::Rect& visible_rect,
                      const gfx::Size& natural_size,
-                     const uint8* extra_data,
-                     size_t extra_data_size,
+                     const std::vector<uint8_t>& extra_data,
                      bool is_encrypted);
 
   ~VideoDecoderConfig();
@@ -49,8 +48,7 @@
                   const gfx::Size& coded_size,
                   const gfx::Rect& visible_rect,
                   const gfx::Size& natural_size,
-                  const uint8* extra_data,
-                  size_t extra_data_size,
+                  const std::vector<uint8_t>& extra_data,
                   bool is_encrypted);
 
   // Returns true if this object has appropriate configuration values, false
@@ -91,8 +89,7 @@
 
   // Optional byte data required to initialize video decoders, such as H.264
   // AAVC data.
-  const uint8* extra_data() const;
-  size_t extra_data_size() const { return extra_data_.size(); }
+  const std::vector<uint8_t>& extra_data() const { return extra_data_; }
 
   // Whether the video stream is potentially encrypted.
   // Note that in a potentially encrypted video stream, individual buffers
@@ -110,7 +107,7 @@
   gfx::Rect visible_rect_;
   gfx::Size natural_size_;
 
-  std::vector<uint8> extra_data_;
+  std::vector<uint8_t> extra_data_;
 
   bool is_encrypted_;
 
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index e6d5e91..c9d86696 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -6,6 +6,7 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
@@ -285,7 +286,7 @@
   return AV_SAMPLE_FMT_NONE;
 }
 
-void AVCodecContextToAudioDecoderConfig(const AVCodecContext* codec_context,
+bool AVCodecContextToAudioDecoderConfig(const AVCodecContext* codec_context,
                                         bool is_encrypted,
                                         AudioDecoderConfig* config) {
   DCHECK_EQ(codec_context->codec_type, AVMEDIA_TYPE_AUDIO);
@@ -319,12 +320,26 @@
         codec_context->seek_preroll * 1000000.0 / codec_context->sample_rate);
   }
 
+  // AVStream occasionally has invalid extra data. See http://crbug.com/517163
+  if ((codec_context->extradata_size == 0) !=
+      (codec_context->extradata == nullptr)) {
+    LOG(ERROR) << __FUNCTION__
+               << (codec_context->extradata == nullptr ? " NULL" : " Non-NULL")
+               << " extra data cannot have size of "
+               << codec_context->extradata_size << ".";
+    return false;
+  }
+
+  std::vector<uint8_t> extra_data;
+  if (codec_context->extradata_size > 0) {
+    extra_data.assign(codec_context->extradata,
+                      codec_context->extradata + codec_context->extradata_size);
+  }
   config->Initialize(codec,
                      sample_format,
                      channel_layout,
                      sample_rate,
-                     codec_context->extradata,
-                     codec_context->extradata_size,
+                     extra_data,
                      is_encrypted,
                      seek_preroll,
                      codec_context->delay);
@@ -333,15 +348,19 @@
     DCHECK_EQ(av_get_bytes_per_sample(codec_context->sample_fmt) * 8,
               config->bits_per_channel());
   }
+
+  return true;
 }
 
-void AVStreamToAudioDecoderConfig(const AVStream* stream,
+bool AVStreamToAudioDecoderConfig(const AVStream* stream,
                                   AudioDecoderConfig* config) {
   bool is_encrypted = false;
-  AVDictionaryEntry* key = av_dict_get(stream->metadata, "enc_key_id", NULL, 0);
+  AVDictionaryEntry* key =
+      av_dict_get(stream->metadata, "enc_key_id", nullptr, 0);
   if (key)
     is_encrypted = true;
-  AVCodecContextToAudioDecoderConfig(stream->codec, is_encrypted, config);
+  return AVCodecContextToAudioDecoderConfig(stream->codec, is_encrypted,
+                                            config);
 }
 
 void AudioDecoderConfigToAVCodecContext(const AudioDecoderConfig& config,
@@ -358,21 +377,21 @@
       ChannelLayoutToChannelCount(config.channel_layout());
   codec_context->sample_rate = config.samples_per_second();
 
-  if (config.extra_data()) {
-    codec_context->extradata_size = config.extra_data_size();
-    codec_context->extradata = reinterpret_cast<uint8_t*>(
-        av_malloc(config.extra_data_size() + FF_INPUT_BUFFER_PADDING_SIZE));
-    memcpy(codec_context->extradata, config.extra_data(),
-           config.extra_data_size());
-    memset(codec_context->extradata + config.extra_data_size(), '\0',
-           FF_INPUT_BUFFER_PADDING_SIZE);
-  } else {
-    codec_context->extradata = NULL;
+  if (config.extra_data().empty()) {
+    codec_context->extradata = nullptr;
     codec_context->extradata_size = 0;
+  } else {
+    codec_context->extradata_size = config.extra_data().size();
+    codec_context->extradata = reinterpret_cast<uint8_t*>(
+        av_malloc(config.extra_data().size() + FF_INPUT_BUFFER_PADDING_SIZE));
+    memcpy(codec_context->extradata, &config.extra_data()[0],
+           config.extra_data().size());
+    memset(codec_context->extradata + config.extra_data().size(), '\0',
+           FF_INPUT_BUFFER_PADDING_SIZE);
   }
 }
 
-void AVStreamToVideoDecoderConfig(const AVStream* stream,
+bool AVStreamToVideoDecoderConfig(const AVStream* stream,
                                   VideoDecoderConfig* config) {
   gfx::Size coded_size(stream->codec->coded_width, stream->codec->coded_height);
 
@@ -433,12 +452,13 @@
   }
 
   bool is_encrypted = false;
-  AVDictionaryEntry* key = av_dict_get(stream->metadata, "enc_key_id", NULL, 0);
+  AVDictionaryEntry* key =
+      av_dict_get(stream->metadata, "enc_key_id", nullptr, 0);
   if (key)
     is_encrypted = true;
 
   AVDictionaryEntry* webm_alpha =
-      av_dict_get(stream->metadata, "alpha_mode", NULL, 0);
+      av_dict_get(stream->metadata, "alpha_mode", nullptr, 0);
   if (webm_alpha && !strcmp(webm_alpha->value, "1")) {
     format = PIXEL_FORMAT_YV12A;
   }
@@ -453,9 +473,24 @@
                                                 : COLOR_SPACE_HD_REC709;
   }
 
+  // AVStream occasionally has invalid extra data. See http://crbug.com/517163
+  if ((stream->codec->extradata_size == 0) !=
+      (stream->codec->extradata == nullptr)) {
+    LOG(ERROR) << __FUNCTION__
+               << (stream->codec->extradata == nullptr ? " NULL" : " Non-Null")
+               << " extra data cannot have size of "
+               << stream->codec->extradata_size << ".";
+    return false;
+  }
+
+  std::vector<uint8_t> extra_data;
+  if (stream->codec->extradata_size > 0) {
+    extra_data.assign(stream->codec->extradata,
+                      stream->codec->extradata + stream->codec->extradata_size);
+  }
   config->Initialize(codec, profile, format, color_space, coded_size,
-                     visible_rect, natural_size, stream->codec->extradata,
-                     stream->codec->extradata_size, is_encrypted);
+                     visible_rect, natural_size, extra_data, is_encrypted);
+  return true;
 }
 
 void VideoDecoderConfigToAVCodecContext(
@@ -470,17 +505,17 @@
   if (config.color_space() == COLOR_SPACE_JPEG)
     codec_context->color_range = AVCOL_RANGE_JPEG;
 
-  if (config.extra_data()) {
-    codec_context->extradata_size = config.extra_data_size();
-    codec_context->extradata = reinterpret_cast<uint8_t*>(
-        av_malloc(config.extra_data_size() + FF_INPUT_BUFFER_PADDING_SIZE));
-    memcpy(codec_context->extradata, config.extra_data(),
-           config.extra_data_size());
-    memset(codec_context->extradata + config.extra_data_size(), '\0',
-           FF_INPUT_BUFFER_PADDING_SIZE);
-  } else {
-    codec_context->extradata = NULL;
+  if (config.extra_data().empty()) {
+    codec_context->extradata = nullptr;
     codec_context->extradata_size = 0;
+  } else {
+    codec_context->extradata_size = config.extra_data().size();
+    codec_context->extradata = reinterpret_cast<uint8_t*>(
+        av_malloc(config.extra_data().size() + FF_INPUT_BUFFER_PADDING_SIZE));
+    memcpy(codec_context->extradata, &config.extra_data()[0],
+           config.extra_data().size());
+    memset(codec_context->extradata + config.extra_data().size(), '\0',
+           FF_INPUT_BUFFER_PADDING_SIZE);
   }
 }
 
diff --git a/media/ffmpeg/ffmpeg_common.h b/media/ffmpeg/ffmpeg_common.h
index 677bd761..f4a8237 100644
--- a/media/ffmpeg/ffmpeg_common.h
+++ b/media/ffmpeg/ffmpeg_common.h
@@ -85,19 +85,26 @@
 MEDIA_EXPORT int64 ConvertToTimeBase(const AVRational& time_base,
                                      const base::TimeDelta& timestamp);
 
-void AVStreamToAudioDecoderConfig(const AVStream* stream,
-                                  AudioDecoderConfig* config);
+// Returns true if AVStream is successfully converted to a AudioDecoderConfig.
+// Returns false if conversion fails, in which case |config| is not modified.
+MEDIA_EXPORT bool AVStreamToAudioDecoderConfig(const AVStream* stream,
+                                               AudioDecoderConfig* config);
 void AudioDecoderConfigToAVCodecContext(
     const AudioDecoderConfig& config,
     AVCodecContext* codec_context);
 
-void AVStreamToVideoDecoderConfig(const AVStream* stream,
-                                  VideoDecoderConfig* config);
+// Returns true if AVStream is successfully converted to a VideoDecoderConfig.
+// Returns false if conversion fails, in which case |config| is not modified.
+MEDIA_EXPORT bool AVStreamToVideoDecoderConfig(const AVStream* stream,
+                                               VideoDecoderConfig* config);
 void VideoDecoderConfigToAVCodecContext(
     const VideoDecoderConfig& config,
     AVCodecContext* codec_context);
 
-MEDIA_EXPORT void AVCodecContextToAudioDecoderConfig(
+// Returns true if AVCodecContext is successfully converted to an
+// AudioDecoderConfig. Returns false if conversion fails, in which case |config|
+// is not modified.
+MEDIA_EXPORT bool AVCodecContextToAudioDecoderConfig(
     const AVCodecContext* codec_context,
     bool is_encrypted,
     AudioDecoderConfig* config);
diff --git a/media/ffmpeg/ffmpeg_common_unittest.cc b/media/ffmpeg/ffmpeg_common_unittest.cc
index ca68fa7..aa8a06d9 100644
--- a/media/ffmpeg/ffmpeg_common_unittest.cc
+++ b/media/ffmpeg/ffmpeg_common_unittest.cc
@@ -2,11 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <cstring>
+
+#include "base/bind.h"
+#include "base/files/memory_mapped_file.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "media/base/audio_decoder_config.h"
 #include "media/base/media.h"
+#include "media/base/test_data_util.h"
+#include "media/base/video_decoder_config.h"
 #include "media/ffmpeg/ffmpeg_common.h"
 #include "media/filters/ffmpeg_glue.h"
+#include "media/filters/in_memory_url_protocol.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace media {
@@ -19,6 +27,97 @@
   ~FFmpegCommonTest() override{};
 };
 
+uint8_t kExtraData[5] = {0x00, 0x01, 0x02, 0x03, 0x04};
+
+template <typename T>
+void TestConfigConvertExtraData(
+    AVStream* stream,
+    T* decoder_config,
+    const base::Callback<bool(const AVStream*, T*)>& converter_fn) {
+  // Should initially convert.
+  EXPECT_TRUE(converter_fn.Run(stream, decoder_config));
+
+  // Store orig to let FFmpeg free whatever it allocated.
+  AVCodecContext* codec_context = stream->codec;
+  uint8_t* orig_extradata = codec_context->extradata;
+  int orig_extradata_size = codec_context->extradata_size;
+
+  // Valid combination: extra_data = NULL && size = 0.
+  codec_context->extradata = NULL;
+  codec_context->extradata_size = 0;
+  EXPECT_TRUE(converter_fn.Run(stream, decoder_config));
+  EXPECT_EQ(static_cast<size_t>(codec_context->extradata_size),
+            decoder_config->extra_data().size());
+
+  // Valid combination: extra_data = non-NULL && size > 0.
+  codec_context->extradata = &kExtraData[0];
+  codec_context->extradata_size = arraysize(kExtraData);
+  EXPECT_TRUE(converter_fn.Run(stream, decoder_config));
+  EXPECT_EQ(static_cast<size_t>(codec_context->extradata_size),
+            decoder_config->extra_data().size());
+  EXPECT_EQ(0, memcmp(codec_context->extradata,
+                      &decoder_config->extra_data()[0],
+                      decoder_config->extra_data().size()));
+
+  // Invalid combination: extra_data = NULL && size != 0.
+  codec_context->extradata = NULL;
+  codec_context->extradata_size = 10;
+  EXPECT_FALSE(converter_fn.Run(stream, decoder_config));
+
+  // Invalid combination: extra_data = non-NULL && size = 0.
+  codec_context->extradata = &kExtraData[0];
+  codec_context->extradata_size = 0;
+  EXPECT_FALSE(converter_fn.Run(stream, decoder_config));
+
+  // Restore orig values for sane cleanup.
+  codec_context->extradata = orig_extradata;
+  codec_context->extradata_size = orig_extradata_size;
+}
+
+TEST_F(FFmpegCommonTest, AVStreamToDecoderConfig) {
+  // Open a file to get a real AVStreams from FFmpeg.
+  base::MemoryMappedFile file;
+  file.Initialize(GetTestDataFilePath("bear-320x240.webm"));
+  InMemoryUrlProtocol protocol(file.data(), file.length(), false);
+  FFmpegGlue glue(&protocol);
+  ASSERT_TRUE(glue.OpenContext());
+  AVFormatContext* format_context = glue.format_context();
+
+  // Find the audio and video streams and test valid and invalid combinations
+  // for extradata and extradata_size.
+  bool found_audio = false;
+  bool found_video = false;
+  for (size_t i = 0;
+       i < format_context->nb_streams && (!found_audio || !found_video);
+       ++i) {
+    AVStream* stream = format_context->streams[i];
+    AVCodecContext* codec_context = stream->codec;
+    AVMediaType codec_type = codec_context->codec_type;
+
+    if (codec_type == AVMEDIA_TYPE_AUDIO) {
+      if (found_audio)
+        continue;
+      found_audio = true;
+      AudioDecoderConfig audio_config;
+      TestConfigConvertExtraData(stream, &audio_config,
+                                 base::Bind(&AVStreamToAudioDecoderConfig));
+    } else if (codec_type == AVMEDIA_TYPE_VIDEO) {
+      if (found_video)
+        continue;
+      found_video = true;
+      VideoDecoderConfig video_config;
+      TestConfigConvertExtraData(stream, &video_config,
+                                 base::Bind(&AVStreamToVideoDecoderConfig));
+    } else {
+      // Only process audio/video.
+      continue;
+    }
+  }
+
+  ASSERT_TRUE(found_audio);
+  ASSERT_TRUE(found_video);
+}
+
 TEST_F(FFmpegCommonTest, OpusAudioDecoderConfig) {
   AVCodecContext context = {0};
   context.codec_type = AVMEDIA_TYPE_AUDIO;
@@ -31,7 +130,8 @@
   context.sample_rate = 44100;
 
   AudioDecoderConfig decoder_config;
-  AVCodecContextToAudioDecoderConfig(&context, false, &decoder_config);
+  ASSERT_TRUE(AVCodecContextToAudioDecoderConfig(&context, false,
+                                                 &decoder_config));
   EXPECT_EQ(48000, decoder_config.samples_per_second());
 }
 
diff --git a/media/filters/audio_decoder_selector_unittest.cc b/media/filters/audio_decoder_selector_unittest.cc
index 7b58a743..2b7f390 100644
--- a/media/filters/audio_decoder_selector_unittest.cc
+++ b/media/filters/audio_decoder_selector_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
 #include "media/base/gmock_callback_support.h"
+#include "media/base/media_util.h"
 #include "media/base/mock_filters.h"
 #include "media/base/test_helpers.h"
 #include "media/filters/decoder_selector.h"
@@ -77,16 +78,16 @@
   }
 
   void UseClearStream() {
-    AudioDecoderConfig clear_audio_config(
-        kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
-        NULL, 0, false);
+    AudioDecoderConfig clear_audio_config(kCodecVorbis, kSampleFormatPlanarF32,
+                                          CHANNEL_LAYOUT_STEREO, 44100,
+                                          EmptyExtraData(), false);
     demuxer_stream_->set_audio_decoder_config(clear_audio_config);
   }
 
   void UseEncryptedStream() {
     AudioDecoderConfig encrypted_audio_config(
         kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
-        NULL, 0, true);
+        EmptyExtraData(), true);
     demuxer_stream_->set_audio_decoder_config(encrypted_audio_config);
   }
 
diff --git a/media/filters/audio_decoder_unittest.cc b/media/filters/audio_decoder_unittest.cc
index 83c2ea5..3ee51f40 100644
--- a/media/filters/audio_decoder_unittest.cc
+++ b/media/filters/audio_decoder_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <deque>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/format_macros.h"
@@ -16,6 +17,7 @@
 #include "media/base/audio_bus.h"
 #include "media/base/audio_hash.h"
 #include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
 #include "media/base/test_data_util.h"
 #include "media/base/test_helpers.h"
 #include "media/base/timestamp_constants.h"
@@ -151,8 +153,8 @@
     ASSERT_TRUE(reader_->SeekForTesting(start_timestamp_));
 
     AudioDecoderConfig config;
-    AVCodecContextToAudioDecoderConfig(reader_->codec_context_for_testing(),
-                                       false, &config);
+    ASSERT_TRUE(AVCodecContextToAudioDecoderConfig(
+        reader_->codec_context_for_testing(), false, &config));
 
     EXPECT_EQ(GetParam().codec, config.codec());
     EXPECT_EQ(GetParam().samples_per_second, config.samples_per_second());
@@ -374,13 +376,15 @@
 
 TEST_P(OpusAudioDecoderBehavioralTest, InitializeWithNoCodecDelay) {
   ASSERT_EQ(GetParam().decoder_type, OPUS);
+  std::vector<uint8_t> extra_data(
+      kOpusExtraData,
+      kOpusExtraData + arraysize(kOpusExtraData));
   AudioDecoderConfig decoder_config;
   decoder_config.Initialize(kCodecOpus,
                             kSampleFormatF32,
                             CHANNEL_LAYOUT_STEREO,
                             48000,
-                            kOpusExtraData,
-                            arraysize(kOpusExtraData),
+                            extra_data,
                             false,
                             base::TimeDelta::FromMilliseconds(80),
                             0);
@@ -389,14 +393,16 @@
 
 TEST_P(OpusAudioDecoderBehavioralTest, InitializeWithBadCodecDelay) {
   ASSERT_EQ(GetParam().decoder_type, OPUS);
+  std::vector<uint8_t> extra_data(
+      kOpusExtraData,
+      kOpusExtraData + arraysize(kOpusExtraData));
   AudioDecoderConfig decoder_config;
   decoder_config.Initialize(
       kCodecOpus,
       kSampleFormatF32,
       CHANNEL_LAYOUT_STEREO,
       48000,
-      kOpusExtraData,
-      arraysize(kOpusExtraData),
+      extra_data,
       false,
       base::TimeDelta::FromMilliseconds(80),
       // Use a different codec delay than in the extradata.
@@ -410,8 +416,7 @@
                                           CHANNEL_LAYOUT_STEREO,
                                           // Invalid sample rate of zero.
                                           0,
-                                          NULL,
-                                          0,
+                                          EmptyExtraData(),
                                           false);
   InitializeDecoderWithResult(decoder_config, false);
 }
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index 747e512..1b6b8943 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -736,8 +736,8 @@
   // bear-320x240.webm : [0-501)       [801-2736)
   // bear-640x360.webm :       [527-793)
   //
-  // bear-320x240.webm AudioDecoderConfig returns 3863 for its extra_data_size()
-  // bear-640x360.webm AudioDecoderConfig returns 3935 for its extra_data_size()
+  // bear-320x240.webm AudioDecoderConfig returns 3863 for its extra_data size.
+  // bear-640x360.webm AudioDecoderConfig returns 3935 for its extra_data size.
   // The resulting audio stream returns data from each file for the following
   // time ranges.
   // bear-320x240.webm : [0-524)       [779-2736)
@@ -1247,8 +1247,7 @@
       EXPECT_EQ(32, config.bits_per_channel());
       EXPECT_EQ(CHANNEL_LAYOUT_STEREO, config.channel_layout());
       EXPECT_EQ(44100, config.samples_per_second());
-      EXPECT_TRUE(config.extra_data());
-      EXPECT_GT(config.extra_data_size(), 0u);
+      EXPECT_GT(config.extra_data().size(), 0u);
       EXPECT_EQ(kSampleFormatPlanarF32, config.sample_format());
       EXPECT_EQ(is_audio_encrypted,
                 audio_stream->audio_decoder_config().is_encrypted());
@@ -1317,8 +1316,7 @@
       EXPECT_EQ(32, config.bits_per_channel());
       EXPECT_EQ(CHANNEL_LAYOUT_STEREO, config.channel_layout());
       EXPECT_EQ(44100, config.samples_per_second());
-      EXPECT_TRUE(config.extra_data());
-      EXPECT_GT(config.extra_data_size(), 0u);
+      EXPECT_GT(config.extra_data().size(), 0u);
       EXPECT_EQ(kSampleFormatPlanarF32, config.sample_format());
       EXPECT_EQ(is_audio_encrypted,
                 audio_stream->audio_decoder_config().is_encrypted());
@@ -2887,7 +2885,7 @@
   const AudioDecoderConfig& audio_config_1 = audio->audio_decoder_config();
   ASSERT_TRUE(audio_config_1.IsValidConfig());
   EXPECT_EQ(audio_config_1.samples_per_second(), 44100);
-  EXPECT_EQ(audio_config_1.extra_data_size(), 3863u);
+  EXPECT_EQ(audio_config_1.extra_data().size(), 3863u);
 
   ExpectRead(DemuxerStream::AUDIO, 0);
 
@@ -2901,7 +2899,7 @@
   const AudioDecoderConfig& audio_config_2 = audio->audio_decoder_config();
   ASSERT_TRUE(audio_config_2.IsValidConfig());
   EXPECT_EQ(audio_config_2.samples_per_second(), 44100);
-  EXPECT_EQ(audio_config_2.extra_data_size(), 3935u);
+  EXPECT_EQ(audio_config_2.extra_data().size(), 3935u);
 
   // The next config change is from a splice frame representing an overlap of
   // buffers from config 2 by buffers from config 1.
diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc
index d6ef2b9..4f749cea 100644
--- a/media/filters/decrypting_audio_decoder_unittest.cc
+++ b/media/filters/decrypting_audio_decoder_unittest.cc
@@ -12,6 +12,7 @@
 #include "media/base/decoder_buffer.h"
 #include "media/base/decrypt_config.h"
 #include "media/base/gmock_callback_support.h"
+#include "media/base/media_util.h"
 #include "media/base/mock_filters.h"
 #include "media/base/test_helpers.h"
 #include "media/base/timestamp_constants.h"
@@ -118,8 +119,8 @@
         .WillOnce(SaveArg<1>(&key_added_cb_));
 
     config_.Initialize(kCodecVorbis, kSampleFormatPlanarF32,
-                       CHANNEL_LAYOUT_STEREO, kSampleRate, NULL, 0, true,
-                       base::TimeDelta(), 0);
+                       CHANNEL_LAYOUT_STEREO, kSampleRate, EmptyExtraData(),
+                       true, base::TimeDelta(), 0);
     InitializeAndExpectResult(config_, true);
   }
 
@@ -287,7 +288,8 @@
 // Ensure that DecryptingAudioDecoder only accepts encrypted audio.
 TEST_F(DecryptingAudioDecoderTest, Initialize_UnencryptedAudioConfig) {
   AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
-                            CHANNEL_LAYOUT_STEREO, kSampleRate, NULL, 0, false);
+                            CHANNEL_LAYOUT_STEREO, kSampleRate,
+                            EmptyExtraData(), false);
 
   InitializeAndExpectResult(config, false);
 }
@@ -295,7 +297,7 @@
 // Ensure decoder handles invalid audio configs without crashing.
 TEST_F(DecryptingAudioDecoderTest, Initialize_InvalidAudioConfig) {
   AudioDecoderConfig config(kUnknownAudioCodec, kUnknownSampleFormat,
-                            CHANNEL_LAYOUT_STEREO, 0, NULL, 0, true);
+                            CHANNEL_LAYOUT_STEREO, 0, EmptyExtraData(), true);
 
   InitializeAndExpectResult(config, false);
 }
@@ -307,14 +309,16 @@
   ExpectDecryptorNotification(decryptor_.get(), true);
 
   AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
-                            CHANNEL_LAYOUT_STEREO, kSampleRate, NULL, 0, true);
+                            CHANNEL_LAYOUT_STEREO, kSampleRate,
+                            EmptyExtraData(), true);
   InitializeAndExpectResult(config, false);
 }
 
 TEST_F(DecryptingAudioDecoderTest, Initialize_NullDecryptor) {
   ExpectDecryptorNotification(NULL, false);
   AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
-                            CHANNEL_LAYOUT_STEREO, kSampleRate, NULL, 0, true);
+                            CHANNEL_LAYOUT_STEREO, kSampleRate,
+                            EmptyExtraData(), true);
   InitializeAndExpectResult(config, false);
 }
 
@@ -382,7 +386,8 @@
   // The new config is different from the initial config in bits-per-channel,
   // channel layout and samples_per_second.
   AudioDecoderConfig new_config(kCodecVorbis, kSampleFormatPlanarS16,
-                                CHANNEL_LAYOUT_5_1, 88200, NULL, 0, true);
+                                CHANNEL_LAYOUT_5_1, 88200, EmptyExtraData(),
+                                true);
   EXPECT_NE(new_config.bits_per_channel(), config_.bits_per_channel());
   EXPECT_NE(new_config.channel_layout(), config_.channel_layout());
   EXPECT_NE(new_config.samples_per_second(), config_.samples_per_second());
diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc
index ff98122..3e67a29c 100644
--- a/media/filters/decrypting_demuxer_stream.cc
+++ b/media/filters/decrypting_demuxer_stream.cc
@@ -385,7 +385,6 @@
                                input_audio_config.channel_layout(),
                                input_audio_config.samples_per_second(),
                                input_audio_config.extra_data(),
-                               input_audio_config.extra_data_size(),
                                false,  // Output audio is not encrypted.
                                input_audio_config.seek_preroll(),
                                input_audio_config.codec_delay());
@@ -400,7 +399,6 @@
           input_video_config.format(), input_video_config.color_space(),
           input_video_config.coded_size(), input_video_config.visible_rect(),
           input_video_config.natural_size(), input_video_config.extra_data(),
-          input_video_config.extra_data_size(),
           false);  // Output video is not encrypted.
       break;
     }
diff --git a/media/filters/decrypting_demuxer_stream_unittest.cc b/media/filters/decrypting_demuxer_stream_unittest.cc
index e5a8f4b0..c679b56 100644
--- a/media/filters/decrypting_demuxer_stream_unittest.cc
+++ b/media/filters/decrypting_demuxer_stream_unittest.cc
@@ -11,6 +11,7 @@
 #include "media/base/decoder_buffer.h"
 #include "media/base/decrypt_config.h"
 #include "media/base/gmock_callback_support.h"
+#include "media/base/media_util.h"
 #include "media/base/mock_filters.h"
 #include "media/base/test_helpers.h"
 #include "media/filters/decrypting_demuxer_stream.h"
@@ -134,9 +135,9 @@
     EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kAudio, _))
         .WillOnce(SaveArg<1>(&key_added_cb_));
 
-    AudioDecoderConfig input_config(
-        kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
-        NULL, 0, true);
+    AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32,
+                                    CHANNEL_LAYOUT_STEREO, 44100,
+                                    EmptyExtraData(), true);
     InitializeAudioAndExpectStatus(input_config, PIPELINE_OK);
 
     const AudioDecoderConfig& output_config =
@@ -309,18 +310,14 @@
   EXPECT_EQ(input_config.coded_size(), output_config.coded_size());
   EXPECT_EQ(input_config.visible_rect(), output_config.visible_rect());
   EXPECT_EQ(input_config.natural_size(), output_config.natural_size());
-  ASSERT_EQ(input_config.extra_data_size(), output_config.extra_data_size());
-  if (input_config.extra_data_size() > 0) {
-    EXPECT_FALSE(output_config.extra_data());
-    EXPECT_EQ(0, memcmp(output_config.extra_data(), input_config.extra_data(),
-                        input_config.extra_data_size()));
-  }
+  ASSERT_EQ(input_config.extra_data(), output_config.extra_data());
 }
 
 TEST_F(DecryptingDemuxerStreamTest, Initialize_NullDecryptor) {
   ExpectDecryptorNotification(NULL, false);
   AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32,
-                                  CHANNEL_LAYOUT_STEREO, 44100, NULL, 0, true);
+                                  CHANNEL_LAYOUT_STEREO, 44100,
+                                  EmptyExtraData(), true);
   InitializeAudioAndExpectStatus(input_config, DECODER_ERROR_NOT_SUPPORTED);
 }
 
@@ -394,9 +391,9 @@
   // One for decryptor request, one for canceling request during Reset().
   EXPECT_CALL(*this, RequestDecryptorNotification(_))
       .Times(2);
-  AudioDecoderConfig input_config(
-      kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
-      NULL, 0, true);
+  AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32,
+                                  CHANNEL_LAYOUT_STEREO, 44100,
+                                  EmptyExtraData(), true);
   InitializeAudioAndExpectStatus(input_config, PIPELINE_ERROR_ABORT);
   Reset();
 }
@@ -482,9 +479,9 @@
 TEST_F(DecryptingDemuxerStreamTest, DemuxerRead_ConfigChanged) {
   Initialize();
 
-  AudioDecoderConfig new_config(
-      kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 88200, NULL,
-      0, true);
+  AudioDecoderConfig new_config(kCodecVorbis, kSampleFormatPlanarF32,
+                                CHANNEL_LAYOUT_STEREO, 88200, EmptyExtraData(),
+                                true);
   input_audio_stream_->set_audio_decoder_config(new_config);
 
   EXPECT_CALL(*input_audio_stream_, Read(_))
@@ -515,9 +512,9 @@
   // One for decryptor request, one for canceling request during Reset().
   EXPECT_CALL(*this, RequestDecryptorNotification(_))
       .Times(2);
-  AudioDecoderConfig input_config(
-      kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
-      NULL, 0, true);
+  AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32,
+                                  CHANNEL_LAYOUT_STEREO, 44100,
+                                  EmptyExtraData(), true);
   InitializeAudioAndExpectStatus(input_config, PIPELINE_ERROR_ABORT);
 }
 
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index 155e980..c06dd29 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -172,14 +172,58 @@
   return HashCodecName("none");
 }
 
+scoped_ptr<FFmpegDemuxerStream> FFmpegDemuxerStream::Create(
+    FFmpegDemuxer* demuxer,
+    AVStream* stream) {
+  if (!demuxer || !stream)
+    return nullptr;
+
+  scoped_ptr<FFmpegDemuxerStream> demuxer_stream;
+  scoped_ptr<AudioDecoderConfig> audio_config;
+  scoped_ptr<VideoDecoderConfig> video_config;
+
+  if (stream->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+    audio_config.reset(new AudioDecoderConfig());
+
+    // IsValidConfig() checks that the codec is supported and that the channel
+    // layout and sample format are valid.
+    //
+    // TODO(chcunningham): Change AVStreamToAudioDecoderConfig to check
+    // IsValidConfig internally and return a null scoped_ptr if not valid.
+    if (!AVStreamToAudioDecoderConfig(stream, audio_config.get()) ||
+        !audio_config->IsValidConfig())
+      return nullptr;
+
+  } else if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+    video_config.reset(new VideoDecoderConfig());
+
+    // IsValidConfig() checks that the codec is supported and that the channel
+    // layout and sample format are valid.
+    //
+    // TODO(chcunningham): Change AVStreamToVideoDecoderConfig to check
+    // IsValidConfig internally and return a null scoped_ptr if not valid.
+    if (!AVStreamToVideoDecoderConfig(stream, video_config.get()) ||
+        !video_config->IsValidConfig())
+      return nullptr;
+  }
+
+  return make_scoped_ptr(new FFmpegDemuxerStream(
+      demuxer, stream, audio_config.Pass(), video_config.Pass()));
+}
+
 //
 // FFmpegDemuxerStream
 //
-FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer,
-                                         AVStream* stream)
+FFmpegDemuxerStream::FFmpegDemuxerStream(
+    FFmpegDemuxer* demuxer,
+    AVStream* stream,
+    scoped_ptr<AudioDecoderConfig> audio_config,
+    scoped_ptr<VideoDecoderConfig> video_config)
     : demuxer_(demuxer),
       task_runner_(base::ThreadTaskRunnerHandle::Get()),
       stream_(stream),
+      audio_config_(audio_config.release()),
+      video_config_(video_config.release()),
       type_(UNKNOWN),
       liveness_(LIVENESS_UNKNOWN),
       end_of_stream_(false),
@@ -196,14 +240,14 @@
   // Determine our media format.
   switch (stream->codec->codec_type) {
     case AVMEDIA_TYPE_AUDIO:
+      DCHECK(audio_config_.get() && !video_config_.get());
       type_ = AUDIO;
-      AVStreamToAudioDecoderConfig(stream, &audio_config_);
-      is_encrypted = audio_config_.is_encrypted();
+      is_encrypted = audio_config_->is_encrypted();
       break;
     case AVMEDIA_TYPE_VIDEO:
+      DCHECK(video_config_.get() && !audio_config_.get());
       type_ = VIDEO;
-      AVStreamToVideoDecoderConfig(stream, &video_config_);
-      is_encrypted = video_config_.is_encrypted();
+      is_encrypted = video_config_->is_encrypted();
 
       rotation_entry = av_dict_get(stream->metadata, "rotate", NULL, 0);
       if (rotation_entry && rotation_entry->value && rotation_entry->value[0])
@@ -228,6 +272,7 @@
 
       break;
     case AVMEDIA_TYPE_SUBTITLE:
+      DCHECK(!video_config_.get() && !audio_config_.get());
       type_ = TEXT;
       break;
     default:
@@ -315,8 +360,8 @@
 
     scoped_ptr<DecryptConfig> decrypt_config;
     int data_offset = 0;
-    if ((type() == DemuxerStream::AUDIO && audio_config_.is_encrypted()) ||
-        (type() == DemuxerStream::VIDEO && video_config_.is_encrypted())) {
+    if ((type() == DemuxerStream::AUDIO && audio_config_->is_encrypted()) ||
+        (type() == DemuxerStream::VIDEO && video_config_->is_encrypted())) {
       if (!WebMCreateDecryptConfig(
           packet->data, packet->size,
           reinterpret_cast<const uint8*>(encryption_key_id_.data()),
@@ -580,14 +625,16 @@
 
 AudioDecoderConfig FFmpegDemuxerStream::audio_decoder_config() {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  CHECK_EQ(type_, AUDIO);
-  return audio_config_;
+  DCHECK_EQ(type_, AUDIO);
+  DCHECK(audio_config_.get());
+  return *audio_config_;
 }
 
 VideoDecoderConfig FFmpegDemuxerStream::video_decoder_config() {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  CHECK_EQ(type_, VIDEO);
-  return video_config_;
+  DCHECK_EQ(type_, VIDEO);
+  DCHECK(video_config_.get());
+  return *video_config_;
 }
 
 VideoRotation FFmpegDemuxerStream::video_rotation() {
@@ -987,7 +1034,6 @@
 
   AVStream* audio_stream = NULL;
   AudioDecoderConfig audio_config;
-
   AVStream* video_stream = NULL;
   VideoDecoderConfig video_config;
 
@@ -1007,13 +1053,6 @@
       // Log the codec detected, whether it is supported or not.
       UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedAudioCodecHash",
                                   GetCodecHash(codec_context));
-
-      // Ensure the codec is supported. IsValidConfig() also checks that the
-      // channel layout and sample format are valid.
-      AVStreamToAudioDecoderConfig(stream, &audio_config);
-      if (!audio_config.IsValidConfig())
-        continue;
-      audio_stream = stream;
     } else if (codec_type == AVMEDIA_TYPE_VIDEO) {
       if (video_stream)
         continue;
@@ -1042,14 +1081,6 @@
       // Log the codec detected, whether it is supported or not.
       UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedVideoCodecHash",
                                   GetCodecHash(codec_context));
-
-      // Ensure the codec is supported. IsValidConfig() also checks that the
-      // frame size and visible size are valid.
-      AVStreamToVideoDecoderConfig(stream, &video_config);
-
-      if (!video_config.IsValidConfig())
-        continue;
-      video_stream = stream;
     } else if (codec_type == AVMEDIA_TYPE_SUBTITLE) {
       if (codec_context->codec_id != AV_CODEC_ID_WEBVTT || !text_enabled_) {
         continue;
@@ -1058,15 +1089,30 @@
       continue;
     }
 
-    streams_[i] = new FFmpegDemuxerStream(this, stream);
+    // Attempt to create a FFmpegDemuxerStream from the AVStream. This will
+    // return nullptr if the AVStream is invalid. Validity checks will verify
+    // things like: codec, channel layout, sample/pixel format, etc...
+    scoped_ptr<FFmpegDemuxerStream> demuxer_stream =
+        FFmpegDemuxerStream::Create(this, stream);
+    if (demuxer_stream.get()) {
+      streams_[i] = demuxer_stream.release();
+    } else {
+      // This AVStream does not successfully convert.
+      continue;
+    }
 
-    // Record audio or video src= playback UMA stats for the stream's decoder
-    // config.
+    // Note when we find our audio/video stream (we only want one of each) and
+    // record src= playback UMA stats for the stream's decoder config.
     if (codec_type == AVMEDIA_TYPE_AUDIO) {
-      RecordAudioCodecStats(streams_[i]->audio_decoder_config());
+      CHECK(!audio_stream);
+      audio_stream = stream;
+      audio_config = streams_[i]->audio_decoder_config();
+      RecordAudioCodecStats(audio_config);
     } else if (codec_type == AVMEDIA_TYPE_VIDEO) {
-      RecordVideoCodecStats(streams_[i]->video_decoder_config(),
-                            stream->codec->color_range);
+      CHECK(!video_stream);
+      video_stream = stream;
+      video_config = streams_[i]->video_decoder_config();
+      RecordVideoCodecStats(video_config, stream->codec->color_range);
     }
 
     max_duration = std::max(max_duration, streams_[i]->duration());
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h
index 9c20e4a9..96c21d5 100644
--- a/media/filters/ffmpeg_demuxer.h
+++ b/media/filters/ffmpeg_demuxer.h
@@ -27,6 +27,7 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/threading/thread.h"
 #include "media/base/audio_decoder_config.h"
@@ -55,9 +56,14 @@
 
 class FFmpegDemuxerStream : public DemuxerStream {
  public:
-  // Keeps a copy of |demuxer| and initializes itself using information inside
-  // |stream|.  Both parameters must outlive |this|.
-  FFmpegDemuxerStream(FFmpegDemuxer* demuxer, AVStream* stream);
+  // Attempts to create FFmpegDemuxerStream form the given AVStream. Will return
+  // null if the AVStream cannot be translated into a valid decoder config.
+  //
+  // FFmpegDemuxerStream keeps a copy of |demuxer| and initializes itself using
+  // information inside |stream|. Both parameters must outlive |this|.
+  static scoped_ptr<FFmpegDemuxerStream> Create(FFmpegDemuxer* demuxer,
+                                                AVStream* stream);
+
   ~FFmpegDemuxerStream() override;
 
   // Enqueues the given AVPacket. It is invalid to queue a |packet| after
@@ -123,6 +129,15 @@
  private:
   friend class FFmpegDemuxerTest;
 
+  // Use FFmpegDemuxerStream::Create to construct.
+  // Audio/Video streams must include their respective DecoderConfig. At most
+  // one DecoderConfig should be provided (leaving the other nullptr). Both
+  // configs should be null for text streams.
+  FFmpegDemuxerStream(FFmpegDemuxer* demuxer,
+                      AVStream* stream,
+                      scoped_ptr<AudioDecoderConfig> audio_config,
+                      scoped_ptr<VideoDecoderConfig> video_config);
+
   // Runs |read_cb_| if present with the front of |buffer_queue_|, calling
   // NotifyCapacityAvailable() if capacity is still available.
   void SatisfyPendingRead();
@@ -140,8 +155,8 @@
   FFmpegDemuxer* demuxer_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   AVStream* stream_;
-  AudioDecoderConfig audio_config_;
-  VideoDecoderConfig video_config_;
+  scoped_ptr<AudioDecoderConfig> audio_config_;
+  scoped_ptr<VideoDecoderConfig> video_config_;
   Type type_;
   Liveness liveness_;
   base::TimeDelta duration_;
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index e75a67fd..2e988d2 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -296,8 +296,7 @@
   EXPECT_EQ(240, video_config.visible_rect().height());
   EXPECT_EQ(320, video_config.natural_size().width());
   EXPECT_EQ(240, video_config.natural_size().height());
-  EXPECT_FALSE(video_config.extra_data());
-  EXPECT_EQ(0u, video_config.extra_data_size());
+  EXPECT_TRUE(video_config.extra_data().empty());
 
   // Audio stream should be present.
   stream = demuxer_->GetStream(DemuxerStream::AUDIO);
@@ -310,8 +309,7 @@
   EXPECT_EQ(CHANNEL_LAYOUT_STEREO, audio_config.channel_layout());
   EXPECT_EQ(44100, audio_config.samples_per_second());
   EXPECT_EQ(kSampleFormatPlanarF32, audio_config.sample_format());
-  EXPECT_TRUE(audio_config.extra_data());
-  EXPECT_GT(audio_config.extra_data_size(), 0u);
+  EXPECT_FALSE(audio_config.extra_data().empty());
 
   // Unknown stream should never be present.
   EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
diff --git a/media/filters/ffmpeg_glue.cc b/media/filters/ffmpeg_glue.cc
index 31c6828b..bfeced0 100644
--- a/media/filters/ffmpeg_glue.cc
+++ b/media/filters/ffmpeg_glue.cc
@@ -153,7 +153,7 @@
 }
 
 bool FFmpegGlue::OpenContext() {
-  DCHECK(!open_called_) << "OpenContext() should't be called twice.";
+  DCHECK(!open_called_) << "OpenContext() shouldn't be called twice.";
 
   // If avformat_open_input() is called we have to take a slightly different
   // destruction path to avoid double frees.
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index f8a954a..4a1be85 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -14,6 +14,7 @@
 #include "media/base/decoder_buffer.h"
 #include "media/base/gmock_callback_support.h"
 #include "media/base/limits.h"
+#include "media/base/media_util.h"
 #include "media/base/mock_filters.h"
 #include "media/base/test_data_util.h"
 #include "media/base/test_helpers.h"
@@ -224,17 +225,17 @@
   // Ensure decoder handles unsupported pixel formats without crashing.
   VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
                             PIXEL_FORMAT_UNKNOWN, COLOR_SPACE_UNSPECIFIED,
-                            kCodedSize, kVisibleRect, kNaturalSize, NULL, 0,
-                            false);
+                            kCodedSize, kVisibleRect, kNaturalSize,
+                            EmptyExtraData(), false);
   InitializeWithConfigWithResult(config, false);
 }
 
 TEST_F(FFmpegVideoDecoderTest, Initialize_OpenDecoderFails) {
   // Specify Theora w/o extra data so that avcodec_open2() fails.
   VideoDecoderConfig config(kCodecTheora, VIDEO_CODEC_PROFILE_UNKNOWN,
-                            kVideoFormat, COLOR_SPACE_UNSPECIFIED,
-                            kCodedSize, kVisibleRect, kNaturalSize,
-                            NULL, 0, false);
+                            kVideoFormat, COLOR_SPACE_UNSPECIFIED, kCodedSize,
+                            kVisibleRect, kNaturalSize, EmptyExtraData(),
+                            false);
   InitializeWithConfigWithResult(config, false);
 }
 
@@ -247,8 +248,7 @@
                             kCodedSize,
                             kVisibleRect,
                             natural_size,
-                            NULL,
-                            0,
+                            EmptyExtraData(),
                             false);
   InitializeWithConfigWithResult(config, false);
 }
@@ -262,8 +262,7 @@
                             kCodedSize,
                             kVisibleRect,
                             natural_size,
-                            NULL,
-                            0,
+                            EmptyExtraData(),
                             false);
   InitializeWithConfigWithResult(config, false);
 }
@@ -277,8 +276,7 @@
                             kCodedSize,
                             kVisibleRect,
                             natural_size,
-                            NULL,
-                            0,
+                            EmptyExtraData(),
                             false);
   InitializeWithConfigWithResult(config, false);
 }
@@ -292,8 +290,7 @@
                             kCodedSize,
                             kVisibleRect,
                             natural_size,
-                            NULL,
-                            0,
+                            EmptyExtraData(),
                             false);
   InitializeWithConfigWithResult(config, false);
 }
@@ -309,8 +306,7 @@
                             kCodedSize,
                             kVisibleRect,
                             natural_size,
-                            NULL,
-                            0,
+                            EmptyExtraData(),
                             false);
   InitializeWithConfigWithResult(config, false);
 }
@@ -327,8 +323,7 @@
                             kCodedSize,
                             kVisibleRect,
                             natural_size,
-                            NULL,
-                            0,
+                            EmptyExtraData(),
                             false);
   InitializeWithConfigWithResult(config, false);
 }
diff --git a/media/filters/frame_processor_unittest.cc b/media/filters/frame_processor_unittest.cc
index ed4e715..4440de01 100644
--- a/media/filters/frame_processor_unittest.cc
+++ b/media/filters/frame_processor_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <map>
 #include <string>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
@@ -12,6 +13,7 @@
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "media/base/media_log.h"
+#include "media/base/media_util.h"
 #include "media/base/mock_filters.h"
 #include "media/base/test_helpers.h"
 #include "media/base/timestamp_constants.h"
@@ -282,13 +284,9 @@
       case DemuxerStream::AUDIO: {
         ASSERT_FALSE(audio_);
         audio_.reset(new ChunkDemuxerStream(DemuxerStream::AUDIO, true));
-        AudioDecoderConfig decoder_config(kCodecVorbis,
-                                          kSampleFormatPlanarF32,
-                                          CHANNEL_LAYOUT_STEREO,
-                                          1000,
-                                          NULL,
-                                          0,
-                                          false);
+        AudioDecoderConfig decoder_config(kCodecVorbis, kSampleFormatPlanarF32,
+                                          CHANNEL_LAYOUT_STEREO, 1000,
+                                          EmptyExtraData(), false);
         frame_processor_->OnPossibleAudioConfigUpdate(decoder_config);
         ASSERT_TRUE(audio_->UpdateAudioConfig(decoder_config, new MediaLog()));
         break;
diff --git a/media/filters/opus_audio_decoder.cc b/media/filters/opus_audio_decoder.cc
index c0fde49..41e06fb9 100644
--- a/media/filters/opus_audio_decoder.cc
+++ b/media/filters/opus_audio_decoder.cc
@@ -358,7 +358,9 @@
 
   // Parse the Opus Extra Data.
   OpusExtraData opus_extra_data;
-  if (!ParseOpusExtraData(config_.extra_data(), config_.extra_data_size(),
+  if (!ParseOpusExtraData(config_.extra_data().empty() ? nullptr :
+                              &config_.extra_data()[0],
+                          config_.extra_data().size(),
                           config_,
                           &opus_extra_data))
     return false;
diff --git a/media/filters/source_buffer_stream_unittest.cc b/media/filters/source_buffer_stream_unittest.cc
index bf15f32..5d8dfd5 100644
--- a/media/filters/source_buffer_stream_unittest.cc
+++ b/media/filters/source_buffer_stream_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <stdint.h>
 #include <string>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -15,6 +16,7 @@
 #include "base/strings/string_util.h"
 #include "media/base/data_buffer.h"
 #include "media/base/media_log.h"
+#include "media/base/media_util.h"
 #include "media/base/mock_media_log.h"
 #include "media/base/test_helpers.h"
 #include "media/base/text_track_config.h"
@@ -101,8 +103,7 @@
                              kSampleFormatPlanarF32,
                              CHANNEL_LAYOUT_STEREO,
                              1000,
-                             NULL,
-                             0,
+                             EmptyExtraData(),
                              false,
                              base::TimeDelta(),
                              0);
@@ -3603,7 +3604,7 @@
 // Test all the valid same timestamp cases for audio.
 TEST_F(SourceBufferStreamTest, SameTimestamp_Audio) {
   AudioDecoderConfig config(kCodecMP3, kSampleFormatF32, CHANNEL_LAYOUT_STEREO,
-                            44100, NULL, 0, false);
+                            44100, EmptyExtraData(), false);
   stream_.reset(new SourceBufferStream(config, media_log_, true));
   Seek(0);
   NewSegmentAppend("0K 0K 30K 30 60 60");
@@ -3614,7 +3615,7 @@
   EXPECT_MEDIA_LOG(ContainsSameTimestampAt30MillisecondsLog());
 
   AudioDecoderConfig config(kCodecMP3, kSampleFormatF32, CHANNEL_LAYOUT_STEREO,
-                            44100, NULL, 0, false);
+                            44100, EmptyExtraData(), false);
   stream_.reset(new SourceBufferStream(config, media_log_, true));
   Seek(0);
   NewSegmentAppend_ExpectFailure("0K 30 30K 60");
@@ -4173,12 +4174,8 @@
 
   SetAudioStream();
 
-  AudioDecoderConfig new_config(kCodecVorbis,
-                                kSampleFormatPlanarF32,
-                                CHANNEL_LAYOUT_MONO,
-                                1000,
-                                NULL,
-                                0,
+  AudioDecoderConfig new_config(kCodecVorbis, kSampleFormatPlanarF32,
+                                CHANNEL_LAYOUT_MONO, 1000, EmptyExtraData(),
                                 false);
   ASSERT_NE(new_config.channel_layout(), audio_config_.channel_layout());
 
@@ -4220,7 +4217,7 @@
 
   video_config_ = TestVideoConfig::Invalid();
   audio_config_.Initialize(kCodecVorbis, kSampleFormatPlanarF32,
-                           CHANNEL_LAYOUT_STEREO, 4000, NULL, 0, false,
+                           CHANNEL_LAYOUT_STEREO, 4000, EmptyExtraData(), false,
                            base::TimeDelta(), 0);
   stream_.reset(new SourceBufferStream(audio_config_, media_log_, true));
   // Equivalent to 0.5ms per frame.
diff --git a/media/formats/mp2t/es_adapter_video_unittest.cc b/media/formats/mp2t/es_adapter_video_unittest.cc
index 396b6559..24feb85 100644
--- a/media/formats/mp2t/es_adapter_video_unittest.cc
+++ b/media/formats/mp2t/es_adapter_video_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
+#include "media/base/media_util.h"
 #include "media/base/stream_parser_buffer.h"
 #include "media/base/timestamp_constants.h"
 #include "media/base/video_decoder_config.h"
@@ -27,7 +28,7 @@
   gfx::Size natural_size(320, 240);
   return VideoDecoderConfig(kCodecH264, H264PROFILE_MAIN, PIXEL_FORMAT_I420,
                             COLOR_SPACE_UNSPECIFIED, coded_size, visible_rect,
-                            natural_size, NULL, 0, false);
+                            natural_size, EmptyExtraData(), false);
 }
 
 StreamParserBuffer::BufferQueue
diff --git a/media/formats/mp2t/es_parser_adts.cc b/media/formats/mp2t/es_parser_adts.cc
index 9c57de19..adf1dbe 100644
--- a/media/formats/mp2t/es_parser_adts.cc
+++ b/media/formats/mp2t/es_parser_adts.cc
@@ -4,6 +4,8 @@
 
 #include "media/formats/mp2t/es_parser_adts.h"
 
+#include <vector>
+
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
@@ -219,10 +221,9 @@
       (frequency_index << 7) +
       // channel_configuration is [0..7], per early out above.
       (channel_configuration << 3));
-  uint8 extra_data[2] = {
-      static_cast<uint8>(extra_data_int >> 8),
-      static_cast<uint8>(extra_data_int & 0xff)
-  };
+  std::vector<uint8_t> extra_data;
+  extra_data.push_back(static_cast<uint8>(extra_data_int >> 8));
+  extra_data.push_back(static_cast<uint8>(extra_data_int & 0xff));
 
   AudioDecoderConfig audio_decoder_config(
       kCodecAAC,
@@ -230,7 +231,6 @@
       kADTSChannelLayoutTable[channel_configuration],
       extended_samples_per_second,
       extra_data,
-      arraysize(extra_data),
       false);
 
   if (!audio_decoder_config.Matches(last_audio_decoder_config_)) {
diff --git a/media/formats/mp2t/es_parser_h264.cc b/media/formats/mp2t/es_parser_h264.cc
index cbdec71d..8c591123 100644
--- a/media/formats/mp2t/es_parser_h264.cc
+++ b/media/formats/mp2t/es_parser_h264.cc
@@ -280,8 +280,8 @@
 
   VideoDecoderConfig video_decoder_config(
       kCodecH264, VIDEO_CODEC_PROFILE_UNKNOWN, PIXEL_FORMAT_YV12,
-      COLOR_SPACE_HD_REC709, coded_size, visible_rect, natural_size, NULL, 0,
-      false);
+      COLOR_SPACE_HD_REC709, coded_size, visible_rect, natural_size,
+      std::vector<uint8_t>(), false);
 
   if (!video_decoder_config.Matches(last_video_decoder_config_)) {
     DVLOG(1) << "Profile IDC: " << sps->profile_idc;
diff --git a/media/formats/mp2t/es_parser_mpeg1audio.cc b/media/formats/mp2t/es_parser_mpeg1audio.cc
index aee4cba..81abc2b 100644
--- a/media/formats/mp2t/es_parser_mpeg1audio.cc
+++ b/media/formats/mp2t/es_parser_mpeg1audio.cc
@@ -4,6 +4,8 @@
 
 #include "media/formats/mp2t/es_parser_mpeg1audio.h"
 
+#include <vector>
+
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/logging.h"
@@ -173,7 +175,7 @@
       kSampleFormatS16,
       header.channel_layout,
       header.sample_rate,
-      NULL, 0,
+      std::vector<uint8_t>(),
       false);
 
   if (!audio_decoder_config.Matches(last_audio_decoder_config_)) {
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index 18698b3..78b7dcd 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -4,6 +4,8 @@
 
 #include "media/formats/mp4/mp4_stream_parser.h"
 
+#include <vector>
+
 #include "base/callback_helpers.h"
 #include "base/logging.h"
 #include "base/time/time.h"
@@ -266,10 +268,9 @@
 
       is_audio_track_encrypted_ = entry.sinf.info.track_encryption.is_encrypted;
       DVLOG(1) << "is_audio_track_encrypted_: " << is_audio_track_encrypted_;
-      audio_config.Initialize(
-          codec, sample_format, channel_layout, sample_per_second,
-          extra_data.size() ? &extra_data[0] : NULL, extra_data.size(),
-          is_audio_track_encrypted_, base::TimeDelta(), 0);
+      audio_config.Initialize(codec, sample_format, channel_layout,
+                              sample_per_second, extra_data,
+                              is_audio_track_encrypted_, base::TimeDelta(), 0);
       has_audio_ = true;
       audio_track_id_ = track->header.track_id;
     }
@@ -305,12 +306,12 @@
 
       is_video_track_encrypted_ = entry.sinf.info.track_encryption.is_encrypted;
       DVLOG(1) << "is_video_track_encrypted_: " << is_video_track_encrypted_;
-      video_config.Initialize(entry.video_codec, entry.video_codec_profile,
-                              PIXEL_FORMAT_YV12, COLOR_SPACE_HD_REC709,
-                              coded_size, visible_rect, natural_size,
-                              // No decoder-specific buffer needed for AVC;
-                              // SPS/PPS are embedded in the video stream
-                              NULL, 0, is_video_track_encrypted_);
+      video_config.Initialize(
+          entry.video_codec, entry.video_codec_profile, PIXEL_FORMAT_YV12,
+          COLOR_SPACE_HD_REC709, coded_size, visible_rect, natural_size,
+          // No decoder-specific buffer needed for AVC;
+          // SPS/PPS are embedded in the video stream
+          std::vector<uint8_t>(), is_video_track_encrypted_);
       has_video_ = true;
       video_track_id_ = track->header.track_id;
     }
diff --git a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc b/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
index d9bf2b52..23032fa4 100644
--- a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
+++ b/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
@@ -207,8 +207,7 @@
                        kSampleFormatF32,
                        channel_layout,
                        sample_rate,
-                       NULL,
-                       0,
+                       std::vector<uint8_t>(),
                        false,
                        base::TimeDelta(),
                        codec_delay_);
diff --git a/media/formats/webm/webm_audio_client.cc b/media/formats/webm/webm_audio_client.cc
index bde7233..995746a4 100644
--- a/media/formats/webm/webm_audio_client.cc
+++ b/media/formats/webm/webm_audio_client.cc
@@ -66,13 +66,6 @@
     sample_format = kSampleFormatF32;
   }
 
-  const uint8* extra_data = NULL;
-  size_t extra_data_size = 0;
-  if (codec_private.size() > 0) {
-    extra_data = &codec_private[0];
-    extra_data_size = codec_private.size();
-  }
-
   // Convert |codec_delay| from nanoseconds into frames.
   int codec_delay_in_frames = 0;
   if (codec_delay != -1) {
@@ -87,8 +80,7 @@
       sample_format,
       channel_layout,
       samples_per_second,
-      extra_data,
-      extra_data_size,
+      codec_private,
       is_encrypted,
       base::TimeDelta::FromMicroseconds(
           (seek_preroll != -1 ? seek_preroll : 0) / 1000),
diff --git a/media/formats/webm/webm_video_client.cc b/media/formats/webm/webm_video_client.cc
index 2d3f43b9..29b7dca 100644
--- a/media/formats/webm/webm_video_client.cc
+++ b/media/formats/webm/webm_video_client.cc
@@ -88,16 +88,10 @@
     return false;
   }
   gfx::Size natural_size = gfx::Size(display_width_, display_height_);
-  const uint8* extra_data = NULL;
-  size_t extra_data_size = 0;
-  if (codec_private.size() > 0) {
-    extra_data = &codec_private[0];
-    extra_data_size = codec_private.size();
-  }
 
   config->Initialize(video_codec, profile, format, COLOR_SPACE_HD_REC709,
-                     coded_size, visible_rect, natural_size, extra_data,
-                     extra_data_size, is_encrypted);
+                     coded_size, visible_rect, natural_size, codec_private,
+                     is_encrypted);
   return config->IsValidConfig();
 }
 
diff --git a/media/media.gyp b/media/media.gyp
index 897c5d9..f0e41703 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -328,6 +328,8 @@
         'base/media_resources.h',
         'base/media_switches.cc',
         'base/media_switches.h',
+        'base/media_util.cc',
+        'base/media_util.h',
         'base/mime_util.cc',
         'base/mime_util.h',
         'base/moving_average.cc',
diff --git a/media/mojo/services/media_type_converters.cc b/media/mojo/services/media_type_converters.cc
index 6dd84fb..bcfab49 100644
--- a/media/mojo/services/media_type_converters.cc
+++ b/media/mojo/services/media_type_converters.cc
@@ -419,10 +419,9 @@
   config->channel_layout =
       static_cast<media::interfaces::ChannelLayout>(input.channel_layout());
   config->samples_per_second = input.samples_per_second();
-  if (input.extra_data()) {
-    std::vector<uint8_t> data(input.extra_data(),
-                              input.extra_data() + input.extra_data_size());
-    config->extra_data.Swap(&data);
+  if (!input.extra_data().empty()) {
+    std::vector<uint8_t> extra_data = input.extra_data();
+    config->extra_data.Swap(&extra_data);
   }
   config->seek_preroll_usec = input.seek_preroll().InMicroseconds();
   config->codec_delay = input.codec_delay();
@@ -440,10 +439,7 @@
       static_cast<media::AudioCodec>(input->codec),
       static_cast<media::SampleFormat>(input->sample_format),
       static_cast<media::ChannelLayout>(input->channel_layout),
-      input->samples_per_second,
-      input->extra_data.size() ? &input->extra_data.front() : NULL,
-      input->extra_data.size(),
-      input->is_encrypted,
+      input->samples_per_second, input->extra_data, input->is_encrypted,
       base::TimeDelta::FromMicroseconds(input->seek_preroll_usec),
       input->codec_delay);
   return config;
@@ -465,11 +461,7 @@
   config->coded_size = Size::From(input.coded_size());
   config->visible_rect = Rect::From(input.visible_rect());
   config->natural_size = Size::From(input.natural_size());
-  if (input.extra_data()) {
-    std::vector<uint8_t> data(input.extra_data(),
-                              input.extra_data() + input.extra_data_size());
-    config->extra_data.Swap(&data);
-  }
+  config->extra_data = mojo::Array<uint8>::From(input.extra_data());
   config->is_encrypted = input.is_encrypted();
   return config.Pass();
 }
@@ -486,9 +478,8 @@
       static_cast<media::VideoPixelFormat>(input->format),
       static_cast<media::ColorSpace>(input->color_space),
       input->coded_size.To<gfx::Size>(), input->visible_rect.To<gfx::Rect>(),
-      input->natural_size.To<gfx::Size>(),
-      input->extra_data.size() ? &input->extra_data.front() : NULL,
-      input->extra_data.size(), input->is_encrypted);
+      input->natural_size.To<gfx::Size>(), input->extra_data,
+      input->is_encrypted);
   return config;
 }
 
diff --git a/media/mojo/services/media_type_converters_unittest.cc b/media/mojo/services/media_type_converters_unittest.cc
index 54cd665..38559f3 100644
--- a/media/mojo/services/media_type_converters_unittest.cc
+++ b/media/mojo/services/media_type_converters_unittest.cc
@@ -7,6 +7,7 @@
 #include "media/base/audio_decoder_config.h"
 #include "media/base/cdm_config.h"
 #include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace media {
@@ -121,22 +122,23 @@
 // TODO(tim): Check other properties.
 
 TEST(MediaTypeConvertersTest, ConvertAudioDecoderConfig_Normal) {
-  const uint8 kExtraData[] = "config extra data";
-  const int kExtraDataSize = arraysize(kExtraData);
+  const uint8_t kExtraData[] = "config extra data";
+  const std::vector<uint8_t> kExtraDataVector(
+      &kExtraData[0], &kExtraData[0] + arraysize(kExtraData));
+
   AudioDecoderConfig config;
   config.Initialize(kCodecAAC, kSampleFormatU8, CHANNEL_LAYOUT_SURROUND, 48000,
-                    reinterpret_cast<const uint8*>(&kExtraData), kExtraDataSize,
-                    false, base::TimeDelta(), 0);
+                    kExtraDataVector, false, base::TimeDelta(), 0);
   interfaces::AudioDecoderConfigPtr ptr(
       interfaces::AudioDecoderConfig::From(config));
   AudioDecoderConfig result(ptr.To<AudioDecoderConfig>());
   EXPECT_TRUE(result.Matches(config));
 }
 
-TEST(MediaTypeConvertersTest, ConvertAudioDecoderConfig_NullExtraData) {
+TEST(MediaTypeConvertersTest, ConvertAudioDecoderConfig_EmptyExtraData) {
   AudioDecoderConfig config;
   config.Initialize(kCodecAAC, kSampleFormatU8, CHANNEL_LAYOUT_SURROUND, 48000,
-                    NULL, 0, false, base::TimeDelta(), 0);
+                    EmptyExtraData(), false, base::TimeDelta(), 0);
   interfaces::AudioDecoderConfigPtr ptr(
       interfaces::AudioDecoderConfig::From(config));
   AudioDecoderConfig result(ptr.To<AudioDecoderConfig>());
@@ -146,7 +148,7 @@
 TEST(MediaTypeConvertersTest, ConvertAudioDecoderConfig_Encrypted) {
   AudioDecoderConfig config;
   config.Initialize(kCodecAAC, kSampleFormatU8, CHANNEL_LAYOUT_SURROUND, 48000,
-                    NULL, 0,
+                    EmptyExtraData(),
                     true,  // Is encrypted.
                     base::TimeDelta(), 0);
   interfaces::AudioDecoderConfigPtr ptr(
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc
index 9e9bf87d..2367c42 100644
--- a/media/renderers/audio_renderer_impl_unittest.cc
+++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -13,6 +13,7 @@
 #include "media/base/audio_splicer.h"
 #include "media/base/fake_audio_renderer_sink.h"
 #include "media/base/gmock_callback_support.h"
+#include "media/base/media_util.h"
 #include "media/base/mock_filters.h"
 #include "media/base/test_helpers.h"
 #include "media/renderers/audio_renderer_impl.h"
@@ -69,8 +70,7 @@
                                     kSampleFormat,
                                     kChannelLayout,
                                     kInputSamplesPerSecond,
-                                    NULL,
-                                    0,
+                                    EmptyExtraData(),
                                     false);
     demuxer_stream_.set_audio_decoder_config(audio_config);