Move encoder metadata into EncoderInfo struct.

This deprecates the following methods in VideoEncoder:
  virtual ScalingSettings GetScalingSettings() const;
  virtual bool SupportsNativeHandle() const;
  virtual const char* ImplementationName() const;

Though they are not marked RTC_DEPRECATED since we still want to call
them from within the default GetEncoderInfo() until downstream
projects have been updated.

Furthmore, implementation name is changed from const char* to
std:string, which prevents some lifetime issues with dynamic encoder
names, and CodecSpecificInfo.codec_name is removed in favor of getting
the implementation name via GetEncoderInfo().

This CL removes calls to these deprecated methods, follow-ups will also
remove implementations of the methods and replace them with new
GetEncoderInfo() substitutions.

Bug: webrtc:9890
Change-Id: I6fd6e531480c0b952f53dbd5105e0b0adc3e3b0c
Reviewed-on: https://webrtc-review.googlesource.com/c/106905
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Commit-Queue: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25351}
diff --git a/api/video/video_stream_encoder_observer.h b/api/video/video_stream_encoder_observer.h
index b940efd..98b5cfc 100644
--- a/api/video/video_stream_encoder_observer.h
+++ b/api/video/video_stream_encoder_observer.h
@@ -11,6 +11,7 @@
 #ifndef API_VIDEO_VIDEO_STREAM_ENCODER_OBSERVER_H_
 #define API_VIDEO_VIDEO_STREAM_ENCODER_OBSERVER_H_
 
+#include <string>
 #include <vector>
 
 #include "absl/types/optional.h"
@@ -68,6 +69,9 @@
   virtual void OnSendEncodedImage(const EncodedImage& encoded_image,
                                   const CodecSpecificInfo* codec_info) = 0;
 
+  virtual void OnEncoderImplementationChanged(
+      const std::string& implementation_name) = 0;
+
   virtual void OnFrameDropped(DropReason reason) = 0;
 
   // Used to indicate change in content type, which may require a change in
diff --git a/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc b/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc
index 91d65ae..fceea8b 100644
--- a/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc
+++ b/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc
@@ -61,9 +61,7 @@
       ++encode_count_;
       if (encode_complete_callback_ &&
           encode_return_code_ == WEBRTC_VIDEO_CODEC_OK) {
-        CodecSpecificInfo info;
-        info.codec_name = ImplementationName();
-        encode_complete_callback_->OnEncodedImage(EncodedImage(), &info,
+        encode_complete_callback_->OnEncodedImage(EncodedImage(), nullptr,
                                                   nullptr);
       }
       return encode_return_code_;
@@ -91,15 +89,10 @@
       return WEBRTC_VIDEO_CODEC_OK;
     }
 
-    bool SupportsNativeHandle() const override {
+    EncoderInfo GetEncoderInfo() const override {
       ++supports_native_handle_count_;
-      return supports_native_handle_;
-    }
-
-    const char* ImplementationName() const override { return "fake-encoder"; }
-
-    VideoEncoder::ScalingSettings GetScalingSettings() const override {
-      return VideoEncoder::ScalingSettings(kLowThreshold, kHighThreshold);
+      return EncoderInfo(ScalingSettings(kLowThreshold, kHighThreshold),
+                         supports_native_handle_, "fake-encoder");
     }
 
     int init_encode_count_ = 0;
@@ -121,11 +114,9 @@
         const CodecSpecificInfo* codec_specific_info,
         const RTPFragmentationHeader* fragmentation) override {
       ++callback_count_;
-      last_codec_name_ = codec_specific_info->codec_name;
       return Result(Result::OK, callback_count_);
     }
     int callback_count_ = 0;
-    std::string last_codec_name_;
   };
 
   void UtilizeFallbackEncoder();
@@ -133,7 +124,8 @@
   void EncodeFrame();
   void EncodeFrame(int expected_ret);
   void CheckLastEncoderName(const char* expected_name) {
-    EXPECT_STREQ(expected_name, callback_.last_codec_name_.c_str());
+    EXPECT_EQ(expected_name,
+              fallback_wrapper_->GetEncoderInfo().implementation_name);
   }
 
   test::ScopedFieldTrials override_field_trials_;
@@ -290,15 +282,19 @@
 
 TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
        SupportsNativeHandleForwardedWithoutFallback) {
-  fallback_wrapper_->SupportsNativeHandle();
+  fallback_wrapper_->GetEncoderInfo();
   EXPECT_EQ(1, fake_encoder_->supports_native_handle_count_);
 }
 
 TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
        SupportsNativeHandleNotForwardedDuringFallback) {
+  // Fake encoder signals support for native handle, default (libvpx) does not.
+  fake_encoder_->supports_native_handle_ = true;
+  EXPECT_TRUE(fallback_wrapper_->GetEncoderInfo().supports_native_handle);
   UtilizeFallbackEncoder();
-  fallback_wrapper_->SupportsNativeHandle();
-  EXPECT_EQ(0, fake_encoder_->supports_native_handle_count_);
+  EXPECT_FALSE(fallback_wrapper_->GetEncoderInfo().supports_native_handle);
+  // Both times, both encoders are queried.
+  EXPECT_EQ(2, fake_encoder_->supports_native_handle_count_);
   EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_->Release());
 }
 
@@ -488,7 +484,7 @@
   EncodeFrameAndVerifyLastName("fake-encoder");
 
   // Default min pixels per frame should be used.
-  const auto settings = fallback_wrapper_->GetScalingSettings();
+  const auto settings = fallback_wrapper_->GetEncoderInfo().scaling_settings;
   EXPECT_TRUE(settings.thresholds.has_value());
   EXPECT_EQ(kDefaultMinPixelsPerFrame, settings.min_pixels_per_frame);
 }
@@ -499,7 +495,7 @@
   EncodeFrameAndVerifyLastName("fake-encoder");
 
   // Configured min pixels per frame should be used.
-  const auto settings = fallback_wrapper_->GetScalingSettings();
+  const auto settings = fallback_wrapper_->GetEncoderInfo().scaling_settings;
   EXPECT_EQ(kMinPixelsPerFrame, settings.min_pixels_per_frame);
   ASSERT_TRUE(settings.thresholds);
   EXPECT_EQ(kLowThreshold, settings.thresholds->low);
@@ -512,7 +508,7 @@
   EncodeFrameAndVerifyLastName("libvpx");
 
   // Configured min pixels per frame should be used.
-  const auto settings = fallback_wrapper_->GetScalingSettings();
+  const auto settings = fallback_wrapper_->GetEncoderInfo().scaling_settings;
   EXPECT_TRUE(settings.thresholds.has_value());
   EXPECT_EQ(kMinPixelsPerFrame, settings.min_pixels_per_frame);
 }
@@ -524,7 +520,7 @@
   EncodeFrameAndVerifyLastName("libvpx");
 
   // Should be disabled for automatic resize off.
-  const auto settings = fallback_wrapper_->GetScalingSettings();
+  const auto settings = fallback_wrapper_->GetEncoderInfo().scaling_settings;
   EXPECT_FALSE(settings.thresholds.has_value());
 }
 
diff --git a/api/video_codecs/video_encoder.cc b/api/video_codecs/video_encoder.cc
index 33d35de..468d50b 100644
--- a/api/video_codecs/video_encoder.cc
+++ b/api/video_codecs/video_encoder.cc
@@ -83,6 +83,20 @@
 constexpr VideoEncoder::ScalingSettings::KOff
     VideoEncoder::ScalingSettings::kOff;
 
+VideoEncoder::EncoderInfo::EncoderInfo()
+    : scaling_settings(VideoEncoder::ScalingSettings::kOff),
+      supports_native_handle(false),
+      implementation_name("unknown") {}
+
+VideoEncoder::EncoderInfo::EncoderInfo(const ScalingSettings& scaling_settings,
+                                       bool supports_native_handle,
+                                       const std::string& implementation_name)
+    : scaling_settings(scaling_settings),
+      supports_native_handle(supports_native_handle),
+      implementation_name(implementation_name) {}
+
+VideoEncoder::EncoderInfo::~EncoderInfo() = default;
+
 int32_t VideoEncoder::SetRates(uint32_t bitrate, uint32_t framerate) {
   RTC_NOTREACHED() << "SetRate(uint32_t, uint32_t) is deprecated.";
   return -1;
@@ -105,4 +119,9 @@
 const char* VideoEncoder::ImplementationName() const {
   return "unknown";
 }
+
+VideoEncoder::EncoderInfo VideoEncoder::GetEncoderInfo() const {
+  return EncoderInfo(GetScalingSettings(), SupportsNativeHandle(),
+                     ImplementationName());
+}
 }  // namespace webrtc
diff --git a/api/video_codecs/video_encoder.h b/api/video_codecs/video_encoder.h
index 8f7d619..2f42b7d 100644
--- a/api/video_codecs/video_encoder.h
+++ b/api/video_codecs/video_encoder.h
@@ -103,13 +103,13 @@
     ScalingSettings(KOff);  // NOLINT(runtime/explicit)
     ~ScalingSettings();
 
-    const absl::optional<QpThresholds> thresholds;
+    absl::optional<QpThresholds> thresholds;
 
     // We will never ask for a resolution lower than this.
     // TODO(kthelgason): Lower this limit when better testing
     // on MediaCodec and fallback implementations are in place.
     // See https://bugs.chromium.org/p/webrtc/issues/detail?id=7206
-    const int min_pixels_per_frame = 320 * 180;
+    int min_pixels_per_frame = 320 * 180;
 
    private:
     // Private constructor; to get an object without thresholds, use
@@ -117,6 +117,28 @@
     ScalingSettings();
   };
 
+  // Struct containing metadata about the encoder implementing this interface.
+  struct EncoderInfo {
+    EncoderInfo();
+    EncoderInfo(const ScalingSettings& scaling_settings,
+                bool supports_native_handle,
+                const std::string& implementation_name);
+    // EncoderInfo(const EncoderInfo& rhs);
+    // EncoderInfo& operator=(const EncoderInfo& rhs);
+    ~EncoderInfo();
+
+    // Any encoder implementation wishing to use the WebRTC provided
+    // quality scaler must populate this field.
+    ScalingSettings scaling_settings;
+
+    // If true, encoder supports working with a native handle (e.g. texture
+    // handle for hw codecs) rather than requiring a raw I420 buffer.
+    bool supports_native_handle;
+
+    // The name of this particular encoder implementation, e.g. "libvpx".
+    std::string implementation_name;
+  };
+
   static VideoCodecVP8 GetDefaultVp8Settings();
   static VideoCodecVP9 GetDefaultVp9Settings();
   static VideoCodecH264 GetDefaultH264Settings();
@@ -197,12 +219,13 @@
   virtual int32_t SetRateAllocation(const VideoBitrateAllocation& allocation,
                                     uint32_t framerate);
 
-  // Any encoder implementation wishing to use the WebRTC provided
-  // quality scaler must implement this method.
+  // GetScalingSettings(), SupportsNativeHandle(), ImplementationName() are
+  // deprecated, use GetEncoderInfo() instead.
   virtual ScalingSettings GetScalingSettings() const;
-
   virtual bool SupportsNativeHandle() const;
   virtual const char* ImplementationName() const;
+
+  virtual EncoderInfo GetEncoderInfo() const;
 };
 }  // namespace webrtc
 #endif  // API_VIDEO_CODECS_VIDEO_ENCODER_H_
diff --git a/api/video_codecs/video_encoder_software_fallback_wrapper.cc b/api/video_codecs/video_encoder_software_fallback_wrapper.cc
index 99f2970..7bc69d6 100644
--- a/api/video_codecs/video_encoder_software_fallback_wrapper.cc
+++ b/api/video_codecs/video_encoder_software_fallback_wrapper.cc
@@ -90,9 +90,7 @@
   int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override;
   int32_t SetRateAllocation(const VideoBitrateAllocation& bitrate_allocation,
                             uint32_t framerate) override;
-  bool SupportsNativeHandle() const override;
-  ScalingSettings GetScalingSettings() const override;
-  const char* ImplementationName() const override;
+  EncoderInfo GetEncoderInfo() const override;
 
  private:
   bool InitFallbackEncoder();
@@ -162,7 +160,7 @@
   if (forced_fallback_possible_) {
     GetForcedFallbackParamsFromFieldTrialGroup(
         &forced_fallback_.min_pixels_, &forced_fallback_.max_pixels_,
-        encoder_->GetScalingSettings().min_pixels_per_frame -
+        encoder_->GetEncoderInfo().scaling_settings.min_pixels_per_frame -
             1);  // No HW below.
   }
 }
@@ -294,29 +292,29 @@
   return ret;
 }
 
-bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const {
-  return use_fallback_encoder_ ? fallback_encoder_->SupportsNativeHandle()
-                               : encoder_->SupportsNativeHandle();
-}
+VideoEncoder::EncoderInfo VideoEncoderSoftwareFallbackWrapper::GetEncoderInfo()
+    const {
+  EncoderInfo fallback_encoder_info = fallback_encoder_->GetEncoderInfo();
+  EncoderInfo default_encoder_info = encoder_->GetEncoderInfo();
 
-VideoEncoder::ScalingSettings
-VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const {
+  EncoderInfo info =
+      use_fallback_encoder_ ? fallback_encoder_info : default_encoder_info;
+
   if (forced_fallback_possible_) {
     const auto settings = forced_fallback_.active_
-                              ? fallback_encoder_->GetScalingSettings()
-                              : encoder_->GetScalingSettings();
-    return settings.thresholds
-               ? VideoEncoder::ScalingSettings(settings.thresholds->low,
-                                               settings.thresholds->high,
-                                               forced_fallback_.min_pixels_)
-               : VideoEncoder::ScalingSettings::kOff;
+                              ? fallback_encoder_info.scaling_settings
+                              : default_encoder_info.scaling_settings;
+    info.scaling_settings =
+        settings.thresholds
+            ? VideoEncoder::ScalingSettings(settings.thresholds->low,
+                                            settings.thresholds->high,
+                                            forced_fallback_.min_pixels_)
+            : VideoEncoder::ScalingSettings::kOff;
+  } else {
+    info.scaling_settings = default_encoder_info.scaling_settings;
   }
-  return encoder_->GetScalingSettings();
-}
 
-const char* VideoEncoderSoftwareFallbackWrapper::ImplementationName() const {
-  return use_fallback_encoder_ ? fallback_encoder_->ImplementationName()
-                               : encoder_->ImplementationName();
+  return info;
 }
 
 bool VideoEncoderSoftwareFallbackWrapper::IsForcedFallbackActive() const {
diff --git a/media/engine/simulcast_encoder_adapter.cc b/media/engine/simulcast_encoder_adapter.cc
index 80c2ef2..0c507b6 100644
--- a/media/engine/simulcast_encoder_adapter.cc
+++ b/media/engine/simulcast_encoder_adapter.cc
@@ -256,7 +256,8 @@
     if (i != 0) {
       implementation_name += ", ";
     }
-    implementation_name += streaminfos_[i].encoder->ImplementationName();
+    implementation_name +=
+        streaminfos_[i].encoder->GetEncoderInfo().implementation_name;
   }
 
   if (doing_simulcast) {
@@ -451,7 +452,6 @@
     const RTPFragmentationHeader* fragmentation) {
   EncodedImage stream_image(encodedImage);
   CodecSpecificInfo stream_codec_specific = *codecSpecificInfo;
-  stream_codec_specific.codec_name = implementation_name_.c_str();
 
   stream_image.SetSpatialIndex(stream_idx);
 
@@ -519,7 +519,6 @@
 bool SimulcastEncoderAdapter::SupportsNativeHandle() const {
   RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_);
   // We should not be calling this method before streaminfos_ are configured.
-  RTC_DCHECK(!streaminfos_.empty());
   for (const auto& streaminfo : streaminfos_) {
     if (!streaminfo.encoder->SupportsNativeHandle()) {
       return false;
diff --git a/media/engine/simulcast_encoder_adapter_unittest.cc b/media/engine/simulcast_encoder_adapter_unittest.cc
index 91d83e9..85c9463 100644
--- a/media/engine/simulcast_encoder_adapter_unittest.cc
+++ b/media/engine/simulcast_encoder_adapter_unittest.cc
@@ -735,9 +735,9 @@
   adapter_->RegisterEncodeCompleteCallback(this);
   ASSERT_EQ(1u, helper_->factory()->encoders().size());
   helper_->factory()->encoders()[0]->set_supports_native_handle(true);
-  EXPECT_TRUE(adapter_->SupportsNativeHandle());
+  EXPECT_TRUE(adapter_->GetEncoderInfo().supports_native_handle);
   helper_->factory()->encoders()[0]->set_supports_native_handle(false);
-  EXPECT_FALSE(adapter_->SupportsNativeHandle());
+  EXPECT_FALSE(adapter_->GetEncoderInfo().supports_native_handle);
 }
 
 TEST_F(TestSimulcastEncoderAdapterFake, SetRatesUnderMinBitrate) {
@@ -770,7 +770,8 @@
 }
 
 TEST_F(TestSimulcastEncoderAdapterFake, SupportsImplementationName) {
-  EXPECT_STREQ("SimulcastEncoderAdapter", adapter_->ImplementationName());
+  EXPECT_EQ("SimulcastEncoderAdapter",
+            adapter_->GetEncoderInfo().implementation_name);
   SimulcastTestFixtureImpl::DefaultSettings(
       &codec_, static_cast<const int*>(kTestTemporalLayerProfile),
       kVideoCodecVP8);
@@ -780,8 +781,8 @@
   encoder_names.push_back("codec3");
   helper_->factory()->SetEncoderNames(encoder_names);
   EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
-  EXPECT_STREQ("SimulcastEncoderAdapter (codec1, codec2, codec3)",
-               adapter_->ImplementationName());
+  EXPECT_EQ("SimulcastEncoderAdapter (codec1, codec2, codec3)",
+            adapter_->GetEncoderInfo().implementation_name);
 
   // Single streams should not expose "SimulcastEncoderAdapter" in name.
   EXPECT_EQ(0, adapter_->Release());
@@ -789,7 +790,7 @@
   EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200));
   adapter_->RegisterEncodeCompleteCallback(this);
   ASSERT_EQ(1u, helper_->factory()->encoders().size());
-  EXPECT_STREQ("codec1", adapter_->ImplementationName());
+  EXPECT_EQ("codec1", adapter_->GetEncoderInfo().implementation_name);
 }
 
 TEST_F(TestSimulcastEncoderAdapterFake,
@@ -805,10 +806,10 @@
     encoder->set_supports_native_handle(true);
   // If one encoder doesn't support it, then overall support is disabled.
   helper_->factory()->encoders()[0]->set_supports_native_handle(false);
-  EXPECT_FALSE(adapter_->SupportsNativeHandle());
+  EXPECT_FALSE(adapter_->GetEncoderInfo().supports_native_handle);
   // Once all do, then the adapter claims support.
   helper_->factory()->encoders()[0]->set_supports_native_handle(true);
-  EXPECT_TRUE(adapter_->SupportsNativeHandle());
+  EXPECT_TRUE(adapter_->GetEncoderInfo().supports_native_handle);
 }
 
 // TODO(nisse): Reuse definition in webrtc/test/fake_texture_handle.h.
@@ -844,7 +845,7 @@
   ASSERT_EQ(3u, helper_->factory()->encoders().size());
   for (MockVideoEncoder* encoder : helper_->factory()->encoders())
     encoder->set_supports_native_handle(true);
-  EXPECT_TRUE(adapter_->SupportsNativeHandle());
+  EXPECT_TRUE(adapter_->GetEncoderInfo().supports_native_handle);
 
   rtc::scoped_refptr<VideoFrameBuffer> buffer(
       new rtc::RefCountedObject<FakeNativeBufferNoI420>(1280, 720));
diff --git a/media/engine/vp8_encoder_simulcast_proxy_unittest.cc b/media/engine/vp8_encoder_simulcast_proxy_unittest.cc
index fc6d5a6..d0a0dfc 100644
--- a/media/engine/vp8_encoder_simulcast_proxy_unittest.cc
+++ b/media/engine/vp8_encoder_simulcast_proxy_unittest.cc
@@ -104,7 +104,8 @@
                                                    SdpVideoFormat("VP8"));
   EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
             simulcast_enabled_proxy.InitEncode(&codec_settings, 4, 1200));
-  EXPECT_EQ(kImplementationName, simulcast_enabled_proxy.ImplementationName());
+  EXPECT_EQ(kImplementationName,
+            simulcast_enabled_proxy.GetEncoderInfo().implementation_name);
 
   NiceMock<MockEncoder>* mock_encoder1 = new NiceMock<MockEncoder>();
   NiceMock<MockEncoder>* mock_encoder2 = new NiceMock<MockEncoder>();
@@ -145,7 +146,7 @@
   EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
             simulcast_disabled_proxy.InitEncode(&codec_settings, 4, 1200));
   EXPECT_EQ(kSimulcastAdaptedImplementationName,
-            simulcast_disabled_proxy.ImplementationName());
+            simulcast_disabled_proxy.GetEncoderInfo().implementation_name);
 
   // Cleanup.
   simulcast_enabled_proxy.Release();
diff --git a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc
index 263e401..e8a666f 100644
--- a/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc
+++ b/modules/video_coding/codecs/test/videocodec_test_fixture_impl.cc
@@ -671,7 +671,7 @@
   std::string encoder_name;
   std::string decoder_name;
   task_queue->SendTask([this, &encoder_name, &decoder_name] {
-    encoder_name = encoder_->ImplementationName();
+    encoder_name = encoder_->GetEncoderInfo().implementation_name;
     decoder_name = decoders_.at(0)->ImplementationName();
   });
   printf("enc_impl_name: %s\n", encoder_name.c_str());
diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc
index a7f060f..b92aa77 100644
--- a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc
+++ b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc
@@ -843,7 +843,6 @@
                                              uint32_t timestamp) {
   assert(codec_specific != NULL);
   codec_specific->codecType = kVideoCodecVP8;
-  codec_specific->codec_name = ImplementationName();
   CodecSpecificInfoVP8* vp8Info = &(codec_specific->codecSpecific.VP8);
   vp8Info->keyIdx = kNoKeyIdx;  // TODO(hlundin) populate this
   vp8Info->nonReference = (pkt.data.frame.flags & VPX_FRAME_IS_DROPPABLE) != 0;
diff --git a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
index 5659a37..5eed5d3 100644
--- a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
+++ b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
@@ -77,7 +77,7 @@
               encoder_->Encode(input_frame, nullptr, &frame_types));
     ASSERT_TRUE(WaitForEncodedFrame(encoded_frame, codec_specific_info));
     VerifyQpParser(*encoded_frame);
-    EXPECT_STREQ("libvpx", codec_specific_info->codec_name);
+    EXPECT_EQ("libvpx", encoder_->GetEncoderInfo().implementation_name);
     EXPECT_EQ(kVideoCodecVP8, codec_specific_info->codecType);
     EXPECT_EQ(0, encoded_frame->SpatialIndex());
   }
@@ -334,7 +334,8 @@
   EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
             encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
 
-  VideoEncoder::ScalingSettings settings = encoder_->GetScalingSettings();
+  VideoEncoder::ScalingSettings settings =
+      encoder_->GetEncoderInfo().scaling_settings;
   EXPECT_FALSE(settings.thresholds.has_value());
 }
 
@@ -344,7 +345,8 @@
   EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
             encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
 
-  VideoEncoder::ScalingSettings settings = encoder_->GetScalingSettings();
+  VideoEncoder::ScalingSettings settings =
+      encoder_->GetEncoderInfo().scaling_settings;
   EXPECT_TRUE(settings.thresholds.has_value());
   EXPECT_EQ(kDefaultMinPixelsPerFrame, settings.min_pixels_per_frame);
 }
diff --git a/modules/video_coding/codecs/vp9/vp9_impl.cc b/modules/video_coding/codecs/vp9/vp9_impl.cc
index 3e58e44..0cc5275 100644
--- a/modules/video_coding/codecs/vp9/vp9_impl.cc
+++ b/modules/video_coding/codecs/vp9/vp9_impl.cc
@@ -837,7 +837,6 @@
                                            bool first_frame_in_picture) {
   RTC_CHECK(codec_specific != nullptr);
   codec_specific->codecType = kVideoCodecVP9;
-  codec_specific->codec_name = ImplementationName();
   CodecSpecificInfoVP9* vp9_info = &(codec_specific->codecSpecific.VP9);
 
   vp9_info->first_frame_in_picture = first_frame_in_picture;
diff --git a/modules/video_coding/generic_encoder.cc b/modules/video_coding/generic_encoder.cc
index b1d7c28..485fe78 100644
--- a/modules/video_coding/generic_encoder.cc
+++ b/modules/video_coding/generic_encoder.cc
@@ -166,7 +166,7 @@
 
 bool VCMGenericEncoder::SupportsNativeHandle() const {
   RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
-  return encoder_->SupportsNativeHandle();
+  return encoder_->GetEncoderInfo().supports_native_handle;
 }
 
 VCMEncodedFrameCallback::VCMEncodedFrameCallback(
diff --git a/modules/video_coding/include/video_codec_interface.h b/modules/video_coding/include/video_codec_interface.h
index d2badf9..38583bf 100644
--- a/modules/video_coding/include/video_codec_interface.h
+++ b/modules/video_coding/include/video_codec_interface.h
@@ -79,6 +79,7 @@
     memset(&codecSpecific, 0, sizeof(codecSpecific));
   }
   VideoCodecType codecType;
+  // |codec_name| is deprecated, use name provided by VideoEncoder instead.
   const char* codec_name;
   CodecSpecificInfoUnion codecSpecific;
 };
diff --git a/sdk/android/src/jni/videoencoderwrapper.cc b/sdk/android/src/jni/videoencoderwrapper.cc
index 6381c63..50437be 100644
--- a/sdk/android/src/jni/videoencoderwrapper.cc
+++ b/sdk/android/src/jni/videoencoderwrapper.cc
@@ -385,7 +385,6 @@
   CodecSpecificInfo info;
   memset(&info, 0, sizeof(info));
   info.codecType = codec_settings_.codecType;
-  info.codec_name = implementation_name_.c_str();
 
   switch (codec_settings_.codecType) {
     case kVideoCodecVP8:
diff --git a/test/fake_encoder.cc b/test/fake_encoder.cc
index ca99038..c151e4c 100644
--- a/test/fake_encoder.cc
+++ b/test/fake_encoder.cc
@@ -128,7 +128,6 @@
                                 ? VideoContentType::SCREENSHARE
                                 : VideoContentType::UNSPECIFIED;
     encoded.SetSpatialIndex(i);
-    specifics.codec_name = ImplementationName();
     if (callback->OnEncodedImage(encoded, &specifics, nullptr).error !=
         EncodedImageCallback::Result::OK) {
       return -1;
diff --git a/test/fake_vp8_encoder.cc b/test/fake_vp8_encoder.cc
index 82ba88b..fedb9c1 100644
--- a/test/fake_vp8_encoder.cc
+++ b/test/fake_vp8_encoder.cc
@@ -106,7 +106,6 @@
                                            uint32_t timestamp) {
   RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
   codec_specific->codecType = kVideoCodecVP8;
-  codec_specific->codec_name = ImplementationName();
   CodecSpecificInfoVP8* vp8Info = &(codec_specific->codecSpecific.VP8);
   vp8Info->keyIdx = kNoKeyIdx;
   vp8Info->nonReference = false;
diff --git a/video/send_statistics_proxy.cc b/video/send_statistics_proxy.cc
index 9839ed7..e11304b 100644
--- a/video/send_statistics_proxy.cc
+++ b/video/send_statistics_proxy.cc
@@ -823,10 +823,13 @@
 
   const int64_t now_ms = clock_->TimeInMilliseconds();
   bool is_active = fallback_info->is_active;
-  if (codec_info->codec_name != stats_.encoder_implementation_name) {
+  if (encoder_changed_) {
     // Implementation changed.
-    is_active = strcmp(codec_info->codec_name, kVp8SwCodecName) == 0;
-    if (!is_active && stats_.encoder_implementation_name != kVp8SwCodecName) {
+    const bool last_was_vp8_software =
+        encoder_changed_->previous_encoder_implementation == kVp8SwCodecName;
+    is_active = encoder_changed_->new_encoder_implementation == kVp8SwCodecName;
+    encoder_changed_.reset();
+    if (!is_active && !last_was_vp8_software) {
       // First or not a VP8 SW change, update stats on next call.
       return;
     }
@@ -865,7 +868,7 @@
   }
 
   if (!IsForcedFallbackPossible(codec_info, simulcast_index) ||
-      strcmp(codec_info->codec_name, kVp8SwCodecName) == 0) {
+      stats_.encoder_implementation_name == kVp8SwCodecName) {
     uma_container_->fallback_info_disabled_.is_possible = false;
     return;
   }
@@ -895,13 +898,9 @@
   rtc::CritScope lock(&crit_);
   ++stats_.frames_encoded;
   if (codec_info) {
-    if (codec_info->codec_name) {
-      UpdateEncoderFallbackStats(
-          codec_info,
-          encoded_image._encodedWidth * encoded_image._encodedHeight,
-          simulcast_idx);
-      stats_.encoder_implementation_name = codec_info->codec_name;
-    }
+    UpdateEncoderFallbackStats(
+        codec_info, encoded_image._encodedWidth * encoded_image._encodedHeight,
+        simulcast_idx);
   }
 
   if (static_cast<size_t>(simulcast_idx) >= rtp_config_.ssrcs.size()) {
@@ -981,6 +980,14 @@
   }
 }
 
+void SendStatisticsProxy::OnEncoderImplementationChanged(
+    const std::string& implementation_name) {
+  rtc::CritScope lock(&crit_);
+  encoder_changed_ = EncoderChangeEvent{stats_.encoder_implementation_name,
+                                        implementation_name};
+  stats_.encoder_implementation_name = implementation_name;
+}
+
 int SendStatisticsProxy::GetInputFrameRate() const {
   rtc::CritScope lock(&crit_);
   return round(uma_container_->input_frame_rate_tracker_.ComputeRate());
diff --git a/video/send_statistics_proxy.h b/video/send_statistics_proxy.h
index b5868d0..2fa87cc 100644
--- a/video/send_statistics_proxy.h
+++ b/video/send_statistics_proxy.h
@@ -53,6 +53,10 @@
 
   void OnSendEncodedImage(const EncodedImage& encoded_image,
                           const CodecSpecificInfo* codec_info) override;
+
+  void OnEncoderImplementationChanged(
+      const std::string& implementation_name) override;
+
   // Used to update incoming frame rate.
   void OnIncomingFrame(int width, int height) override;
 
@@ -241,6 +245,14 @@
 
   absl::optional<int64_t> last_outlier_timestamp_ RTC_GUARDED_BY(crit_);
 
+  struct EncoderChangeEvent {
+    std::string previous_encoder_implementation;
+    std::string new_encoder_implementation;
+  };
+  // Stores the last change in encoder implementation in an optional, so that
+  // the event can be consumed.
+  absl::optional<EncoderChangeEvent> encoder_changed_;
+
   // Contains stats used for UMA histograms. These stats will be reset if
   // content type changes between real-time video and screenshare, since these
   // will be reported separately.
diff --git a/video/send_statistics_proxy_unittest.cc b/video/send_statistics_proxy_unittest.cc
index 3d27c71..586d57f 100644
--- a/video/send_statistics_proxy_unittest.cc
+++ b/video/send_statistics_proxy_unittest.cc
@@ -2167,13 +2167,9 @@
 }
 
 TEST_F(SendStatisticsProxyTest, GetStatsReportsEncoderImplementationName) {
-  const char* kName = "encoderName";
-  EncodedImage encoded_image;
-  CodecSpecificInfo codec_info;
-  codec_info.codec_name = kName;
-  statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
-  EXPECT_STREQ(
-      kName, statistics_proxy_->GetStats().encoder_implementation_name.c_str());
+  const std::string kName = "encoderName";
+  statistics_proxy_->OnEncoderImplementationChanged(kName);
+  EXPECT_EQ(kName, statistics_proxy_->GetStats().encoder_implementation_name);
 }
 
 TEST_F(SendStatisticsProxyTest, Vp9SvcLowSpatialLayerDoesNotUpdateResolution) {
@@ -2219,7 +2215,6 @@
       : SendStatisticsProxyTest(field_trials) {
     codec_info_.codecType = kVideoCodecVP8;
     codec_info_.codecSpecific.VP8.temporalIdx = 0;
-    codec_info_.codec_name = "fake_codec";
     encoded_image_._encodedWidth = kWidth;
     encoded_image_._encodedHeight = kHeight;
     encoded_image_.SetSpatialIndex(0);
@@ -2229,6 +2224,8 @@
 
  protected:
   void InsertEncodedFrames(int num_frames, int interval_ms) {
+    statistics_proxy_->OnEncoderImplementationChanged(codec_name_);
+
     // First frame is not updating stats, insert initial frame.
     if (statistics_proxy_->GetStats().frames_encoded == 0) {
       statistics_proxy_->OnSendEncodedImage(encoded_image_, &codec_info_);
@@ -2243,6 +2240,7 @@
 
   EncodedImage encoded_image_;
   CodecSpecificInfo codec_info_;
+  std::string codec_name_;
   const std::string kPrefix = "WebRTC.Video.Encoder.ForcedSw";
   const int kFrameIntervalMs = 1000;
   const int kMinFrames = 20;  // Min run time 20 sec.
@@ -2321,7 +2319,7 @@
 }
 
 TEST_F(ForcedFallbackEnabled, EnteredLowResolutionSetIfLibvpx) {
-  codec_info_.codec_name = "libvpx";
+  codec_name_ = "libvpx";
   InsertEncodedFrames(1, kFrameIntervalMs);
   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
 }
@@ -2333,7 +2331,7 @@
 }
 
 TEST_F(ForcedFallbackDisabled, EnteredLowResolutionNotSetIfLibvpx) {
-  codec_info_.codec_name = "libvpx";
+  codec_name_ = "libvpx";
   InsertEncodedFrames(1, kFrameIntervalMs);
   EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
 }
@@ -2351,7 +2349,7 @@
   EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
   InsertEncodedFrames(15, 1000);
   EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
-  codec_info_.codec_name = "libvpx";
+  codec_name_ = "libvpx";
   InsertEncodedFrames(5, 1000);
   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
 
@@ -2369,18 +2367,18 @@
   // Three changes. Video: 60000 ms, fallback: 15000 ms (25%).
   InsertEncodedFrames(10, 1000);
   EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
-  codec_info_.codec_name = "libvpx";
+  codec_name_ = "libvpx";
   InsertEncodedFrames(15, 500);
   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
-  codec_info_.codec_name = "notlibvpx";
+  codec_name_ = "notlibvpx";
   InsertEncodedFrames(20, 1000);
   InsertEncodedFrames(3, kMaxFrameDiffMs);  // Should not be included.
   InsertEncodedFrames(10, 1000);
   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
-  codec_info_.codec_name = "notlibvpx2";
+  codec_name_ = "notlibvpx2";
   InsertEncodedFrames(10, 500);
   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
-  codec_info_.codec_name = "libvpx";
+  codec_name_ = "libvpx";
   InsertEncodedFrames(15, 500);
   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
 
@@ -2393,7 +2391,7 @@
 
 TEST_F(ForcedFallbackEnabled, NoFallbackIfAboveMaxPixels) {
   encoded_image_._encodedWidth = kWidth + 1;
-  codec_info_.codec_name = "libvpx";
+  codec_name_ = "libvpx";
   InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
 
   EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
@@ -2404,7 +2402,7 @@
 
 TEST_F(ForcedFallbackEnabled, FallbackIfAtMaxPixels) {
   encoded_image_._encodedWidth = kWidth;
-  codec_info_.codec_name = "libvpx";
+  codec_name_ = "libvpx";
   InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
 
   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc
index 786ded4..6f734fb 100644
--- a/video/video_stream_encoder.cc
+++ b/video/video_stream_encoder.cc
@@ -363,6 +363,8 @@
       max_framerate_(-1),
       pending_encoder_reconfiguration_(false),
       pending_encoder_creation_(false),
+      crop_width_(0),
+      crop_height_(0),
       encoder_start_bitrate_bps_(0),
       max_data_payload_length_(0),
       last_observed_bitrate_bps_(0),
@@ -376,6 +378,7 @@
       last_frame_log_ms_(clock_->TimeInMilliseconds()),
       captured_frame_count_(0),
       dropped_frame_count_(0),
+      pending_frame_post_time_us_(0),
       bitrate_observer_(nullptr),
       encoder_queue_("EncoderQueue") {
   RTC_DCHECK(encoder_stats_observer);
@@ -629,7 +632,7 @@
 
 void VideoStreamEncoder::ConfigureQualityScaler() {
   RTC_DCHECK_RUN_ON(&encoder_queue_);
-  const auto scaling_settings = encoder_->GetScalingSettings();
+  const auto scaling_settings = encoder_->GetEncoderInfo().scaling_settings;
   const bool quality_scaling_allowed =
       IsResolutionScalingEnabled(degradation_preference_) &&
       scaling_settings.thresholds;
@@ -887,6 +890,14 @@
 
   overuse_detector_->FrameCaptured(out_frame, time_when_posted_us);
 
+  // Encoder metadata needs to be updated before encode complete callback.
+  VideoEncoder::EncoderInfo info = encoder_->GetEncoderInfo();
+  if (info.implementation_name != encoder_info_.implementation_name) {
+    encoder_stats_observer_->OnEncoderImplementationChanged(
+        info.implementation_name);
+  }
+  encoder_info_ = info;
+
   video_sender_.AddVideoFrame(out_frame, nullptr);
 }
 
@@ -1085,7 +1096,7 @@
       bool min_pixels_reached = false;
       if (!source_proxy_->RequestResolutionLowerThan(
               adaptation_request.input_pixel_count_,
-              encoder_->GetScalingSettings().min_pixels_per_frame,
+              encoder_->GetEncoderInfo().scaling_settings.min_pixels_per_frame,
               &min_pixels_reached)) {
         if (min_pixels_reached)
           encoder_stats_observer_->OnMinPixelLimitReached();
diff --git a/video/video_stream_encoder.h b/video/video_stream_encoder.h
index 4008426..8c5efbe 100644
--- a/video/video_stream_encoder.h
+++ b/video/video_stream_encoder.h
@@ -268,6 +268,8 @@
   absl::optional<int64_t> last_parameters_update_ms_
       RTC_GUARDED_BY(&encoder_queue_);
 
+  VideoEncoder::EncoderInfo encoder_info_ RTC_GUARDED_BY(&encoder_queue_);
+
   // All public methods are proxied to |encoder_queue_|. It must must be
   // destroyed first to make sure no tasks are run that use other members.
   rtc::TaskQueue encoder_queue_;