Clean up ownership of webrtc::VideoEncoder

Currently, webrtc::VideoEncoders are supposed to be deleted through the
factory that created them with the
WebRtcVideoEncoderFactory::DestroyVideoEncoder method. In practice,
we sometimes use this method and sometimes we just call delete on the
webrtc::VideoEncoder pointer. We want to be able to consistently use the
normal destructor of webrtc::VideoEncoder instead of having to call
DestroyVideoEncoder so that we can put webrtc::VideoEncoder inside
an std::unique_ptr and make ownership more clear. As part of webrtc:7925
we also want to make a new encoder factory class that does not have the
DestroyVideoEncoder() method, and this CL is a step in that direction.

This CL introduces a helper function CreateScopedVideoEncoder that takes
a webrtc::VideoEncoder and a WebRtcVideoEncoderFactory pointer, and
returns a new webrtc::VideoEncoder instance that can be deleted through
the regular destructor.

This CL also removes WebRtcSimulcastEncoderFactory that almost only
contains logic for handling the DestroyVideoEncoder calls that we no
longer need, and inlines the rest of the logic inside the
WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoder method.

BUG=webrtc:7925

Review-Url: https://codereview.webrtc.org/3007643002
Cr-Original-Commit-Position: refs/heads/master@{#19564}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 3f8975839865d668b993d3f84824167672830235
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 66fce0b..0ed8fc2 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/scopedvideoencoder.cc",
+    "engine/scopedvideoencoder.h",
     "engine/simulcast.cc",
     "engine/simulcast.h",
     "engine/simulcast_encoder_adapter.cc",
diff --git a/media/engine/scopedvideoencoder.cc b/media/engine/scopedvideoencoder.cc
new file mode 100644
index 0000000..0c07d8c
--- /dev/null
+++ b/media/engine/scopedvideoencoder.cc
@@ -0,0 +1,126 @@
+/*
+ *  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/scopedvideoencoder.h"
+
+#include <vector>
+
+#include "webrtc/api/video_codecs/video_encoder.h"
+
+namespace cricket {
+
+namespace {
+
+class ScopedVideoEncoder : public webrtc::VideoEncoder {
+ public:
+  ScopedVideoEncoder(WebRtcVideoEncoderFactory* factory,
+                     webrtc::VideoEncoder* encoder);
+
+  int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
+                     int32_t number_of_cores,
+                     size_t max_payload_size) override;
+  int32_t RegisterEncodeCompleteCallback(
+      webrtc::EncodedImageCallback* callback) override;
+  int32_t Release() override;
+  int32_t Encode(const webrtc::VideoFrame& frame,
+                 const webrtc::CodecSpecificInfo* codec_specific_info,
+                 const std::vector<webrtc::FrameType>* frame_types) override;
+  int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override;
+  int32_t SetRates(uint32_t bitrate, uint32_t framerate) override;
+  int32_t SetRateAllocation(const webrtc::BitrateAllocation& allocation,
+                            uint32_t framerate) override;
+  ScalingSettings GetScalingSettings() const override;
+  int32_t SetPeriodicKeyFrames(bool enable) override;
+  bool SupportsNativeHandle() const override;
+  const char* ImplementationName() const override;
+
+  ~ScopedVideoEncoder() override;
+
+ private:
+  WebRtcVideoEncoderFactory* factory_;
+  webrtc::VideoEncoder* encoder_;
+};
+
+ScopedVideoEncoder::ScopedVideoEncoder(WebRtcVideoEncoderFactory* factory,
+                                       webrtc::VideoEncoder* encoder)
+    : factory_(factory), encoder_(encoder) {}
+
+int32_t ScopedVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings,
+                                       int32_t number_of_cores,
+                                       size_t max_payload_size) {
+  return encoder_->InitEncode(codec_settings, number_of_cores,
+                              max_payload_size);
+}
+
+int32_t ScopedVideoEncoder::RegisterEncodeCompleteCallback(
+    webrtc::EncodedImageCallback* callback) {
+  return encoder_->RegisterEncodeCompleteCallback(callback);
+}
+
+int32_t ScopedVideoEncoder::Release() {
+  return encoder_->Release();
+}
+
+int32_t ScopedVideoEncoder::Encode(
+    const webrtc::VideoFrame& frame,
+    const webrtc::CodecSpecificInfo* codec_specific_info,
+    const std::vector<webrtc::FrameType>* frame_types) {
+  return encoder_->Encode(frame, codec_specific_info, frame_types);
+}
+
+int32_t ScopedVideoEncoder::SetChannelParameters(uint32_t packet_loss,
+                                                 int64_t rtt) {
+  return encoder_->SetChannelParameters(packet_loss, rtt);
+}
+
+int32_t ScopedVideoEncoder::SetRates(uint32_t bitrate, uint32_t framerate) {
+  return encoder_->SetRates(bitrate, framerate);
+}
+
+int32_t ScopedVideoEncoder::SetRateAllocation(
+    const webrtc::BitrateAllocation& allocation,
+    uint32_t framerate) {
+  return encoder_->SetRateAllocation(allocation, framerate);
+}
+
+webrtc::VideoEncoder::ScalingSettings ScopedVideoEncoder::GetScalingSettings()
+    const {
+  return encoder_->GetScalingSettings();
+}
+
+int32_t ScopedVideoEncoder::SetPeriodicKeyFrames(bool enable) {
+  return encoder_->SetPeriodicKeyFrames(enable);
+}
+
+bool ScopedVideoEncoder::SupportsNativeHandle() const {
+  return encoder_->SupportsNativeHandle();
+}
+
+const char* ScopedVideoEncoder::ImplementationName() const {
+  return encoder_->ImplementationName();
+}
+
+ScopedVideoEncoder::~ScopedVideoEncoder() {
+  factory_->DestroyVideoEncoder(encoder_);
+}
+
+}  // namespace
+
+std::unique_ptr<webrtc::VideoEncoder> CreateScopedVideoEncoder(
+    WebRtcVideoEncoderFactory* factory,
+    const VideoCodec& codec) {
+  webrtc::VideoEncoder* encoder = factory->CreateVideoEncoder(codec);
+  if (!encoder)
+    return nullptr;
+  return std::unique_ptr<webrtc::VideoEncoder>(
+      new ScopedVideoEncoder(factory, encoder));
+}
+
+}  // namespace cricket
diff --git a/media/engine/scopedvideoencoder.h b/media/engine/scopedvideoencoder.h
new file mode 100644
index 0000000..f0ff40f
--- /dev/null
+++ b/media/engine/scopedvideoencoder.h
@@ -0,0 +1,33 @@
+/*
+ *  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_SCOPEDVIDEOENCODER_H_
+#define WEBRTC_MEDIA_ENGINE_SCOPEDVIDEOENCODER_H_
+
+#include <memory>
+
+#include "webrtc/media/engine/webrtcvideoencoderfactory.h"
+
+namespace cricket {
+
+// Helper function that creates a webrtc::VideoEncoder held by an
+// std::unique_ptr instead of having to be deleted through
+// WebRtcVideoEncoderFactory::DestroyVideoEncoder. The factory passed in must
+// outlive the returned encoder.
+// TODO(magjed): This helper function will be deleted once
+// cricket::WebRtcVideoEncoderFactory is deprecated, see
+// https://bugs.chromium.org/p/webrtc/issues/detail?id=7925 for more info.
+std::unique_ptr<webrtc::VideoEncoder> CreateScopedVideoEncoder(
+    cricket::WebRtcVideoEncoderFactory* factory,
+    const VideoCodec& codec);
+
+}  // namespace cricket
+
+#endif  // WEBRTC_MEDIA_ENGINE_SCOPEDVIDEOENCODER_H_
diff --git a/media/engine/simulcast_encoder_adapter.cc b/media/engine/simulcast_encoder_adapter.cc
index c33dfdd..af84b85 100644
--- a/media/engine/simulcast_encoder_adapter.cc
+++ b/media/engine/simulcast_encoder_adapter.cc
@@ -16,6 +16,7 @@
 #include "libyuv/scale.h"  // NOLINT
 
 #include "webrtc/api/video/i420_buffer.h"
+#include "webrtc/media/engine/scopedvideoencoder.h"
 #include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h"
 #include "webrtc/modules/video_coding/codecs/vp8/simulcast_rate_allocator.h"
 #include "webrtc/rtc_base/checks.h"
@@ -148,14 +149,15 @@
   RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
 
   while (!streaminfos_.empty()) {
-    VideoEncoder* encoder = streaminfos_.back().encoder;
+    std::unique_ptr<VideoEncoder> encoder =
+        std::move(streaminfos_.back().encoder);
     encoder->Release();
     // Even though it seems very unlikely, there are no guarantees that the
     // encoder will not call back after being Release()'d. Therefore, we disable
     // the callbacks here.
     encoder->RegisterEncodeCompleteCallback(nullptr);
     streaminfos_.pop_back();  // Deletes callback adapter.
-    stored_encoders_.push(encoder);
+    stored_encoders_.push(std::move(encoder));
   }
 
   // It's legal to move the encoder to another queue now.
@@ -232,27 +234,28 @@
     // If an existing encoder instance exists, reuse it.
     // TODO(brandtr): Set initial RTP state (e.g., picture_id/tl0_pic_idx) here,
     // when we start storing that state outside the encoder wrappers.
-    VideoEncoder* encoder;
+    std::unique_ptr<VideoEncoder> encoder;
     if (!stored_encoders_.empty()) {
-      encoder = stored_encoders_.top();
+      encoder = std::move(stored_encoders_.top());
       stored_encoders_.pop();
     } else {
-      encoder = factory_->CreateVideoEncoder(cricket::VideoCodec("VP8"));
+      encoder = CreateScopedVideoEncoder(factory_, cricket::VideoCodec("VP8"));
     }
 
     ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size);
     if (ret < 0) {
       // Explicitly destroy the current encoder; because we haven't registered a
       // StreamInfo for it yet, Release won't do anything about it.
-      factory_->DestroyVideoEncoder(encoder);
+      encoder.reset();
       Release();
       return ret;
     }
     std::unique_ptr<EncodedImageCallback> callback(
         new AdapterEncodedImageCallback(this, i));
     encoder->RegisterEncodeCompleteCallback(callback.get());
-    streaminfos_.emplace_back(encoder, std::move(callback), stream_codec.width,
-                              stream_codec.height, start_bitrate_kbps > 0);
+    streaminfos_.emplace_back(std::move(encoder), std::move(callback),
+                              stream_codec.width, stream_codec.height,
+                              start_bitrate_kbps > 0);
 
     if (i != 0) {
       implementation_name += ", ";
@@ -500,8 +503,6 @@
 
 void SimulcastEncoderAdapter::DestroyStoredEncoders() {
   while (!stored_encoders_.empty()) {
-    VideoEncoder* encoder = stored_encoders_.top();
-    factory_->DestroyVideoEncoder(encoder);
     stored_encoders_.pop();
   }
 }
diff --git a/media/engine/simulcast_encoder_adapter.h b/media/engine/simulcast_encoder_adapter.h
index 68af74a..03576f6 100644
--- a/media/engine/simulcast_encoder_adapter.h
+++ b/media/engine/simulcast_encoder_adapter.h
@@ -65,19 +65,18 @@
 
  private:
   struct StreamInfo {
-    StreamInfo(VideoEncoder* encoder,
+    StreamInfo(std::unique_ptr<VideoEncoder> encoder,
                std::unique_ptr<EncodedImageCallback> callback,
                uint16_t width,
                uint16_t height,
                bool send_stream)
-        : encoder(encoder),
+        : encoder(std::move(encoder)),
           callback(std::move(callback)),
           width(width),
           height(height),
           key_frame_request(false),
           send_stream(send_stream) {}
-    // Deleted by SimulcastEncoderAdapter::DestroyStoredEncoders().
-    VideoEncoder* encoder;
+    std::unique_ptr<VideoEncoder> encoder;
     std::unique_ptr<EncodedImageCallback> callback;
     uint16_t width;
     uint16_t height;
@@ -108,7 +107,7 @@
 
   // Store encoders in between calls to Release and InitEncode, so they don't
   // have to be recreated. Remaining encoders are destroyed by the destructor.
-  std::stack<VideoEncoder*> stored_encoders_;
+  std::stack<std::unique_ptr<VideoEncoder>> stored_encoders_;
 };
 
 }  // namespace webrtc
diff --git a/media/engine/webrtcvideoengine.cc b/media/engine/webrtcvideoengine.cc
index 6808f2c..9c11bb9 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/scopedvideoencoder.h"
 #include "webrtc/media/engine/simulcast.h"
 #include "webrtc/media/engine/simulcast_encoder_adapter.h"
 #include "webrtc/media/engine/videodecodersoftwarefallbackwrapper.h"
@@ -55,75 +56,6 @@
   return webrtc::field_trial::IsEnabled("WebRTC-FlexFEC-03-Advertised");
 }
 
-// An encoder factory that wraps Create requests for simulcastable codec types
-// with a webrtc::SimulcastEncoderAdapter. Non simulcastable codec type
-// requests are just passed through to the contained encoder factory.
-class WebRtcSimulcastEncoderFactory
-    : public cricket::WebRtcVideoEncoderFactory {
- public:
-  // WebRtcSimulcastEncoderFactory doesn't take ownership of |factory|, which is
-  // owned by e.g. PeerConnectionFactory.
-  explicit WebRtcSimulcastEncoderFactory(
-      cricket::WebRtcVideoEncoderFactory* factory)
-      : factory_(factory) {}
-
-  static bool UseSimulcastEncoderFactory(
-      const std::vector<cricket::VideoCodec>& codecs) {
-    // If any codec is VP8, use the simulcast factory. If asked to create a
-    // non-VP8 codec, we'll just return a contained factory encoder directly.
-    for (const auto& codec : codecs) {
-      if (CodecNamesEq(codec.name.c_str(), kVp8CodecName)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  webrtc::VideoEncoder* CreateVideoEncoder(
-      const cricket::VideoCodec& codec) override {
-    RTC_DCHECK(factory_ != NULL);
-    // If it's a codec type we can simulcast, create a wrapped encoder.
-    if (CodecNamesEq(codec.name.c_str(), kVp8CodecName)) {
-      return new webrtc::SimulcastEncoderAdapter(factory_);
-    }
-    webrtc::VideoEncoder* encoder = factory_->CreateVideoEncoder(codec);
-    if (encoder) {
-      non_simulcast_encoders_.push_back(encoder);
-    }
-    return encoder;
-  }
-
-  const std::vector<cricket::VideoCodec>& supported_codecs() const override {
-    return factory_->supported_codecs();
-  }
-
-  bool EncoderTypeHasInternalSource(
-      webrtc::VideoCodecType type) const override {
-    return factory_->EncoderTypeHasInternalSource(type);
-  }
-
-  void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) override {
-    // Check first to see if the encoder wasn't wrapped in a
-    // SimulcastEncoderAdapter. In that case, ask the factory to destroy it.
-    if (std::remove(non_simulcast_encoders_.begin(),
-                    non_simulcast_encoders_.end(),
-                    encoder) != non_simulcast_encoders_.end()) {
-      factory_->DestroyVideoEncoder(encoder);
-      return;
-    }
-
-    // Otherwise, SimulcastEncoderAdapter can be deleted directly, and will call
-    // DestroyVideoEncoder on the factory for individual encoder instances.
-    delete encoder;
-  }
-
- private:
-  cricket::WebRtcVideoEncoderFactory* factory_;
-  // A list of encoders that were created without being wrapped in a
-  // SimulcastEncoderAdapter.
-  std::vector<webrtc::VideoEncoder*> non_simulcast_encoders_;
-};
-
 void AddDefaultFeedbackParams(VideoCodec* codec) {
   codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamCcm, kRtcpFbCcmParamFir));
   codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
@@ -441,20 +373,6 @@
 void WebRtcVideoEngine::SetExternalEncoderFactory(
     WebRtcVideoEncoderFactory* encoder_factory) {
   RTC_DCHECK(!initialized_);
-  if (external_encoder_factory_ == encoder_factory)
-    return;
-
-  // No matter what happens we shouldn't hold on to a stale
-  // WebRtcSimulcastEncoderFactory.
-  simulcast_encoder_factory_.reset();
-
-  if (encoder_factory &&
-      WebRtcSimulcastEncoderFactory::UseSimulcastEncoderFactory(
-          encoder_factory->supported_codecs())) {
-    simulcast_encoder_factory_.reset(
-        new WebRtcSimulcastEncoderFactory(encoder_factory));
-    encoder_factory = simulcast_encoder_factory_.get();
-  }
   external_encoder_factory_ = encoder_factory;
 }
 
@@ -1496,18 +1414,19 @@
       codec_settings(codec_settings) {}
 
 WebRtcVideoChannel::WebRtcVideoSendStream::AllocatedEncoder::AllocatedEncoder(
-    webrtc::VideoEncoder* encoder,
+    std::unique_ptr<webrtc::VideoEncoder> encoder,
+    std::unique_ptr<webrtc::VideoEncoder> external_encoder,
     const cricket::VideoCodec& codec,
-    bool external)
-    : encoder(encoder),
-      external_encoder(nullptr),
-      codec(codec),
-      external(external) {
-  if (external) {
-    external_encoder = encoder;
-    this->encoder =
-        new webrtc::VideoEncoderSoftwareFallbackWrapper(codec, encoder);
-  }
+    bool has_internal_source)
+    : encoder_(std::move(encoder)),
+      external_encoder_(std::move(external_encoder)),
+      codec_(codec),
+      has_internal_source_(has_internal_source) {}
+
+void WebRtcVideoChannel::WebRtcVideoSendStream::AllocatedEncoder::Reset() {
+  external_encoder_.reset();
+  encoder_.reset();
+  codec_ = cricket::VideoCodec();
 }
 
 WebRtcVideoChannel::WebRtcVideoSendStream::WebRtcVideoSendStream(
@@ -1535,7 +1454,6 @@
       encoder_sink_(nullptr),
       parameters_(std::move(config), options, max_bitrate_bps, codec_settings),
       rtp_parameters_(CreateRtpParametersWithOneEncoding()),
-      allocated_encoder_(nullptr, cricket::VideoCodec(), false),
       sending_(false) {
   parameters_.config.rtp.max_packet_size = kVideoMtu;
   parameters_.conference_mode = send_params.conference_mode;
@@ -1592,7 +1510,8 @@
   if (stream_ != NULL) {
     call_->DestroyVideoSendStream(stream_);
   }
-  DestroyVideoEncoder(&allocated_encoder_);
+  // Release |allocated_encoder_|.
+  allocated_encoder_.Reset();
 }
 
 bool WebRtcVideoChannel::WebRtcVideoSendStream::SetVideoSend(
@@ -1665,54 +1584,59 @@
 
 WebRtcVideoChannel::WebRtcVideoSendStream::AllocatedEncoder
 WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoder(
-    const VideoCodec& codec,
-    bool force_encoder_allocation) {
+    const VideoCodec& codec) {
   RTC_DCHECK_RUN_ON(&thread_checker_);
-  // Do not re-create encoders of the same type.
-  if (!force_encoder_allocation && codec == allocated_encoder_.codec &&
-      allocated_encoder_.encoder != nullptr) {
-    return allocated_encoder_;
-  }
 
   // Try creating external encoder.
   if (external_encoder_factory_ != nullptr &&
       FindMatchingCodec(external_encoder_factory_->supported_codecs(), codec)) {
-    webrtc::VideoEncoder* encoder =
-        external_encoder_factory_->CreateVideoEncoder(codec);
-    if (encoder != nullptr)
-      return AllocatedEncoder(encoder, codec, true /* is_external */);
+    std::unique_ptr<webrtc::VideoEncoder> external_encoder;
+    if (CodecNamesEq(codec.name.c_str(), kVp8CodecName)) {
+      // If it's a codec type we can simulcast, create a wrapped encoder.
+      external_encoder = std::unique_ptr<webrtc::VideoEncoder>(
+          new webrtc::SimulcastEncoderAdapter(external_encoder_factory_));
+    } else {
+      external_encoder =
+          CreateScopedVideoEncoder(external_encoder_factory_, codec);
+    }
+    if (external_encoder) {
+      std::unique_ptr<webrtc::VideoEncoder> internal_encoder(
+          new webrtc::VideoEncoderSoftwareFallbackWrapper(
+              codec, external_encoder.get()));
+      const webrtc::VideoCodecType codec_type =
+          webrtc::PayloadStringToCodecType(codec.name);
+      const bool has_internal_source =
+          external_encoder_factory_->EncoderTypeHasInternalSource(codec_type);
+      return AllocatedEncoder(std::move(internal_encoder),
+                              std::move(external_encoder), codec,
+                              has_internal_source);
+    }
   }
 
   // Try creating internal encoder.
+  std::unique_ptr<webrtc::VideoEncoder> internal_encoder;
   if (FindMatchingCodec(internal_encoder_factory_->supported_codecs(), codec)) {
-    if (parameters_.encoder_config.content_type ==
+    if (CodecNamesEq(codec.name.c_str(), kVp8CodecName) &&
+        parameters_.encoder_config.content_type ==
             webrtc::VideoEncoderConfig::ContentType::kScreen &&
         parameters_.conference_mode && UseSimulcastScreenshare()) {
       // TODO(sprang): Remove this adapter once libvpx supports simulcast with
       // same-resolution substreams.
-      WebRtcSimulcastEncoderFactory adapter_factory(
-          internal_encoder_factory_.get());
-      return AllocatedEncoder(adapter_factory.CreateVideoEncoder(codec), codec,
-                              false /* is_external */);
+      internal_encoder = std::unique_ptr<webrtc::VideoEncoder>(
+          new webrtc::SimulcastEncoderAdapter(internal_encoder_factory_.get()));
+    } else {
+      internal_encoder = std::unique_ptr<webrtc::VideoEncoder>(
+          internal_encoder_factory_->CreateVideoEncoder(codec));
     }
-    return AllocatedEncoder(
-        internal_encoder_factory_->CreateVideoEncoder(codec), codec,
-        false /* is_external */);
+    return AllocatedEncoder(std::move(internal_encoder),
+                            nullptr /* external_encoder */, codec,
+                            false /* has_internal_source */);
   }
 
   // This shouldn't happen, we should not be trying to create something we don't
   // support.
   RTC_NOTREACHED();
-  return AllocatedEncoder(NULL, cricket::VideoCodec(), false);
-}
-
-void WebRtcVideoChannel::WebRtcVideoSendStream::DestroyVideoEncoder(
-    AllocatedEncoder* encoder) {
-  RTC_DCHECK_RUN_ON(&thread_checker_);
-  if (encoder->external) {
-    external_encoder_factory_->DestroyVideoEncoder(encoder->external_encoder);
-  }
-  delete encoder->encoder;
+  return AllocatedEncoder();
 }
 
 void WebRtcVideoChannel::WebRtcVideoSendStream::SetCodec(
@@ -1722,20 +1646,23 @@
   parameters_.encoder_config = CreateVideoEncoderConfig(codec_settings.codec);
   RTC_DCHECK_GT(parameters_.encoder_config.number_of_streams, 0);
 
-  AllocatedEncoder new_encoder =
-      CreateVideoEncoder(codec_settings.codec, force_encoder_allocation);
-  parameters_.config.encoder_settings.encoder = new_encoder.encoder;
-  parameters_.config.encoder_settings.full_overuse_time = new_encoder.external;
+  // Do not re-create encoders of the same type. We can't overwrite
+  // |allocated_encoder_| immediately, because we need to release it after the
+  // RecreateWebRtcStream() call.
+  AllocatedEncoder new_encoder;
+  if (force_encoder_allocation || !allocated_encoder_.encoder() ||
+      allocated_encoder_.codec() != codec_settings.codec) {
+    new_encoder = CreateVideoEncoder(codec_settings.codec);
+  } else {
+    new_encoder = std::move(allocated_encoder_);
+  }
+  parameters_.config.encoder_settings.encoder = new_encoder.encoder();
+  parameters_.config.encoder_settings.full_overuse_time =
+      new_encoder.IsExternal();
   parameters_.config.encoder_settings.payload_name = codec_settings.codec.name;
   parameters_.config.encoder_settings.payload_type = codec_settings.codec.id;
-  if (new_encoder.external) {
-    webrtc::VideoCodecType type =
-        webrtc::PayloadStringToCodecType(codec_settings.codec.name);
-    parameters_.config.encoder_settings.internal_source =
-        external_encoder_factory_->EncoderTypeHasInternalSource(type);
-  } else {
-    parameters_.config.encoder_settings.internal_source = false;
-  }
+  parameters_.config.encoder_settings.internal_source =
+      new_encoder.HasInternalSource();
   parameters_.config.rtp.ulpfec = codec_settings.ulpfec;
   parameters_.config.rtp.flexfec.payload_type =
       codec_settings.flexfec_payload_type;
@@ -1759,10 +1686,7 @@
 
   LOG(LS_INFO) << "RecreateWebRtcStream (send) because of SetCodec.";
   RecreateWebRtcStream();
-  if (allocated_encoder_.encoder != new_encoder.encoder) {
-    DestroyVideoEncoder(&allocated_encoder_);
-    allocated_encoder_ = new_encoder;
-  }
+  allocated_encoder_ = std::move(new_encoder);
 }
 
 void WebRtcVideoChannel::WebRtcVideoSendStream::SetSendParameters(
diff --git a/media/engine/webrtcvideoengine.h b/media/engine/webrtcvideoengine.h
index 64581dc..caca11c 100644
--- a/media/engine/webrtcvideoengine.h
+++ b/media/engine/webrtcvideoengine.h
@@ -122,7 +122,6 @@
 
   WebRtcVideoDecoderFactory* external_decoder_factory_;
   WebRtcVideoEncoderFactory* external_encoder_factory_;
-  std::unique_ptr<WebRtcVideoEncoderFactory> simulcast_encoder_factory_;
 };
 
 class WebRtcVideoChannel : public VideoMediaChannel, public webrtc::Transport {
@@ -311,24 +310,46 @@
       webrtc::VideoEncoderConfig encoder_config;
     };
 
-    struct AllocatedEncoder {
-      AllocatedEncoder(webrtc::VideoEncoder* encoder,
+    class AllocatedEncoder {
+     public:
+      AllocatedEncoder() = default;
+      AllocatedEncoder(AllocatedEncoder&&) = default;
+      AllocatedEncoder& operator=(AllocatedEncoder&&) = default;
+
+      AllocatedEncoder(std::unique_ptr<webrtc::VideoEncoder> encoder,
+                       std::unique_ptr<webrtc::VideoEncoder> external_encoder,
                        const cricket::VideoCodec& codec,
-                       bool external);
-      webrtc::VideoEncoder* encoder;
-      webrtc::VideoEncoder* external_encoder;
-      cricket::VideoCodec codec;
-      bool external;
+                       bool has_internal_source);
+
+      // Returns a raw pointer to the allocated encoder. This object still has
+      // ownership of the encoder and is responsible for deleting it.
+      webrtc::VideoEncoder* encoder() { return encoder_.get(); }
+
+      // Returns true if the encoder is external.
+      bool IsExternal() { return static_cast<bool>(external_encoder_); }
+
+      cricket::VideoCodec codec() { return codec_; }
+
+      bool HasInternalSource() { return has_internal_source_; }
+
+      // Release the encoders this object manages.
+      void Reset();
+
+     private:
+      std::unique_ptr<webrtc::VideoEncoder> encoder_;
+      // TODO(magjed): |external_encoder_| is not used except for managing
+      // the lifetime when we use VideoEncoderSoftwareFallbackWrapper. Let
+      // VideoEncoderSoftwareFallbackWrapper own the external encoder instead
+      // and remove this member variable.
+      std::unique_ptr<webrtc::VideoEncoder> external_encoder_;
+      cricket::VideoCodec codec_;
+      bool has_internal_source_;
     };
 
     rtc::scoped_refptr<webrtc::VideoEncoderConfig::EncoderSpecificSettings>
     ConfigureVideoEncoderSettings(const VideoCodec& codec);
-    // If force_encoder_allocation is true, a new AllocatedEncoder is always
-    // created. If false, the allocated encoder may be reused, if the type
-    // matches.
-    AllocatedEncoder CreateVideoEncoder(const VideoCodec& codec,
-                                        bool force_encoder_allocation);
-    void DestroyVideoEncoder(AllocatedEncoder* encoder);
+    // Creates and returns a new AllocatedEncoder of the specified codec type.
+    AllocatedEncoder CreateVideoEncoder(const VideoCodec& codec);
     void SetCodec(const VideoCodecSettings& codec,
                   bool force_encoder_allocation);
     void RecreateWebRtcStream();