Prepare for injectable SW decoders

Pretty much mirrors the work done on the encoding side in CLs:

"Clean up ownership of webrtc::VideoEncoder"
https://codereview.webrtc.org/3007643002/

"Let VideoEncoderSoftwareFallbackWrapper own the wrapped encoder"
https://codereview.webrtc.org/3007683002/

"WebRtcVideoEngine: Encapsulate logic for unifying internal and external video codecs"
https://codereview.webrtc.org/3006713002/

BUG=webrtc:7925

Review-Url: https://codereview.webrtc.org/3009973002
Cr-Original-Commit-Position: refs/heads/master@{#19641}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 084c55a63a2d9bdc71579458406d44f8bab9f454
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 0ed8fc2..9438e6b 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -146,6 +146,8 @@
     "engine/nullwebrtcvideoengine.h",
     "engine/payload_type_mapper.cc",
     "engine/payload_type_mapper.h",
+    "engine/scopedvideodecoder.cc",
+    "engine/scopedvideodecoder.h",
     "engine/scopedvideoencoder.cc",
     "engine/scopedvideoencoder.h",
     "engine/simulcast.cc",
diff --git a/media/engine/scopedvideodecoder.cc b/media/engine/scopedvideodecoder.cc
new file mode 100644
index 0000000..6dfbefa
--- /dev/null
+++ b/media/engine/scopedvideodecoder.cc
@@ -0,0 +1,110 @@
+/*
+ *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/media/engine/scopedvideodecoder.h"
+
+#include <vector>
+
+#include "webrtc/api/video_codecs/video_decoder.h"
+
+namespace cricket {
+
+namespace {
+
+class ScopedVideoDecoder : public webrtc::VideoDecoder {
+ public:
+  ScopedVideoDecoder(WebRtcVideoDecoderFactory* factory,
+                     webrtc::VideoDecoder* decoder);
+
+  int32_t InitDecode(const webrtc::VideoCodec* codec_settings,
+                     int32_t number_of_cores) override;
+  int32_t RegisterDecodeCompleteCallback(
+      webrtc::DecodedImageCallback* callback) override;
+  int32_t Release() override;
+  int32_t Decode(const webrtc::EncodedImage& input_image,
+                 bool missing_frames,
+                 const webrtc::RTPFragmentationHeader* fragmentation,
+                 const webrtc::CodecSpecificInfo* codec_specific_info,
+                 int64_t render_time_ms) override;
+  bool PrefersLateDecoding() const override;
+  const char* ImplementationName() const override;
+
+  ~ScopedVideoDecoder() override;
+
+ private:
+  WebRtcVideoDecoderFactory* factory_;
+  webrtc::VideoDecoder* decoder_;
+};
+
+ScopedVideoDecoder::ScopedVideoDecoder(WebRtcVideoDecoderFactory* factory,
+                                       webrtc::VideoDecoder* decoder)
+    : factory_(factory), decoder_(decoder) {}
+
+int32_t ScopedVideoDecoder::InitDecode(const webrtc::VideoCodec* codec_settings,
+                                       int32_t number_of_cores) {
+  return decoder_->InitDecode(codec_settings, number_of_cores);
+}
+
+int32_t ScopedVideoDecoder::RegisterDecodeCompleteCallback(
+    webrtc::DecodedImageCallback* callback) {
+  return decoder_->RegisterDecodeCompleteCallback(callback);
+}
+
+int32_t ScopedVideoDecoder::Release() {
+  return decoder_->Release();
+}
+
+int32_t ScopedVideoDecoder::Decode(
+    const webrtc::EncodedImage& input_image,
+    bool missing_frames,
+    const webrtc::RTPFragmentationHeader* fragmentation,
+    const webrtc::CodecSpecificInfo* codec_specific_info,
+    int64_t render_time_ms) {
+  return decoder_->Decode(input_image, missing_frames, fragmentation,
+                          codec_specific_info, render_time_ms);
+}
+
+bool ScopedVideoDecoder::PrefersLateDecoding() const {
+  return decoder_->PrefersLateDecoding();
+}
+
+const char* ScopedVideoDecoder::ImplementationName() const {
+  return decoder_->ImplementationName();
+}
+
+ScopedVideoDecoder::~ScopedVideoDecoder() {
+  factory_->DestroyVideoDecoder(decoder_);
+}
+
+}  // namespace
+
+std::unique_ptr<webrtc::VideoDecoder> CreateScopedVideoDecoder(
+    WebRtcVideoDecoderFactory* factory,
+    webrtc::VideoCodecType type) {
+  webrtc::VideoDecoder* decoder = factory->CreateVideoDecoder(type);
+  if (!decoder)
+    return nullptr;
+  return std::unique_ptr<webrtc::VideoDecoder>(
+      new ScopedVideoDecoder(factory, decoder));
+}
+
+std::unique_ptr<webrtc::VideoDecoder> CreateScopedVideoDecoder(
+    WebRtcVideoDecoderFactory* factory,
+    webrtc::VideoCodecType type,
+    VideoDecoderParams params) {
+  webrtc::VideoDecoder* decoder =
+      factory->CreateVideoDecoderWithParams(type, params);
+  if (!decoder)
+    return nullptr;
+  return std::unique_ptr<webrtc::VideoDecoder>(
+      new ScopedVideoDecoder(factory, decoder));
+}
+
+}  // namespace cricket
diff --git a/media/engine/scopedvideodecoder.h b/media/engine/scopedvideodecoder.h
new file mode 100644
index 0000000..f921d99
--- /dev/null
+++ b/media/engine/scopedvideodecoder.h
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MEDIA_ENGINE_SCOPEDVIDEODECODER_H_
+#define WEBRTC_MEDIA_ENGINE_SCOPEDVIDEODECODER_H_
+
+#include <memory>
+
+#include "webrtc/media/engine/webrtcvideodecoderfactory.h"
+
+namespace cricket {
+
+// Helper function that creates a webrtc::VideoDecoder held by an
+// std::unique_ptr instead of having to be deleted through
+// WebRtcVideoDecoderFactory::DestroyVideoDecoder. The factory passed in must
+// outlive the returned encoder.
+// TODO(andersc): This helper function will be deleted once
+// cricket::WebRtcVideoDecoderFactory is deprecated, see
+// https://bugs.chromium.org/p/webrtc/issues/detail?id=7925 for more info.
+std::unique_ptr<webrtc::VideoDecoder> CreateScopedVideoDecoder(
+    cricket::WebRtcVideoDecoderFactory* factory,
+    webrtc::VideoCodecType type);
+std::unique_ptr<webrtc::VideoDecoder> CreateScopedVideoDecoder(
+    cricket::WebRtcVideoDecoderFactory* factory,
+    webrtc::VideoCodecType type,
+    VideoDecoderParams params);
+
+}  // namespace cricket
+
+#endif  // WEBRTC_MEDIA_ENGINE_SCOPEDVIDEODECODER_H_
diff --git a/media/engine/videodecodersoftwarefallbackwrapper.cc b/media/engine/videodecodersoftwarefallbackwrapper.cc
index 6a234d5..0e7632b 100644
--- a/media/engine/videodecodersoftwarefallbackwrapper.cc
+++ b/media/engine/videodecodersoftwarefallbackwrapper.cc
@@ -22,9 +22,9 @@
 
 VideoDecoderSoftwareFallbackWrapper::VideoDecoderSoftwareFallbackWrapper(
     VideoCodecType codec_type,
-    VideoDecoder* decoder)
+    std::unique_ptr<VideoDecoder> decoder)
     : codec_type_(codec_type),
-      decoder_(decoder),
+      decoder_(std::move(decoder)),
       decoder_initialized_(false),
       callback_(nullptr) {}
 
diff --git a/media/engine/videodecodersoftwarefallbackwrapper.h b/media/engine/videodecodersoftwarefallbackwrapper.h
index 3984e1f..d6c3e0e 100644
--- a/media/engine/videodecodersoftwarefallbackwrapper.h
+++ b/media/engine/videodecodersoftwarefallbackwrapper.h
@@ -21,10 +21,10 @@
 // Class used to wrap external VideoDecoders to provide a fallback option on
 // software decoding when a hardware decoder fails to decode a stream due to
 // hardware restrictions, such as max resolution.
-class VideoDecoderSoftwareFallbackWrapper : public webrtc::VideoDecoder {
+class VideoDecoderSoftwareFallbackWrapper : public VideoDecoder {
  public:
   VideoDecoderSoftwareFallbackWrapper(VideoCodecType codec_type,
-                                      VideoDecoder* decoder);
+                                      std::unique_ptr<VideoDecoder> decoder);
 
   int32_t InitDecode(const VideoCodec* codec_settings,
                      int32_t number_of_cores) override;
@@ -47,7 +47,7 @@
   bool InitFallbackDecoder();
 
   const VideoCodecType codec_type_;
-  VideoDecoder* const decoder_;
+  std::unique_ptr<VideoDecoder> decoder_;
   bool decoder_initialized_;
 
   VideoCodec codec_settings_;
diff --git a/media/engine/videodecodersoftwarefallbackwrapper_unittest.cc b/media/engine/videodecodersoftwarefallbackwrapper_unittest.cc
index b4fc7ca..84a6a59 100644
--- a/media/engine/videodecodersoftwarefallbackwrapper_unittest.cc
+++ b/media/engine/videodecodersoftwarefallbackwrapper_unittest.cc
@@ -19,7 +19,9 @@
 class VideoDecoderSoftwareFallbackWrapperTest : public ::testing::Test {
  protected:
   VideoDecoderSoftwareFallbackWrapperTest()
-      : fallback_wrapper_(kVideoCodecVP8, &fake_decoder_) {}
+      : fake_decoder_(new CountingFakeDecoder()),
+        fallback_wrapper_(kVideoCodecVP8,
+                          std::unique_ptr<VideoDecoder>(fake_decoder_)) {}
 
   class CountingFakeDecoder : public VideoDecoder {
    public:
@@ -61,39 +63,41 @@
     int release_count_ = 0;
     int reset_count_ = 0;
   };
-  CountingFakeDecoder fake_decoder_;
+  // |fake_decoder_| is owned and released by |fallback_wrapper_|.
+  CountingFakeDecoder* fake_decoder_;
   VideoDecoderSoftwareFallbackWrapper fallback_wrapper_;
 };
 
 TEST_F(VideoDecoderSoftwareFallbackWrapperTest, InitializesDecoder) {
   VideoCodec codec = {};
   fallback_wrapper_.InitDecode(&codec, 2);
-  EXPECT_EQ(1, fake_decoder_.init_decode_count_);
+  EXPECT_EQ(1, fake_decoder_->init_decode_count_);
 
   EncodedImage encoded_image;
   encoded_image._frameType = kVideoFrameKey;
   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
-  EXPECT_EQ(1, fake_decoder_.init_decode_count_)
+  EXPECT_EQ(1, fake_decoder_->init_decode_count_)
       << "Initialized decoder should not be reinitialized.";
-  EXPECT_EQ(1, fake_decoder_.decode_count_);
+  EXPECT_EQ(1, fake_decoder_->decode_count_);
 }
 
 TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
        UsesFallbackDecoderAfterOnInitDecodeFailure) {
   VideoCodec codec = {};
-  fake_decoder_.init_decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+  fake_decoder_->init_decode_return_code_ =
+      WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
   fallback_wrapper_.InitDecode(&codec, 2);
-  EXPECT_EQ(1, fake_decoder_.init_decode_count_);
+  EXPECT_EQ(1, fake_decoder_->init_decode_count_);
 
   EncodedImage encoded_image;
   encoded_image._frameType = kVideoFrameKey;
   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
-  EXPECT_EQ(2, fake_decoder_.init_decode_count_)
+  EXPECT_EQ(2, fake_decoder_->init_decode_count_)
       << "Should have attempted reinitializing the fallback decoder on "
          "keyframe.";
   // Unfortunately faking a VP8 frame is hard. Rely on no Decode -> using SW
   // decoder.
-  EXPECT_EQ(0, fake_decoder_.decode_count_)
+  EXPECT_EQ(0, fake_decoder_->decode_count_)
       << "Decoder used even though no InitDecode had succeeded.";
 }
 
@@ -103,41 +107,41 @@
   fallback_wrapper_.InitDecode(&codec, 2);
   // Unfortunately faking a VP8 frame is hard. Rely on no Decode -> using SW
   // decoder.
-  fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+  fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
   EncodedImage encoded_image;
   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
-  EXPECT_EQ(1, fake_decoder_.decode_count_);
+  EXPECT_EQ(1, fake_decoder_->decode_count_);
 
   // Fail -> fake_decoder shouldn't be used anymore.
   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
-  EXPECT_EQ(1, fake_decoder_.decode_count_)
+  EXPECT_EQ(1, fake_decoder_->decode_count_)
       << "Decoder used even though fallback should be active.";
 
   // Should be able to recover on a keyframe.
   encoded_image._frameType = kVideoFrameKey;
-  fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
+  fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
-  EXPECT_EQ(2, fake_decoder_.decode_count_)
+  EXPECT_EQ(2, fake_decoder_->decode_count_)
       << "Wrapper did not try to decode a keyframe using registered decoder.";
 
   encoded_image._frameType = kVideoFrameDelta;
   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
-  EXPECT_EQ(3, fake_decoder_.decode_count_)
+  EXPECT_EQ(3, fake_decoder_->decode_count_)
       << "Decoder not used on future delta frames.";
 }
 
 TEST_F(VideoDecoderSoftwareFallbackWrapperTest, DoesNotFallbackOnEveryError) {
   VideoCodec codec = {};
   fallback_wrapper_.InitDecode(&codec, 2);
-  fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
+  fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
   EncodedImage encoded_image;
   EXPECT_EQ(
-      fake_decoder_.decode_return_code_,
+      fake_decoder_->decode_return_code_,
       fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1));
-  EXPECT_EQ(1, fake_decoder_.decode_count_);
+  EXPECT_EQ(1, fake_decoder_->decode_count_);
 
   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
-  EXPECT_EQ(2, fake_decoder_.decode_count_)
+  EXPECT_EQ(2, fake_decoder_->decode_count_)
       << "Decoder should be active even though previous decode failed.";
 }
 
@@ -145,15 +149,15 @@
   VideoCodec codec = {};
   fallback_wrapper_.InitDecode(&codec, 2);
   fallback_wrapper_.Release();
-  EXPECT_EQ(1, fake_decoder_.release_count_);
+  EXPECT_EQ(1, fake_decoder_->release_count_);
 
-  fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+  fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
   EncodedImage encoded_image;
   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
-  EXPECT_EQ(1, fake_decoder_.release_count_)
+  EXPECT_EQ(1, fake_decoder_->release_count_)
       << "Decoder should not be released during fallback.";
   fallback_wrapper_.Release();
-  EXPECT_EQ(2, fake_decoder_.release_count_);
+  EXPECT_EQ(2, fake_decoder_->release_count_);
 }
 
 // TODO(pbos): Fake a VP8 frame well enough to actually receive a callback from
@@ -177,13 +181,13 @@
   VideoCodec codec = {};
   fallback_wrapper_.InitDecode(&codec, 2);
   fallback_wrapper_.RegisterDecodeCompleteCallback(&callback);
-  EXPECT_EQ(&callback, fake_decoder_.decode_complete_callback_);
+  EXPECT_EQ(&callback, fake_decoder_->decode_complete_callback_);
 
-  fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+  fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
   EncodedImage encoded_image;
   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
   fallback_wrapper_.RegisterDecodeCompleteCallback(&callback2);
-  EXPECT_EQ(&callback2, fake_decoder_.decode_complete_callback_);
+  EXPECT_EQ(&callback2, fake_decoder_->decode_complete_callback_);
 }
 
 TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
@@ -191,7 +195,7 @@
   VideoCodec codec = {};
   fallback_wrapper_.InitDecode(&codec, 2);
 
-  fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
+  fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
   EncodedImage encoded_image;
   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
   // Hard coded expected value since libvpx is the software implementation name
diff --git a/media/engine/webrtcvideoengine.cc b/media/engine/webrtcvideoengine.cc
index 00d138a..dd0a7b0 100644
--- a/media/engine/webrtcvideoengine.cc
+++ b/media/engine/webrtcvideoengine.cc
@@ -24,6 +24,7 @@
 #include "webrtc/media/engine/constants.h"
 #include "webrtc/media/engine/internaldecoderfactory.h"
 #include "webrtc/media/engine/internalencoderfactory.h"
+#include "webrtc/media/engine/scopedvideodecoder.h"
 #include "webrtc/media/engine/scopedvideoencoder.h"
 #include "webrtc/media/engine/simulcast.h"
 #include "webrtc/media/engine/simulcast_encoder_adapter.h"
@@ -71,6 +72,17 @@
   virtual std::unique_ptr<EncoderFactoryAdapter> clone() const = 0;
 };
 
+class DecoderFactoryAdapter {
+ public:
+  virtual ~DecoderFactoryAdapter() {}
+
+  virtual std::unique_ptr<webrtc::VideoDecoder> CreateVideoDecoder(
+      webrtc::VideoCodecType type,
+      const VideoDecoderParams& decoder_params) const = 0;
+
+  virtual std::unique_ptr<DecoderFactoryAdapter> clone() const = 0;
+};
+
 namespace {
 
 // Wraps cricket::WebRtcVideoEncoderFactory* into common EncoderFactoryAdapter
@@ -104,6 +116,31 @@
   WebRtcVideoEncoderFactory* const external_encoder_factory_;
 };
 
+class CricketDecoderFactoryAdapter : public DecoderFactoryAdapter {
+ public:
+  explicit CricketDecoderFactoryAdapter(
+      WebRtcVideoDecoderFactory* external_decoder_factory)
+      : internal_decoder_factory_(new InternalDecoderFactory()),
+        external_decoder_factory_(external_decoder_factory) {}
+
+ private:
+  explicit CricketDecoderFactoryAdapter(
+      const CricketDecoderFactoryAdapter& other)
+      : CricketDecoderFactoryAdapter(other.external_decoder_factory_) {}
+
+  std::unique_ptr<webrtc::VideoDecoder> CreateVideoDecoder(
+      webrtc::VideoCodecType type,
+      const VideoDecoderParams& decoder_params) const override;
+
+  std::unique_ptr<DecoderFactoryAdapter> clone() const override {
+    return std::unique_ptr<DecoderFactoryAdapter>(
+        new CricketDecoderFactoryAdapter(*this));
+  }
+
+  const std::unique_ptr<WebRtcVideoDecoderFactory> internal_decoder_factory_;
+  WebRtcVideoDecoderFactory* const external_decoder_factory_;
+};
+
 // If this field trial is enabled, we will enable sending FlexFEC and disable
 // sending ULPFEC whenever the former has been negotiated in the SDPs.
 bool IsFlexfecFieldTrialEnabled() {
@@ -367,7 +404,8 @@
 
 WebRtcVideoEngine::WebRtcVideoEngine()
     : initialized_(false),
-      external_decoder_factory_(NULL),
+      decoder_factory_(new CricketDecoderFactoryAdapter(
+          nullptr /* external_decoder_factory */)),
       encoder_factory_(new CricketEncoderFactoryAdapter(
           nullptr /* external_encoder_factory */)) {
   LOG(LS_INFO) << "WebRtcVideoEngine::WebRtcVideoEngine()";
@@ -389,7 +427,7 @@
   RTC_DCHECK(initialized_);
   LOG(LS_INFO) << "CreateChannel. Options: " << options.ToString();
   return new WebRtcVideoChannel(call, config, options, *encoder_factory_,
-                                external_decoder_factory_);
+                                *decoder_factory_);
 }
 
 std::vector<VideoCodec> WebRtcVideoEngine::codecs() const {
@@ -425,7 +463,7 @@
 void WebRtcVideoEngine::SetExternalDecoderFactory(
     WebRtcVideoDecoderFactory* decoder_factory) {
   RTC_DCHECK(!initialized_);
-  external_decoder_factory_ = decoder_factory;
+  decoder_factory_.reset(new CricketDecoderFactoryAdapter(decoder_factory));
 }
 
 void WebRtcVideoEngine::SetExternalEncoderFactory(
@@ -503,13 +541,13 @@
     const MediaConfig& config,
     const VideoOptions& options,
     const EncoderFactoryAdapter& encoder_factory,
-    WebRtcVideoDecoderFactory* external_decoder_factory)
+    const DecoderFactoryAdapter& decoder_factory)
     : VideoMediaChannel(config),
       call_(call),
       unsignalled_ssrc_handler_(&default_unsignalled_ssrc_handler_),
       video_config_(config.video),
       encoder_factory_(encoder_factory.clone()),
-      external_decoder_factory_(external_decoder_factory),
+      decoder_factory_(decoder_factory.clone()),
       default_send_options_(options),
       last_stats_log_ms_(-1) {
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
@@ -1125,7 +1163,7 @@
   config.sync_group = sp.sync_label;
 
   receive_streams_[ssrc] = new WebRtcVideoReceiveStream(
-      call_, sp, std::move(config), external_decoder_factory_, default_stream,
+      call_, sp, std::move(config), *decoder_factory_, default_stream,
       recv_codecs_, flexfec_config);
 
   return true;
@@ -2063,7 +2101,7 @@
     webrtc::Call* call,
     const StreamParams& sp,
     webrtc::VideoReceiveStream::Config config,
-    WebRtcVideoDecoderFactory* external_decoder_factory,
+    const DecoderFactoryAdapter& decoder_factory,
     bool default_stream,
     const std::vector<VideoCodecSettings>& recv_codecs,
     const webrtc::FlexfecReceiveStream::Config& flexfec_config)
@@ -2074,12 +2112,13 @@
       config_(std::move(config)),
       flexfec_config_(flexfec_config),
       flexfec_stream_(nullptr),
-      external_decoder_factory_(external_decoder_factory),
+      decoder_factory_(decoder_factory.clone()),
       sink_(NULL),
       first_frame_timestamp_(-1),
       estimated_remote_start_ntp_time_ms_(0) {
   config_.renderer = this;
-  std::vector<AllocatedDecoder> old_decoders;
+  std::map<webrtc::VideoCodecType, std::unique_ptr<webrtc::VideoDecoder>>
+      old_decoders;
   ConfigureCodecs(recv_codecs, &old_decoders);
   ConfigureFlexfecCodec(flexfec_config.payload_type);
   MaybeRecreateWebRtcFlexfecStream();
@@ -2087,28 +2126,13 @@
   RTC_DCHECK(old_decoders.empty());
 }
 
-WebRtcVideoChannel::WebRtcVideoReceiveStream::AllocatedDecoder::
-    AllocatedDecoder(webrtc::VideoDecoder* decoder,
-                     webrtc::VideoCodecType type,
-                     bool external)
-    : decoder(decoder),
-      external_decoder(nullptr),
-      type(type),
-      external(external) {
-  if (external) {
-    external_decoder = decoder;
-    this->decoder =
-        new webrtc::VideoDecoderSoftwareFallbackWrapper(type, external_decoder);
-  }
-}
-
 WebRtcVideoChannel::WebRtcVideoReceiveStream::~WebRtcVideoReceiveStream() {
   if (flexfec_stream_) {
     MaybeDissociateFlexfecFromVideo();
     call_->DestroyFlexfecReceiveStream(flexfec_stream_);
   }
   call_->DestroyVideoReceiveStream(stream_);
-  ClearDecoders(&allocated_decoders_);
+  allocated_decoders_.clear();
 }
 
 const std::vector<uint32_t>&
@@ -2129,53 +2153,59 @@
   }
 }
 
-WebRtcVideoChannel::WebRtcVideoReceiveStream::AllocatedDecoder
-WebRtcVideoChannel::WebRtcVideoReceiveStream::CreateOrReuseVideoDecoder(
-    std::vector<AllocatedDecoder>* old_decoders,
-    const VideoCodec& codec) {
-  webrtc::VideoCodecType type = webrtc::PayloadStringToCodecType(codec.name);
-
-  for (size_t i = 0; i < old_decoders->size(); ++i) {
-    if ((*old_decoders)[i].type == type) {
-      AllocatedDecoder decoder = (*old_decoders)[i];
-      (*old_decoders)[i] = old_decoders->back();
-      old_decoders->pop_back();
-      return decoder;
+std::unique_ptr<webrtc::VideoDecoder>
+CricketDecoderFactoryAdapter::CreateVideoDecoder(
+    webrtc::VideoCodecType type,
+    const VideoDecoderParams& decoder_params) const {
+  if (external_decoder_factory_ != nullptr) {
+    std::unique_ptr<webrtc::VideoDecoder> external_decoder =
+        CreateScopedVideoDecoder(external_decoder_factory_, type,
+                                 decoder_params);
+    if (external_decoder) {
+      std::unique_ptr<webrtc::VideoDecoder> internal_decoder(
+          new webrtc::VideoDecoderSoftwareFallbackWrapper(
+              type, std::move(external_decoder)));
+      return internal_decoder;
     }
   }
 
-  if (external_decoder_factory_ != NULL) {
-    webrtc::VideoDecoder* decoder =
-        external_decoder_factory_->CreateVideoDecoderWithParams(
-            type, {stream_params_.id});
-    if (decoder != NULL) {
-      return AllocatedDecoder(decoder, type, true /* is_external */);
-    }
-  }
-
-  InternalDecoderFactory internal_decoder_factory;
-  return AllocatedDecoder(internal_decoder_factory.CreateVideoDecoderWithParams(
-                              type, {stream_params_.id}),
-                          type, false /* is_external */);
+  std::unique_ptr<webrtc::VideoDecoder> internal_decoder(
+      internal_decoder_factory_->CreateVideoDecoderWithParams(type,
+                                                              decoder_params));
+  return internal_decoder;
 }
 
 void WebRtcVideoChannel::WebRtcVideoReceiveStream::ConfigureCodecs(
     const std::vector<VideoCodecSettings>& recv_codecs,
-    std::vector<AllocatedDecoder>* old_decoders) {
-  *old_decoders = allocated_decoders_;
+    std::map<webrtc::VideoCodecType, std::unique_ptr<webrtc::VideoDecoder>>*
+        old_decoders) {
+  *old_decoders = std::move(allocated_decoders_);
   allocated_decoders_.clear();
   config_.decoders.clear();
   for (size_t i = 0; i < recv_codecs.size(); ++i) {
-    AllocatedDecoder allocated_decoder =
-        CreateOrReuseVideoDecoder(old_decoders, recv_codecs[i].codec);
-    allocated_decoders_.push_back(allocated_decoder);
+    webrtc::VideoCodecType type =
+        webrtc::PayloadStringToCodecType(recv_codecs[i].codec.name);
+    std::unique_ptr<webrtc::VideoDecoder> new_decoder;
+
+    auto it = old_decoders->find(type);
+    if (it != old_decoders->end()) {
+      new_decoder = std::move(it->second);
+      old_decoders->erase(it);
+    }
+
+    if (!new_decoder) {
+      new_decoder =
+          decoder_factory_->CreateVideoDecoder(type, {stream_params_.id});
+    }
 
     webrtc::VideoReceiveStream::Decoder decoder;
-    decoder.decoder = allocated_decoder.decoder;
+    decoder.decoder = new_decoder.get();
     decoder.payload_type = recv_codecs[i].codec.id;
     decoder.payload_name = recv_codecs[i].codec.name;
     decoder.codec_params = recv_codecs[i].codec.params;
     config_.decoders.push_back(decoder);
+
+    allocated_decoders_.insert(std::make_pair(type, std::move(new_decoder)));
   }
 
   config_.rtp.rtx_associated_payload_types.clear();
@@ -2253,7 +2283,8 @@
     const ChangedRecvParameters& params) {
   bool video_needs_recreation = false;
   bool flexfec_needs_recreation = false;
-  std::vector<AllocatedDecoder> old_decoders;
+  std::map<webrtc::VideoCodecType, std::unique_ptr<webrtc::VideoDecoder>>
+      old_decoders;
   if (params.codec_settings) {
     ConfigureCodecs(*params.codec_settings, &old_decoders);
     video_needs_recreation = true;
@@ -2277,7 +2308,6 @@
     LOG(LS_INFO)
         << "RecreateWebRtcVideoStream (recv) because of SetRecvParameters";
     RecreateWebRtcVideoStream();
-    ClearDecoders(&old_decoders);
   }
 }
 
@@ -2322,18 +2352,6 @@
   }
 }
 
-void WebRtcVideoChannel::WebRtcVideoReceiveStream::ClearDecoders(
-    std::vector<AllocatedDecoder>* allocated_decoders) {
-  for (size_t i = 0; i < allocated_decoders->size(); ++i) {
-    if ((*allocated_decoders)[i].external) {
-      external_decoder_factory_->DestroyVideoDecoder(
-          (*allocated_decoders)[i].external_decoder);
-    }
-    delete (*allocated_decoders)[i].decoder;
-  }
-  allocated_decoders->clear();
-}
-
 void WebRtcVideoChannel::WebRtcVideoReceiveStream::OnFrame(
     const webrtc::VideoFrame& frame) {
   rtc::CritScope crit(&sink_lock_);
diff --git a/media/engine/webrtcvideoengine.h b/media/engine/webrtcvideoengine.h
index 3224d00..8f7a790 100644
--- a/media/engine/webrtcvideoengine.h
+++ b/media/engine/webrtcvideoengine.h
@@ -47,6 +47,7 @@
 
 namespace cricket {
 
+class DecoderFactoryAdapter;
 class EncoderFactoryAdapter;
 class VideoCapturer;
 class VideoProcessor;
@@ -121,7 +122,7 @@
  private:
   bool initialized_;
 
-  WebRtcVideoDecoderFactory* external_decoder_factory_;
+  std::unique_ptr<DecoderFactoryAdapter> decoder_factory_;
   std::unique_ptr<EncoderFactoryAdapter> encoder_factory_;
 };
 
@@ -131,7 +132,7 @@
                      const MediaConfig& config,
                      const VideoOptions& options,
                      const EncoderFactoryAdapter& encoder_factory,
-                     WebRtcVideoDecoderFactory* external_decoder_factory);
+                     const DecoderFactoryAdapter& decoder_factory);
   ~WebRtcVideoChannel() override;
 
   // VideoMediaChannel implementation
@@ -369,7 +370,7 @@
         webrtc::Call* call,
         const StreamParams& sp,
         webrtc::VideoReceiveStream::Config config,
-        WebRtcVideoDecoderFactory* external_decoder_factory,
+        const DecoderFactoryAdapter& decoder_factory,
         bool default_stream,
         const std::vector<VideoCodecSettings>& recv_codecs,
         const webrtc::FlexfecReceiveStream::Config& flexfec_config);
@@ -394,30 +395,17 @@
     VideoReceiverInfo GetVideoReceiverInfo(bool log_stats);
 
    private:
-    struct AllocatedDecoder {
-      AllocatedDecoder(webrtc::VideoDecoder* decoder,
-                       webrtc::VideoCodecType type,
-                       bool external);
-      webrtc::VideoDecoder* decoder;
-      // Decoder wrapped into a fallback decoder to permit software fallback.
-      webrtc::VideoDecoder* external_decoder;
-      webrtc::VideoCodecType type;
-      bool external;
-    };
-
     void RecreateWebRtcVideoStream();
     void MaybeRecreateWebRtcFlexfecStream();
 
     void MaybeAssociateFlexfecWithVideo();
     void MaybeDissociateFlexfecFromVideo();
 
-    void ConfigureCodecs(const std::vector<VideoCodecSettings>& recv_codecs,
-                         std::vector<AllocatedDecoder>* old_codecs);
+    void ConfigureCodecs(
+        const std::vector<VideoCodecSettings>& recv_codecs,
+        std::map<webrtc::VideoCodecType, std::unique_ptr<webrtc::VideoDecoder>>*
+            old_codecs);
     void ConfigureFlexfecCodec(int flexfec_payload_type);
-    AllocatedDecoder CreateOrReuseVideoDecoder(
-        std::vector<AllocatedDecoder>* old_decoder,
-        const VideoCodec& codec);
-    void ClearDecoders(std::vector<AllocatedDecoder>* allocated_decoders);
 
     std::string GetCodecNameFromPayloadType(int payload_type);
 
@@ -433,8 +421,9 @@
     webrtc::FlexfecReceiveStream::Config flexfec_config_;
     webrtc::FlexfecReceiveStream* flexfec_stream_;
 
-    WebRtcVideoDecoderFactory* const external_decoder_factory_;
-    std::vector<AllocatedDecoder> allocated_decoders_;
+    std::unique_ptr<DecoderFactoryAdapter> decoder_factory_;
+    std::map<webrtc::VideoCodecType, std::unique_ptr<webrtc::VideoDecoder>>
+        allocated_decoders_;
 
     rtc::CriticalSection sink_lock_;
     rtc::VideoSinkInterface<webrtc::VideoFrame>* sink_ GUARDED_BY(sink_lock_);
@@ -497,7 +486,7 @@
   rtc::Optional<std::vector<webrtc::RtpExtension>> send_rtp_extensions_;
 
   std::unique_ptr<EncoderFactoryAdapter> encoder_factory_;
-  WebRtcVideoDecoderFactory* const external_decoder_factory_;
+  std::unique_ptr<DecoderFactoryAdapter> decoder_factory_;
   std::vector<VideoCodecSettings> recv_codecs_;
   std::vector<webrtc::RtpExtension> recv_rtp_extensions_;
   // See reason for keeping track of the FlexFEC payload type separately in