Delete post_encode_callback

Bug: webrtc:9864
Change-Id: I5e45a73e50e2cf6b25b415a83fe637f8f5b4e70e
Reviewed-on: https://webrtc-review.googlesource.com/c/14840
Commit-Queue: Niels Moller <nisse@webrtc.org>
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25106}
diff --git a/call/video_receive_stream.h b/call/video_receive_stream.h
index 49efe4f..071e1f2 100644
--- a/call/video_receive_stream.h
+++ b/call/video_receive_stream.h
@@ -26,7 +26,6 @@
 #include "api/video_codecs/sdp_video_format.h"
 #include "call/rtp_config.h"
 #include "common_types.h"  // NOLINT(build/include)
-#include "common_video/include/frame_callback.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 
 namespace webrtc {
diff --git a/call/video_send_stream.cc b/call/video_send_stream.cc
index 6b93fe2..a116155 100644
--- a/call/video_send_stream.cc
+++ b/call/video_send_stream.cc
@@ -78,8 +78,6 @@
   ss << ", rtcp: " << rtcp.ToString();
   ss << ", pre_encode_callback: "
      << (pre_encode_callback ? "(VideoSinkInterface)" : "nullptr");
-  ss << ", post_encode_callback: "
-     << (post_encode_callback ? "(EncodedFrameObserver)" : "nullptr");
   ss << ", render_delay_ms: " << render_delay_ms;
   ss << ", target_delay_ms: " << target_delay_ms;
   ss << ", suspend_below_min_bitrate: "
diff --git a/call/video_send_stream.h b/call/video_send_stream.h
index 3ff624d..918ce93 100644
--- a/call/video_send_stream.h
+++ b/call/video_send_stream.h
@@ -17,6 +17,7 @@
 #include <vector>
 
 #include "api/call/transport.h"
+#include "api/video/video_frame.h"
 #include "api/video/video_sink_interface.h"
 #include "api/video/video_source_interface.h"
 #include "api/video/video_stream_encoder_settings.h"
@@ -24,7 +25,6 @@
 #include "api/video_codecs/video_encoder_factory.h"
 #include "call/rtp_config.h"
 #include "common_types.h"  // NOLINT(build/include)
-#include "common_video/include/frame_callback.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 
 namespace webrtc {
@@ -117,12 +117,6 @@
     // effects, snapshots etc. 'nullptr' disables the callback.
     rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback = nullptr;
 
-    // Called for each encoded frame, e.g. used for file storage. 'nullptr'
-    // disables the callback. Also measures timing and passes the time
-    // spent on encoding. This timing will not fire if encoding takes longer
-    // than the measuring window, since the sample data will have been dropped.
-    EncodedFrameObserver* post_encode_callback = nullptr;
-
     // Expected delay needed by the renderer, i.e. the frame will be delivered
     // this many milliseconds, if possible, earlier than expected render time.
     // Only valid if |local_renderer| is set.
diff --git a/common_video/BUILD.gn b/common_video/BUILD.gn
index 665535a..fa0d855 100644
--- a/common_video/BUILD.gn
+++ b/common_video/BUILD.gn
@@ -26,7 +26,6 @@
     "h264/sps_vui_rewriter.h",
     "i420_buffer_pool.cc",
     "include/bitrate_adjuster.h",
-    "include/frame_callback.h",
     "include/i420_buffer_pool.h",
     "include/incoming_video_stream.h",
     "include/video_frame.h",
diff --git a/common_video/include/frame_callback.h b/common_video/include/frame_callback.h
deleted file mode 100644
index a3883c1..0000000
--- a/common_video/include/frame_callback.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- *  Copyright (c) 2013 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 COMMON_VIDEO_INCLUDE_FRAME_CALLBACK_H_
-#define COMMON_VIDEO_INCLUDE_FRAME_CALLBACK_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "common_types.h"  // NOLINT(build/include)
-
-namespace webrtc {
-
-class VideoFrame;
-
-struct EncodedFrame {
- public:
-  EncodedFrame()
-      : data_(nullptr),
-        length_(0),
-        frame_type_(kEmptyFrame),
-        stream_id_(0),
-        timestamp_(0) {}
-  EncodedFrame(const uint8_t* data,
-               size_t length,
-               FrameType frame_type,
-               size_t stream_id,
-               uint32_t timestamp)
-      : data_(data),
-        length_(length),
-        frame_type_(frame_type),
-        stream_id_(stream_id),
-        timestamp_(timestamp) {}
-
-  const uint8_t* data_;
-  const size_t length_;
-  const FrameType frame_type_;
-  const size_t stream_id_;
-  const uint32_t timestamp_;
-};
-
-class EncodedFrameObserver {
- public:
-  virtual void EncodedFrameCallback(const EncodedFrame& encoded_frame) = 0;
-
- protected:
-  virtual ~EncodedFrameObserver() {}
-};
-
-}  // namespace webrtc
-
-#endif  // COMMON_VIDEO_INCLUDE_FRAME_CALLBACK_H_
diff --git a/modules/video_coding/video_coding_impl.h b/modules/video_coding/video_coding_impl.h
index 3c09f96..04c6714 100644
--- a/modules/video_coding/video_coding_impl.h
+++ b/modules/video_coding/video_coding_impl.h
@@ -17,7 +17,6 @@
 #include <string>
 #include <vector>
 
-#include "common_video/include/frame_callback.h"
 #include "modules/video_coding/decoder_database.h"
 #include "modules/video_coding/encoder_database.h"
 #include "modules/video_coding/frame_buffer.h"
diff --git a/video/end_to_end_tests/call_operation_tests.cc b/video/end_to_end_tests/call_operation_tests.cc
index 2821451..31b0ed6 100644
--- a/video/end_to_end_tests/call_operation_tests.cc
+++ b/video/end_to_end_tests/call_operation_tests.cc
@@ -221,79 +221,4 @@
   });
 }
 
-TEST_P(CallOperationEndToEndTest, ObserversEncodedFrames) {
-  class EncodedFrameTestObserver : public EncodedFrameObserver {
-   public:
-    EncodedFrameTestObserver()
-        : length_(0), frame_type_(kEmptyFrame), called_(false, false) {}
-    virtual ~EncodedFrameTestObserver() {}
-
-    virtual void EncodedFrameCallback(const EncodedFrame& encoded_frame) {
-      frame_type_ = encoded_frame.frame_type_;
-      length_ = encoded_frame.length_;
-      buffer_.reset(new uint8_t[length_]);
-      memcpy(buffer_.get(), encoded_frame.data_, length_);
-      called_.Set();
-    }
-
-    bool Wait() { return called_.Wait(kDefaultTimeoutMs); }
-
-   private:
-    std::unique_ptr<uint8_t[]> buffer_;
-    size_t length_;
-    FrameType frame_type_;
-    rtc::Event called_;
-  };
-
-  EncodedFrameTestObserver post_encode_observer;
-  test::FrameForwarder forwarder;
-  std::unique_ptr<test::FrameGenerator> frame_generator;
-
-  std::unique_ptr<test::DirectTransport> sender_transport;
-  std::unique_ptr<test::DirectTransport> receiver_transport;
-
-  task_queue_.SendTask([&]() {
-    CreateCalls();
-
-    sender_transport = absl::make_unique<test::DirectTransport>(
-        &task_queue_,
-        absl::make_unique<FakeNetworkPipe>(Clock::GetRealTimeClock(),
-                                           absl::make_unique<SimulatedNetwork>(
-                                               BuiltInNetworkBehaviorConfig())),
-        sender_call_.get(), payload_type_map_);
-    receiver_transport = absl::make_unique<test::DirectTransport>(
-        &task_queue_,
-        absl::make_unique<FakeNetworkPipe>(Clock::GetRealTimeClock(),
-                                           absl::make_unique<SimulatedNetwork>(
-                                               BuiltInNetworkBehaviorConfig())),
-        receiver_call_.get(), payload_type_map_);
-    sender_transport->SetReceiver(receiver_call_->Receiver());
-    receiver_transport->SetReceiver(sender_call_->Receiver());
-
-    CreateSendConfig(1, 0, 0, sender_transport.get());
-    CreateMatchingReceiveConfigs(receiver_transport.get());
-    GetVideoSendConfig()->post_encode_callback = &post_encode_observer;
-
-    CreateVideoStreams();
-    Start();
-
-    frame_generator = test::FrameGenerator::CreateSquareGenerator(
-        kDefaultWidth, kDefaultHeight, absl::nullopt, absl::nullopt);
-    GetVideoSendStream()->SetSource(&forwarder,
-                                    DegradationPreference::MAINTAIN_FRAMERATE);
-    forwarder.IncomingCapturedFrame(*frame_generator->NextFrame());
-  });
-
-  EXPECT_TRUE(post_encode_observer.Wait())
-      << "Timed out while waiting for send-side encoded-frame callback.";
-
-  task_queue_.SendTask([this, &sender_transport, &receiver_transport]() {
-    Stop();
-    DestroyStreams();
-    sender_transport.reset();
-    receiver_transport.reset();
-    DestroyCalls();
-  });
-}
-
 }  // namespace webrtc
diff --git a/video/video_analyzer.cc b/video/video_analyzer.cc
index 05abe1f..1b1c557 100644
--- a/video/video_analyzer.cc
+++ b/video/video_analyzer.cc
@@ -70,7 +70,6 @@
       selected_stream_(selected_stream),
       selected_sl_(selected_sl),
       selected_tl_(selected_tl),
-      pre_encode_proxy_(this),
       last_fec_bytes_(0),
       frames_to_process_(duration_frames),
       frames_recorded_(0),
@@ -231,10 +230,10 @@
   }
 }
 
-void VideoAnalyzer::EncodedFrameCallback(const EncodedFrame& encoded_frame) {
+void VideoAnalyzer::PostEncodeOnFrame(size_t stream_id, uint32_t timestamp) {
   rtc::CritScope lock(&crit_);
-  if (!first_sent_timestamp_ && encoded_frame.stream_id_ == selected_stream_) {
-    first_sent_timestamp_ = encoded_frame.timestamp_;
+  if (!first_sent_timestamp_ && stream_id == selected_stream_) {
+    first_sent_timestamp_ = timestamp;
   }
 }
 
@@ -366,10 +365,6 @@
   stats_polling_thread_.Stop();
 }
 
-rtc::VideoSinkInterface<VideoFrame>* VideoAnalyzer::pre_encode_proxy() {
-  return &pre_encode_proxy_;
-}
-
 void VideoAnalyzer::StartMeasuringCpuProcessTime() {
   rtc::CritScope lock(&cpu_measurement_lock_);
   cpu_time_ -= rtc::GetProcessCpuTimeNanos();
@@ -841,13 +836,6 @@
       psnr(psnr),
       ssim(ssim) {}
 
-VideoAnalyzer::PreEncodeProxy::PreEncodeProxy(VideoAnalyzer* parent)
-    : parent_(parent) {}
-
-void VideoAnalyzer::PreEncodeProxy::OnFrame(const VideoFrame& video_frame) {
-  parent_->PreEncodeOnFrame(video_frame);
-}
-
 VideoAnalyzer::CapturedFrameForwarder::CapturedFrameForwarder(
     VideoAnalyzer* analyzer,
     Clock* clock)
diff --git a/video/video_analyzer.h b/video/video_analyzer.h
index 681d1f4..d2c4fa8 100644
--- a/video/video_analyzer.h
+++ b/video/video_analyzer.h
@@ -25,8 +25,7 @@
 
 class VideoAnalyzer : public PacketReceiver,
                       public Transport,
-                      public rtc::VideoSinkInterface<VideoFrame>,
-                      public EncodedFrameObserver {
+                      public rtc::VideoSinkInterface<VideoFrame> {
  public:
   VideoAnalyzer(test::LayerFilteringTransport* transport,
                 const std::string& test_label,
@@ -61,9 +60,7 @@
                                int64_t packet_time_us) override;
 
   void PreEncodeOnFrame(const VideoFrame& video_frame);
-
-  // EncodedFrameObserver implementation, wired to post_encode_callback.
-  void EncodedFrameCallback(const EncodedFrame& encoded_frame) override;
+  void PostEncodeOnFrame(size_t stream_id, uint32_t timestamp);
 
   bool SendRtp(const uint8_t* packet,
                size_t length,
@@ -73,8 +70,6 @@
   void OnFrame(const VideoFrame& video_frame) override;
   void Wait();
 
-  rtc::VideoSinkInterface<VideoFrame>* pre_encode_proxy();
-
   void StartMeasuringCpuProcessTime();
   void StopMeasuringCpuProcessTime();
   void StartExcludingCpuThreadTime();
@@ -132,17 +127,6 @@
     double ssim;
   };
 
-  // This class receives the send-side OnFrame callback and is provided to not
-  // conflict with the receiver-side renderer callback.
-  class PreEncodeProxy : public rtc::VideoSinkInterface<VideoFrame> {
-   public:
-    explicit PreEncodeProxy(VideoAnalyzer* parent);
-    void OnFrame(const VideoFrame& video_frame) override;
-
-   private:
-    VideoAnalyzer* const parent_;
-  };
-
   // Implements VideoSinkInterface to receive captured frames from a
   // FrameGeneratorCapturer. Implements VideoSourceInterface to be able to act
   // as a source to VideoSendStream.
@@ -221,7 +205,6 @@
   const size_t selected_stream_;
   const int selected_sl_;
   const int selected_tl_;
-  PreEncodeProxy pre_encode_proxy_;
 
   rtc::CriticalSection comparison_lock_;
   std::vector<Sample> samples_ RTC_GUARDED_BY(comparison_lock_);
diff --git a/video/video_quality_test.cc b/video/video_quality_test.cc
index 2a3be67..7e1fd97 100644
--- a/video/video_quality_test.cc
+++ b/video/video_quality_test.cc
@@ -35,7 +35,6 @@
 #include "test/run_loop.h"
 #include "test/testsupport/fileutils.h"
 #include "test/video_renderer.h"
-#include "video/video_analyzer.h"
 #ifdef WEBRTC_WIN
 #include "modules/audio_device/include/audio_device_factory.h"
 #endif
@@ -123,13 +122,16 @@
   std::unique_ptr<IvfFileWriter> writer_;
 };
 
-// An encoder wrapper that writes the encoded frames to file, one per simulcast
-// layer.
-class FrameDumpingEncoder : public VideoEncoder, private EncodedImageCallback {
+// This wrapper provides two features needed by the video quality tests:
+//  1. Invoke VideoAnalyzer callbacks before and after encoding each frame.
+//  2. Write the encoded frames to file, one file per simulcast layer.
+class QualityTestVideoEncoder : public VideoEncoder,
+                                private EncodedImageCallback {
  public:
-  FrameDumpingEncoder(std::unique_ptr<VideoEncoder> encoder,
-                      std::vector<rtc::PlatformFile> files)
-      : encoder_(std::move(encoder)) {
+  QualityTestVideoEncoder(std::unique_ptr<VideoEncoder> encoder,
+                          VideoAnalyzer* analyzer,
+                          std::vector<rtc::PlatformFile> files)
+      : encoder_(std::move(encoder)), analyzer_(analyzer) {
     for (rtc::PlatformFile file : files) {
       writers_.push_back(
           IvfFileWriter::Wrap(rtc::File(file), /* byte_limit= */ 100000000));
@@ -151,6 +153,9 @@
   int32_t Encode(const VideoFrame& frame,
                  const CodecSpecificInfo* codec_specific_info,
                  const std::vector<FrameType>* frame_types) {
+    if (analyzer_) {
+      analyzer_->PreEncodeOnFrame(frame);
+    }
     return encoder_->Encode(frame, codec_specific_info, frame_types);
   }
   int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override {
@@ -186,6 +191,10 @@
         simulcast_index = encoded_image.SpatialIndex().value_or(0);
       }
       RTC_DCHECK_GE(simulcast_index, 0);
+      if (analyzer_) {
+        analyzer_->PostEncodeOnFrame(simulcast_index,
+                                     encoded_image.Timestamp());
+      }
       if (static_cast<size_t>(simulcast_index) < writers_.size()) {
         writers_[simulcast_index]->WriteFrame(encoded_image,
                                               codec_specific_info->codecType);
@@ -202,6 +211,7 @@
 
   std::unique_ptr<VideoEncoder> encoder_;
   EncodedImageCallback* callback_ = nullptr;
+  VideoAnalyzer* const analyzer_;
   std::vector<std::unique_ptr<IvfFileWriter>> writers_;
 };
 
@@ -228,7 +238,8 @@
 }
 
 std::unique_ptr<VideoEncoder> VideoQualityTest::CreateVideoEncoder(
-    const SdpVideoFormat& format) {
+    const SdpVideoFormat& format,
+    VideoAnalyzer* analyzer) {
   std::unique_ptr<VideoEncoder> encoder;
   if (format.name == "VP8") {
     encoder = absl::make_unique<VP8EncoderSimulcastProxy>(
@@ -245,12 +256,17 @@
     sb << send_logs_++;
     std::string prefix =
         params_.logging.encoded_frame_base_path + "." + sb.str() + ".send.";
-    encoder = absl::make_unique<FrameDumpingEncoder>(
-        std::move(encoder), std::vector<rtc::PlatformFile>(
-                                {rtc::CreatePlatformFile(prefix + "1.ivf"),
-                                 rtc::CreatePlatformFile(prefix + "2.ivf"),
-                                 rtc::CreatePlatformFile(prefix + "3.ivf")}));
+    encoder = absl::make_unique<QualityTestVideoEncoder>(
+        std::move(encoder), analyzer,
+        std::vector<rtc::PlatformFile>(
+            {rtc::CreatePlatformFile(prefix + "1.ivf"),
+             rtc::CreatePlatformFile(prefix + "2.ivf"),
+             rtc::CreatePlatformFile(prefix + "3.ivf")}));
+  } else if (analyzer) {
+    encoder = absl::make_unique<QualityTestVideoEncoder>(
+        std::move(encoder), analyzer, std::vector<rtc::PlatformFile>());
   }
+
   return encoder;
 }
 
@@ -261,8 +277,12 @@
         return this->CreateVideoDecoder(format);
       }),
       video_encoder_factory_([this](const SdpVideoFormat& format) {
-        return this->CreateVideoEncoder(format);
+        return this->CreateVideoEncoder(format, nullptr);
       }),
+      video_encoder_factory_with_analyzer_(
+          [this](const SdpVideoFormat& format) {
+            return this->CreateVideoEncoder(format, analyzer_.get());
+          }),
       receive_logs_(0),
       send_logs_(0),
       injection_components_(std::move(injection_components)) {
@@ -594,7 +614,8 @@
       return;
     }
     video_send_configs_[video_idx].encoder_settings.encoder_factory =
-        &video_encoder_factory_;
+        (video_idx == 0) ? &video_encoder_factory_with_analyzer_
+                         : &video_encoder_factory_;
 
     video_send_configs_[video_idx].rtp.payload_name =
         params_.video[video_idx].codec;
@@ -1043,7 +1064,6 @@
   std::unique_ptr<test::LayerFilteringTransport> send_transport;
   std::unique_ptr<test::DirectTransport> recv_transport;
   FILE* graph_data_output_file = nullptr;
-  std::unique_ptr<VideoAnalyzer> analyzer;
 
   params_ = params;
   // TODO(ivica): Merge with RunWithRenderer and use a flag / argument to
@@ -1100,7 +1120,7 @@
   if (graph_title.empty())
     graph_title = VideoQualityTest::GenerateGraphTitle();
   bool is_quick_test_enabled = field_trial::IsEnabled("WebRTC-QuickPerfTest");
-  analyzer = absl::make_unique<VideoAnalyzer>(
+  analyzer_ = absl::make_unique<VideoAnalyzer>(
       send_transport.get(), params_.analyzer.test_label,
       params_.analyzer.avg_psnr_threshold, params_.analyzer.avg_ssim_threshold,
       is_quick_test_enabled
@@ -1114,26 +1134,23 @@
       is_quick_test_enabled, clock_, params_.logging.rtp_dump_name);
 
   task_queue_.SendTask([&]() {
-    analyzer->SetCall(sender_call_.get());
-    analyzer->SetReceiver(receiver_call_->Receiver());
-    send_transport->SetReceiver(analyzer.get());
+    analyzer_->SetCall(sender_call_.get());
+    analyzer_->SetReceiver(receiver_call_->Receiver());
+    send_transport->SetReceiver(analyzer_.get());
     recv_transport->SetReceiver(sender_call_->Receiver());
 
-    SetupVideo(analyzer.get(), recv_transport.get());
-    SetupThumbnails(analyzer.get(), recv_transport.get());
+    SetupVideo(analyzer_.get(), recv_transport.get());
+    SetupThumbnails(analyzer_.get(), recv_transport.get());
     video_receive_configs_[params_.ss[0].selected_stream].renderer =
-        analyzer.get();
-    GetVideoSendConfig()->pre_encode_callback = analyzer->pre_encode_proxy();
-    RTC_DCHECK(!GetVideoSendConfig()->post_encode_callback);
-    GetVideoSendConfig()->post_encode_callback = analyzer.get();
+        analyzer_.get();
 
     CreateFlexfecStreams();
     CreateVideoStreams();
-    analyzer->SetSendStream(video_send_streams_[0]);
+    analyzer_->SetSendStream(video_send_streams_[0]);
     if (video_receive_streams_.size() == 1)
-      analyzer->SetReceiveStream(video_receive_streams_[0]);
+      analyzer_->SetReceiveStream(video_receive_streams_[0]);
 
-    GetVideoSendStream()->SetSource(analyzer->OutputInterface(),
+    GetVideoSendStream()->SetSource(analyzer_->OutputInterface(),
                                     degradation_preference_);
     SetupThumbnailCapturers(params_.call.num_thumbnails);
     for (size_t i = 0; i < thumbnail_send_streams_.size(); ++i) {
@@ -1143,7 +1160,8 @@
 
     CreateCapturers();
 
-    analyzer->SetSource(video_capturers_[0].get(), params_.ss[0].infer_streams);
+    analyzer_->SetSource(video_capturers_[0].get(),
+                         params_.ss[0].infer_streams);
 
     for (size_t video_idx = 1; video_idx < num_video_streams_; ++video_idx) {
       video_send_streams_[video_idx]->SetSource(
@@ -1153,16 +1171,16 @@
     if (params_.audio.enabled) {
       SetupAudio(send_transport.get());
       StartAudioStreams();
-      analyzer->SetAudioReceiveStream(audio_receive_streams_[0]);
+      analyzer_->SetAudioReceiveStream(audio_receive_streams_[0]);
     }
     StartVideoStreams();
     StartThumbnails();
-    analyzer->StartMeasuringCpuProcessTime();
+    analyzer_->StartMeasuringCpuProcessTime();
     StartVideoCapture();
     StartThumbnailCapture();
   });
 
-  analyzer->Wait();
+  analyzer_->Wait();
 
   task_queue_.SendTask([&]() {
     StopThumbnailCapture();
@@ -1181,6 +1199,7 @@
 
     DestroyCalls();
   });
+  analyzer_ = nullptr;
 }
 
 rtc::scoped_refptr<AudioDeviceModule> VideoQualityTest::CreateAudioDevice() {
diff --git a/video/video_quality_test.h b/video/video_quality_test.h
index 7ec7e8d..92796f3 100644
--- a/video/video_quality_test.h
+++ b/video/video_quality_test.h
@@ -23,6 +23,7 @@
 #include "test/call_test.h"
 #include "test/frame_generator.h"
 #include "test/layer_filtering_transport.h"
+#include "video/video_analyzer.h"
 #ifdef WEBRTC_WIN
 #include "modules/audio_device/win/core_audio_utility_win.h"
 #endif
@@ -75,8 +76,8 @@
   void SetupThumbnailCapturers(size_t num_thumbnail_streams);
   std::unique_ptr<VideoDecoder> CreateVideoDecoder(
       const SdpVideoFormat& format);
-  std::unique_ptr<VideoEncoder> CreateVideoEncoder(
-      const SdpVideoFormat& format);
+  std::unique_ptr<VideoEncoder> CreateVideoEncoder(const SdpVideoFormat& format,
+                                                   VideoAnalyzer* analyzer);
   void SetupVideo(Transport* send_transport, Transport* recv_transport);
   void SetupThumbnails(Transport* send_transport, Transport* recv_transport);
   void StartAudioStreams();
@@ -103,6 +104,7 @@
   test::FunctionVideoDecoderFactory video_decoder_factory_;
   InternalDecoderFactory internal_decoder_factory_;
   test::FunctionVideoEncoderFactory video_encoder_factory_;
+  test::FunctionVideoEncoderFactory video_encoder_factory_with_analyzer_;
   InternalEncoderFactory internal_encoder_factory_;
   std::vector<VideoSendStream::Config> thumbnail_send_configs_;
   std::vector<VideoEncoderConfig> thumbnail_encoder_configs_;
@@ -116,6 +118,9 @@
   Params params_;
   std::unique_ptr<InjectionComponents> injection_components_;
 
+  // Set non-null when running with analyzer.
+  std::unique_ptr<VideoAnalyzer> analyzer_;
+
   // Note: not same as similarly named member in CallTest. This is the number of
   // separate send streams, the one in CallTest is the number of substreams for
   // a single send stream.
diff --git a/video/video_send_stream_impl.cc b/video/video_send_stream_impl.cc
index 58caf47..b725e63 100644
--- a/video/video_send_stream_impl.cc
+++ b/video/video_send_stream_impl.cc
@@ -563,17 +563,6 @@
   // Encoded is called on whatever thread the real encoder implementation run
   // on. In the case of hardware encoders, there might be several encoders
   // running in parallel on different threads.
-  const size_t simulcast_idx =
-      (codec_specific_info->codecType != kVideoCodecVP9)
-          ? encoded_image.SpatialIndex().value_or(0)
-          : 0;
-  if (config_->post_encode_callback) {
-    // TODO(nisse): Delete webrtc::EncodedFrame class, pass EncodedImage
-    // instead.
-    config_->post_encode_callback->EncodedFrameCallback(EncodedFrame(
-        encoded_image._buffer, encoded_image._length, encoded_image._frameType,
-        simulcast_idx, encoded_image.Timestamp()));
-  }
   {
     rtc::CritScope lock(&encoder_activity_crit_sect_);
     if (check_encoder_activity_task_)