Reland of Prepare for injectable SW decoders (patchset #1 id:1 of https://codereview.webrtc.org/3010953002/ )

Reason for revert:
Fix bug introduced by keeping the allocated decoders in a map.

Original issue's description:
> Revert of Prepare for injectable SW decoders (patchset #3 id:40001 of https://codereview.webrtc.org/3009973002/ )
>
> Reason for revert:
> Tentative revert since it seems to cause problems in Chrome, MAC.
>
> https://build.chromium.org/p/chromium.webrtc.fyi/builders/Mac%20Tester/builds/42684
>
>
>
> Original issue's description:
> > 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-Commit-Position: refs/heads/master@{#19641}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/084c55a63a2d9bdc71579458406d44f8bab9f454
>
> TBR=magjed@webrtc.org,andersc@webrtc.org
> # Not skipping CQ checks because original CL landed more than 1 days ago.
> BUG=webrtc:7925
>
> Review-Url: https://codereview.webrtc.org/3010953002
> Cr-Commit-Position: refs/heads/master@{#19647}
> Committed: https://chromium.googlesource.com/external/webrtc/+/1f88531038c24c5ce3b0f4cfc682b970770a71f6

TBR=magjed@webrtc.org,perkj@webrtc.org
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=webrtc:7925

Review-Url: https://codereview.webrtc.org/3005363002
Cr-Original-Commit-Position: refs/heads/master@{#19782}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 063f0c0d3ac62f9110d54c7fea8aed7722264600
diff --git a/api/video_codecs/BUILD.gn b/api/video_codecs/BUILD.gn
index be7194e..c8bde01 100644
--- a/api/video_codecs/BUILD.gn
+++ b/api/video_codecs/BUILD.gn
@@ -14,6 +14,7 @@
 
 rtc_source_set("video_codecs_api") {
   sources = [
+    "sdp_video_format.h",
     "video_decoder.h",
     "video_encoder.cc",
     "video_encoder.h",
diff --git a/api/video_codecs/sdp_video_format.h b/api/video_codecs/sdp_video_format.h
new file mode 100644
index 0000000..bee4bf0
--- /dev/null
+++ b/api/video_codecs/sdp_video_format.h
@@ -0,0 +1,42 @@
+/*
+ *  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_API_VIDEO_CODECS_SDP_VIDEO_FORMAT_H_
+#define WEBRTC_API_VIDEO_CODECS_SDP_VIDEO_FORMAT_H_
+
+#include <map>
+#include <string>
+
+namespace webrtc {
+
+// SDP specification for a single video codec.
+// NOTE: This class is still under development and may change without notice.
+struct SdpVideoFormat {
+  using Parameters = std::map<std::string, std::string>;
+
+  explicit SdpVideoFormat(const std::string& name) : name(name) {}
+  SdpVideoFormat(const std::string& name, const Parameters& parameters)
+      : name(name), parameters(parameters) {}
+
+  friend bool operator==(const SdpVideoFormat& a, const SdpVideoFormat& b) {
+    return a.name == b.name && a.parameters == b.parameters;
+  }
+
+  friend bool operator!=(const SdpVideoFormat& a, const SdpVideoFormat& b) {
+    return !(a == b);
+  }
+
+  std::string name;
+  Parameters parameters;
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_API_VIDEO_CODECS_SDP_VIDEO_FORMAT_H_
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 25aa1e0..9deddee 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -147,6 +147,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..b328286
--- /dev/null
+++ b/media/engine/scopedvideodecoder.cc
@@ -0,0 +1,100 @@
+/*
+ *  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,
+    const VideoCodec& codec,
+    VideoDecoderParams params) {
+  webrtc::VideoDecoder* decoder =
+      factory->CreateVideoDecoderWithParams(codec, 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..c76c9fc
--- /dev/null
+++ b/media/engine/scopedvideodecoder.h
@@ -0,0 +1,34 @@
+/*
+ *  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,
+    const VideoCodec& codec,
+    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 a613dc6..284eb9a 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(
+      const VideoCodec& codec,
+      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(
+      const VideoCodec& codec,
+      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;
@@ -2065,7 +2103,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)
@@ -2076,12 +2114,12 @@
       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;
+  DecoderMap old_decoders;
   ConfigureCodecs(recv_codecs, &old_decoders);
   ConfigureFlexfecCodec(flexfec_config.payload_type);
   MaybeRecreateWebRtcFlexfecStream();
@@ -2089,28 +2127,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>&
@@ -2131,56 +2154,66 @@
   }
 }
 
-WebRtcVideoChannel::WebRtcVideoReceiveStream::AllocatedDecoder
-WebRtcVideoChannel::WebRtcVideoReceiveStream::CreateOrReuseVideoDecoder(
-    std::vector<AllocatedDecoder>* old_decoders,
-    const VideoCodec& codec) {
-  webrtc::VideoCodecType type = webrtc::PayloadStringToCodecType(codec.name);
-
-  const auto& found = std::find_if(
-      old_decoders->begin(), old_decoders->end(),
-      [type](const AllocatedDecoder decoder) { return decoder.type == type; });
-  if (found != old_decoders->end()) {
-    AllocatedDecoder decoder = *found;
-    old_decoders->erase(found);
-    return decoder;
-  }
-
-  if (external_decoder_factory_ != NULL) {
-    webrtc::VideoDecoder* decoder =
-        external_decoder_factory_->CreateVideoDecoderWithParams(
-            codec, {stream_params_.id});
-    if (decoder != NULL) {
-      return AllocatedDecoder(decoder, type, true /* is_external */);
+std::unique_ptr<webrtc::VideoDecoder>
+CricketDecoderFactoryAdapter::CreateVideoDecoder(
+    const VideoCodec& codec,
+    const VideoDecoderParams& decoder_params) const {
+  if (external_decoder_factory_ != nullptr) {
+    std::unique_ptr<webrtc::VideoDecoder> external_decoder =
+        CreateScopedVideoDecoder(external_decoder_factory_, codec,
+                                 decoder_params);
+    if (external_decoder) {
+      webrtc::VideoCodecType type =
+          webrtc::PayloadStringToCodecType(codec.name);
+      std::unique_ptr<webrtc::VideoDecoder> internal_decoder(
+          new webrtc::VideoDecoderSoftwareFallbackWrapper(
+              type, std::move(external_decoder)));
+      return internal_decoder;
     }
   }
 
-  InternalDecoderFactory internal_decoder_factory;
-  return AllocatedDecoder(internal_decoder_factory.CreateVideoDecoderWithParams(
-                              codec, {stream_params_.id}),
-                          type, false /* is_external */);
+  std::unique_ptr<webrtc::VideoDecoder> internal_decoder(
+      internal_decoder_factory_->CreateVideoDecoderWithParams(codec,
+                                                              decoder_params));
+  return internal_decoder;
 }
 
 void WebRtcVideoChannel::WebRtcVideoReceiveStream::ConfigureCodecs(
     const std::vector<VideoCodecSettings>& recv_codecs,
-    std::vector<AllocatedDecoder>* old_decoders) {
-  *old_decoders = allocated_decoders_;
-  allocated_decoders_.clear();
+    DecoderMap* old_decoders) {
+  *old_decoders = std::move(allocated_decoders_);
   config_.decoders.clear();
   config_.rtp.rtx_associated_payload_types.clear();
   for (const auto& recv_codec : recv_codecs) {
-    AllocatedDecoder allocated_decoder =
-        CreateOrReuseVideoDecoder(old_decoders, recv_codec.codec);
-    allocated_decoders_.push_back(allocated_decoder);
+    webrtc::SdpVideoFormat video_format(recv_codec.codec.name,
+                                        recv_codec.codec.params);
+    std::unique_ptr<webrtc::VideoDecoder> new_decoder;
+
+    auto it = old_decoders->find(video_format);
+    if (it != old_decoders->end()) {
+      new_decoder = std::move(it->second);
+      old_decoders->erase(it);
+    }
+
+    if (!new_decoder) {
+      new_decoder = decoder_factory_->CreateVideoDecoder(recv_codec.codec,
+                                                         {stream_params_.id});
+    }
 
     webrtc::VideoReceiveStream::Decoder decoder;
-    decoder.decoder = allocated_decoder.decoder;
+    decoder.decoder = new_decoder.get();
     decoder.payload_type = recv_codec.codec.id;
     decoder.payload_name = recv_codec.codec.name;
     decoder.codec_params = recv_codec.codec.params;
     config_.decoders.push_back(decoder);
     config_.rtp.rtx_associated_payload_types[recv_codec.rtx_payload_type] =
         recv_codec.codec.id;
+
+    const bool did_insert =
+        allocated_decoders_
+            .insert(std::make_pair(video_format, std::move(new_decoder)))
+            .second;
+    RTC_CHECK(did_insert);
   }
 
   config_.rtp.ulpfec = recv_codecs.front().ulpfec;
@@ -2257,7 +2290,7 @@
     const ChangedRecvParameters& params) {
   bool video_needs_recreation = false;
   bool flexfec_needs_recreation = false;
-  std::vector<AllocatedDecoder> old_decoders;
+  DecoderMap old_decoders;
   if (params.codec_settings) {
     ConfigureCodecs(*params.codec_settings, &old_decoders);
     video_needs_recreation = true;
@@ -2281,7 +2314,6 @@
     LOG(LS_INFO)
         << "RecreateWebRtcVideoStream (recv) because of SetRecvParameters";
     RecreateWebRtcVideoStream();
-    ClearDecoders(&old_decoders);
   }
 }
 
@@ -2326,16 +2358,6 @@
   }
 }
 
-void WebRtcVideoChannel::WebRtcVideoReceiveStream::ClearDecoders(
-    std::vector<AllocatedDecoder>* allocated_decoders) {
-  for (auto& dec : *allocated_decoders) {
-    if (dec.external)
-      external_decoder_factory_->DestroyVideoDecoder(dec.external_decoder);
-    delete dec.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 81a85c8..e61f422 100644
--- a/media/engine/webrtcvideoengine.h
+++ b/media/engine/webrtcvideoengine.h
@@ -20,6 +20,7 @@
 #include "webrtc/api/call/transport.h"
 #include "webrtc/api/optional.h"
 #include "webrtc/api/video/video_frame.h"
+#include "webrtc/api/video_codecs/sdp_video_format.h"
 #include "webrtc/call/call.h"
 #include "webrtc/call/flexfec_receive_stream.h"
 #include "webrtc/call/video_receive_stream.h"
@@ -47,6 +48,7 @@
 
 namespace cricket {
 
+class DecoderFactoryAdapter;
 class EncoderFactoryAdapter;
 class VideoCapturer;
 class VideoProcessor;
@@ -121,7 +123,7 @@
  private:
   bool initialized_;
 
-  WebRtcVideoDecoderFactory* external_decoder_factory_;
+  std::unique_ptr<DecoderFactoryAdapter> decoder_factory_;
   std::unique_ptr<EncoderFactoryAdapter> encoder_factory_;
 };
 
@@ -131,7 +133,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 +371,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,16 +396,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;
+    struct SdpVideoFormatCompare {
+      bool operator()(const webrtc::SdpVideoFormat& lhs,
+                      const webrtc::SdpVideoFormat& rhs) const {
+        return std::tie(lhs.name, lhs.parameters) <
+               std::tie(rhs.name, rhs.parameters);
+      }
     };
+    typedef std::map<webrtc::SdpVideoFormat,
+                     std::unique_ptr<webrtc::VideoDecoder>,
+                     SdpVideoFormatCompare>
+        DecoderMap;
 
     void RecreateWebRtcVideoStream();
     void MaybeRecreateWebRtcFlexfecStream();
@@ -412,12 +415,8 @@
     void MaybeDissociateFlexfecFromVideo();
 
     void ConfigureCodecs(const std::vector<VideoCodecSettings>& recv_codecs,
-                         std::vector<AllocatedDecoder>* old_codecs);
+                         DecoderMap* 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 +432,8 @@
     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_;
+    DecoderMap allocated_decoders_;
 
     rtc::CriticalSection sink_lock_;
     rtc::VideoSinkInterface<webrtc::VideoFrame>* sink_
@@ -498,7 +497,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