[M120 Migration] Fixup! [WebRTC] Add TizenEsPlusPlayerRendererManager Implementation
[platform/framework/web/chromium-efl.git] / third_party / blink / renderer / modules / mediastream / video_track_adapter.cc
index 6d8091e..e8f03c2 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include <string>
 #include <utility>
 
-#include "base/bind.h"
 #include "base/containers/flat_map.h"
+#include "base/functional/bind.h"
 #include "base/location.h"
-#include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/sequence_checker.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/bind_post_task.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/single_thread_task_runner.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "media/base/bind_to_current_loop.h"
 #include "media/base/limits.h"
+#include "media/base/timestamp_constants.h"
 #include "media/base/video_util.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/web/modules/mediastream/video_track_adapter_settings.h"
+#include "third_party/blink/renderer/modules/mediastream/video_track_adapter_settings.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_gfx.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
 
+namespace WTF {
+
+// Template specializations of [1], needed to be able to pass WTF callbacks
+// that have VideoTrackAdapterSettings or gfx::Size parameters across threads.
+//
+// [1] third_party/blink/renderer/platform/wtf/cross_thread_copier.h.
+template <>
+struct CrossThreadCopier<blink::VideoTrackAdapterSettings>
+    : public CrossThreadCopierPassThrough<blink::VideoTrackAdapterSettings> {
+  STATIC_ONLY(CrossThreadCopier);
+};
+
+}  // namespace WTF
+
 namespace blink {
 
 namespace {
@@ -38,16 +59,18 @@ namespace {
 const float kFirstFrameTimeoutInFrameIntervals = 100.0f;
 const float kNormalFrameTimeoutInFrameIntervals = 25.0f;
 
-// Min delta time between two frames allowed without being dropped if a max
-// frame rate is specified.
-const double kMinTimeInMsBetweenFrames = 5;
+// |kMaxDeltaDeviationFactor| is used to determine |max_delta_deviation_| which
+// specifies the allowed deviation from |target_delta_| before dropping a frame.
+// It's set to 20% to be aligned with the previous logic in this file.
+constexpr float kMaxDeltaDeviationFactor = 0.2;
+
 // If the delta between two frames is bigger than this, we will consider it to
 // be invalid and reset the fps calculation.
-const double kMaxTimeInMsBetweenFrames = 1000;
+constexpr base::TimeDelta kMaxTimeBetweenFrames = base::Milliseconds(1000);
 
-const double kFrameRateChangeIntervalInSeconds = 1;
+constexpr base::TimeDelta kFrameRateChangeInterval = base::Seconds(1);
 const double kFrameRateChangeRate = 0.01;
-const double kFrameRateUpdateIntervalInSeconds = 5;
+constexpr base::TimeDelta kFrameRateUpdateInterval = base::Seconds(5);
 
 struct ComputedSettings {
   gfx::Size frame_size;
@@ -58,11 +81,6 @@ struct ComputedSettings {
   base::TimeTicks last_update_timestamp;
 };
 
-// Empty method used for keeping a reference to the original media::VideoFrame
-// in VideoFrameResolutionAdapter::DeliverFrame if cropping is needed.
-// The reference to |frame| is kept in the closure that calls this method.
-void TrackReleaseOriginalFrame(scoped_refptr<media::VideoFrame> frame) {}
-
 int ClampToValidDimension(int dimension) {
   return std::min(static_cast<int>(media::limits::kMaxDimension),
                   std::max(0, dimension));
@@ -71,6 +89,9 @@ int ClampToValidDimension(int dimension) {
 void ComputeFrameRate(const base::TimeDelta& frame_timestamp,
                       double* frame_rate,
                       base::TimeDelta* prev_frame_timestamp) {
+  if (frame_timestamp == media::kNoTimestamp)
+    return;
+
   const double delta_ms =
       (frame_timestamp - *prev_frame_timestamp).InMillisecondsF();
   *prev_frame_timestamp = frame_timestamp;
@@ -93,8 +114,7 @@ bool MaybeUpdateFrameRate(ComputedSettings* settings) {
   // reported value.
   if (std::abs(settings->frame_rate - settings->last_updated_frame_rate) >
       settings->last_updated_frame_rate * kFrameRateChangeRate) {
-    if ((now - settings->new_frame_rate_timestamp).InSecondsF() >
-        kFrameRateChangeIntervalInSeconds) {
+    if (now - settings->new_frame_rate_timestamp > kFrameRateChangeInterval) {
       settings->new_frame_rate_timestamp = now;
       settings->last_update_timestamp = now;
       settings->last_updated_frame_rate = settings->frame_rate;
@@ -106,8 +126,7 @@ bool MaybeUpdateFrameRate(ComputedSettings* settings) {
 
   // Update frame rate if it hasn't been updated in the last
   // kFrameRateUpdateIntervalInSeconds seconds.
-  if ((now - settings->last_update_timestamp).InSecondsF() >
-      kFrameRateUpdateIntervalInSeconds) {
+  if (now - settings->last_update_timestamp > kFrameRateUpdateInterval) {
     settings->last_update_timestamp = now;
     settings->last_updated_frame_rate = settings->frame_rate;
     return true;
@@ -115,49 +134,65 @@ bool MaybeUpdateFrameRate(ComputedSettings* settings) {
   return false;
 }
 
-}  // anonymous namespace
-
-// Template specializations of [1], needed to be able to pass WTF callbacks
-// that have VideoTrackAdapterSettings or gfx::Size parameters across threads.
-//
-// [1] third_party/blink/renderer/platform/cross_thread_copier.h.
-template <>
-struct CrossThreadCopier<VideoTrackAdapterSettings>
-    : public CrossThreadCopierPassThrough<VideoTrackAdapterSettings> {
-  STATIC_ONLY(CrossThreadCopier);
-};
+VideoTrackAdapterSettings ReturnSettingsMaybeOverrideMaxFps(
+    const VideoTrackAdapterSettings& settings) {
+  VideoTrackAdapterSettings new_settings = settings;
+  absl::optional<double> max_fps_override =
+      Platform::Current()->GetWebRtcMaxCaptureFrameRate();
+  if (max_fps_override) {
+    DVLOG(1) << "Overriding max frame rate.  Was="
+             << settings.max_frame_rate().value_or(-1)
+             << ", Now=" << *max_fps_override;
+    new_settings.set_max_frame_rate(*max_fps_override);
+  }
+  return new_settings;
+}
 
-template <>
-struct CrossThreadCopier<gfx::Size>
-    : public CrossThreadCopierPassThrough<gfx::Size> {
-  STATIC_ONLY(CrossThreadCopier);
-};
+}  // anonymous namespace
 
-// VideoFrameResolutionAdapter is created on and lives on the IO-thread. It does
-// the resolution adaptation and delivers frames to all registered tracks on the
-// IO-thread. All method calls must be on the IO-thread.
+// VideoFrameResolutionAdapter is created on and lives on the video task runner.
+// It does the resolution adaptation and delivers frames to all registered
+// tracks on the video task runner. All method calls must be on the video task
+// runner.
 class VideoTrackAdapter::VideoFrameResolutionAdapter
     : public WTF::ThreadSafeRefCounted<VideoFrameResolutionAdapter> {
  public:
   struct VideoTrackCallbacks {
     VideoCaptureDeliverFrameInternalCallback frame_callback;
+    VideoCaptureNotifyFrameDroppedInternalCallback
+        notify_frame_dropped_callback;
+    DeliverEncodedVideoFrameInternalCallback encoded_frame_callback;
+    VideoCaptureSubCaptureTargetVersionInternalCallback
+        sub_capture_target_version_callback;
     VideoTrackSettingsInternalCallback settings_callback;
     VideoTrackFormatInternalCallback format_callback;
   };
   // Setting |max_frame_rate| to 0.0, means that no frame rate limitation
   // will be done.
   VideoFrameResolutionAdapter(
-      scoped_refptr<base::SingleThreadTaskRunner> render_message_loop,
+      scoped_refptr<base::SingleThreadTaskRunner> reader_task_runner,
       const VideoTrackAdapterSettings& settings,
       base::WeakPtr<MediaStreamVideoSource> media_stream_video_source);
 
-  // Add |frame_callback| to receive video frames on the IO-thread and
+  VideoFrameResolutionAdapter(const VideoFrameResolutionAdapter&) = delete;
+  VideoFrameResolutionAdapter& operator=(const VideoFrameResolutionAdapter&) =
+      delete;
+
+  // Add |frame_callback|, |encoded_frame_callback| to receive video frames on
+  // the video task runner, |sub_capture_target_version_callback| to receive
+  // notifications when a new sub-capture-target version is acknowledged, and
   // |settings_callback| to set track settings on the main thread.
   // |frame_callback| will however be released on the main render thread.
-  void AddCallbacks(const MediaStreamVideoTrack* track,
-                    VideoCaptureDeliverFrameInternalCallback frame_callback,
-                    VideoTrackSettingsInternalCallback settings_callback,
-                    VideoTrackFormatInternalCallback format_callback);
+  void AddCallbacks(
+      const MediaStreamVideoTrack* track,
+      VideoCaptureDeliverFrameInternalCallback frame_callback,
+      VideoCaptureNotifyFrameDroppedInternalCallback
+          notify_frame_dropped_callback,
+      DeliverEncodedVideoFrameInternalCallback encoded_frame_callback,
+      VideoCaptureSubCaptureTargetVersionInternalCallback
+          sub_capture_target_version_callback,
+      VideoTrackSettingsInternalCallback settings_callback,
+      VideoTrackFormatInternalCallback format_callback);
 
   // Removes the callbacks associated with |track| if |track| has been added. It
   // is ok to call RemoveCallbacks() even if |track| has not been added.
@@ -169,9 +204,21 @@ class VideoTrackAdapter::VideoFrameResolutionAdapter
   // callbacks if |track| was not present in the adapter.
   VideoTrackCallbacks RemoveAndGetCallbacks(const MediaStreamVideoTrack* track);
 
-  void DeliverFrame(scoped_refptr<media::VideoFrame> frame,
-                    const base::TimeTicks& estimated_capture_time,
-                    bool is_device_rotated);
+  // The source has provided us with a frame.
+  void DeliverFrame(
+      scoped_refptr<media::VideoFrame> frame,
+      const base::TimeTicks& estimated_capture_time,
+      bool is_device_rotated);
+  // This method is called when a frame is dropped, whether dropped by the
+  // source (via VideoTrackAdapter::OnFrameDroppedOnVideoTaskRunner) or
+  // internally (in DeliverFrame).
+  void OnFrameDropped(media::VideoCaptureFrameDropReason reason);
+
+  void DeliverEncodedVideoFrame(scoped_refptr<EncodedVideoFrame> frame,
+                                base::TimeTicks estimated_capture_time);
+
+  void NewSubCaptureTargetVersionOnVideoTaskRunner(
+      uint32_t sub_capture_target_version);
 
   // Returns true if all arguments match with the output of this adapter.
   bool SettingsMatch(const VideoTrackAdapterSettings& settings) const;
@@ -185,8 +232,9 @@ class VideoTrackAdapter::VideoFrameResolutionAdapter
   virtual ~VideoFrameResolutionAdapter();
   friend class WTF::ThreadSafeRefCounted<VideoFrameResolutionAdapter>;
 
-  void DoDeliverFrame(scoped_refptr<media::VideoFrame> frame,
-                      const base::TimeTicks& estimated_capture_time);
+  void DoDeliverFrame(
+      scoped_refptr<media::VideoFrame> video_frame,
+      const base::TimeTicks& estimated_capture_time);
 
   // Returns |true| if the input frame rate is higher that the requested max
   // frame rate and |frame| should be dropped. If it returns true, |reason| is
@@ -205,11 +253,8 @@ class VideoTrackAdapter::VideoFrameResolutionAdapter
   // or frame rate have changed since last update.
   void MaybeUpdateTracksFormat(const media::VideoFrame& frame);
 
-  void PostFrameDroppedToMainTaskRunner(
-      media::VideoCaptureFrameDropReason reason);
-
-  // Bound to the IO-thread.
-  THREAD_CHECKER(io_thread_checker_);
+  // Bound to the video task runner.
+  SEQUENCE_CHECKER(video_sequence_checker_);
 
   // The task runner where we will release VideoCaptureDeliverFrameCB
   // registered in AddCallbacks.
@@ -217,70 +262,100 @@ class VideoTrackAdapter::VideoFrameResolutionAdapter
 
   base::WeakPtr<MediaStreamVideoSource> media_stream_video_source_;
 
-  VideoTrackAdapterSettings settings_;
-  double frame_rate_;
-  base::TimeDelta last_time_stamp_;
-  double keep_frame_counter_;
+  const VideoTrackAdapterSettings settings_;
+
+  // The target timestamp delta between video frames, corresponding to the max
+  // fps.
+  const absl::optional<base::TimeDelta> target_delta_;
+
+  // The maximum allowed deviation from |target_delta_| before dropping a frame.
+  const absl::optional<base::TimeDelta> max_delta_deviation_;
+
+  // The timestamp of the last delivered video frame.
+  base::TimeDelta timestamp_last_delivered_frame_ = base::TimeDelta::Max();
+
+  // Stores the accumulated difference between |target_delta_| and the actual
+  // timestamp delta between frames that are delivered. Clamped to
+  // [-max_delta_deviation, target_delta_ / 2]. This is used to allow some
+  // frames to be closer than |target_delta_| in order to maintain
+  // |target_delta_| on average. Without it we may end up with an average fps
+  // that is half of max fps.
+  base::TimeDelta accumulated_drift_;
 
   ComputedSettings track_settings_;
   ComputedSettings source_format_settings_;
 
   base::flat_map<const MediaStreamVideoTrack*, VideoTrackCallbacks> callbacks_;
-
-  DISALLOW_COPY_AND_ASSIGN(VideoFrameResolutionAdapter);
 };
 
 VideoTrackAdapter::VideoFrameResolutionAdapter::VideoFrameResolutionAdapter(
-    scoped_refptr<base::SingleThreadTaskRunner> render_message_loop,
+    scoped_refptr<base::SingleThreadTaskRunner> reader_task_runner,
     const VideoTrackAdapterSettings& settings,
     base::WeakPtr<MediaStreamVideoSource> media_stream_video_source)
-    : renderer_task_runner_(render_message_loop),
+    : renderer_task_runner_(reader_task_runner),
       media_stream_video_source_(media_stream_video_source),
-      settings_(settings),
-      frame_rate_(MediaStreamVideoSource::kDefaultFrameRate),
-      last_time_stamp_(base::TimeDelta::Max()),
-      keep_frame_counter_(0.0) {
+      settings_(ReturnSettingsMaybeOverrideMaxFps(settings)),
+      target_delta_(settings_.max_frame_rate()
+                        ? absl::make_optional(base::Seconds(
+                              1.0 / settings_.max_frame_rate().value()))
+                        : absl::nullopt),
+      max_delta_deviation_(target_delta_
+                               ? absl::make_optional(kMaxDeltaDeviationFactor *
+                                                     target_delta_.value())
+                               : absl::nullopt) {
+  DVLOG(1) << __func__ << " max_framerate "
+           << settings.max_frame_rate().value_or(-1);
   DCHECK(renderer_task_runner_.get());
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
   CHECK_NE(0, settings_.max_aspect_ratio());
-
-  base::Optional<double> max_fps_override =
-      Platform::Current()->GetWebRtcMaxCaptureFrameRate();
-  if (max_fps_override) {
-    DVLOG(1) << "Overriding max frame rate.  Was=" << settings_.max_frame_rate()
-             << ", Now=" << *max_fps_override;
-    settings_.set_max_frame_rate(*max_fps_override);
-  }
 }
 
 VideoTrackAdapter::VideoFrameResolutionAdapter::~VideoFrameResolutionAdapter() {
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
   DCHECK(callbacks_.empty());
 }
 
 void VideoTrackAdapter::VideoFrameResolutionAdapter::AddCallbacks(
     const MediaStreamVideoTrack* track,
     VideoCaptureDeliverFrameInternalCallback frame_callback,
+    VideoCaptureNotifyFrameDroppedInternalCallback
+        notify_frame_dropped_callback,
+    DeliverEncodedVideoFrameInternalCallback encoded_frame_callback,
+    VideoCaptureSubCaptureTargetVersionInternalCallback
+        sub_capture_target_version_callback,
     VideoTrackSettingsInternalCallback settings_callback,
     VideoTrackFormatInternalCallback format_callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
 
-  VideoTrackCallbacks track_callbacks = {std::move(frame_callback),
-                                         std::move(settings_callback),
-                                         std::move(format_callback)};
-  callbacks_.insert({track, std::move(track_callbacks)});
+  // The new track's settings should match the resolution adapter's current
+  // |track_settings_| as set for existing track(s) with matching
+  // VideoTrackAdapterSettings.
+  if (!callbacks_.empty() && track_settings_.frame_size.width() > 0 &&
+      track_settings_.frame_size.height() > 0) {
+    settings_callback.Run(track_settings_.frame_size,
+                          track_settings_.frame_rate);
+  }
+
+  VideoTrackCallbacks track_callbacks = {
+      std::move(frame_callback),
+      std::move(notify_frame_dropped_callback),
+      std::move(encoded_frame_callback),
+      std::move(sub_capture_target_version_callback),
+      std::move(settings_callback),
+      std::move(format_callback)};
+  callbacks_.emplace(track, std::move(track_callbacks));
 }
 
 void VideoTrackAdapter::VideoFrameResolutionAdapter::RemoveCallbacks(
     const MediaStreamVideoTrack* track) {
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
   callbacks_.erase(track);
 }
 
 VideoTrackAdapter::VideoFrameResolutionAdapter::VideoTrackCallbacks
 VideoTrackAdapter::VideoFrameResolutionAdapter::RemoveAndGetCallbacks(
     const MediaStreamVideoTrack* track) {
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
   VideoTrackCallbacks track_callbacks;
   auto it = callbacks_.find(track);
   if (it == callbacks_.end())
@@ -292,95 +367,150 @@ VideoTrackAdapter::VideoFrameResolutionAdapter::RemoveAndGetCallbacks(
 }
 
 void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverFrame(
-    scoped_refptr<media::VideoFrame> frame,
+    scoped_refptr<media::VideoFrame> video_frame,
     const base::TimeTicks& estimated_capture_time,
     bool is_device_rotated) {
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
 
-  if (!frame) {
+  if (!video_frame) {
     DLOG(ERROR) << "Incoming frame is not valid.";
-    PostFrameDroppedToMainTaskRunner(
+    OnFrameDropped(
         media::VideoCaptureFrameDropReason::kResolutionAdapterFrameIsNotValid);
     return;
   }
 
-  ComputeFrameRate(frame->timestamp(), &source_format_settings_.frame_rate,
+  ComputeFrameRate(video_frame->timestamp(),
+                   &source_format_settings_.frame_rate,
                    &source_format_settings_.prev_frame_timestamp);
-  MaybeUpdateTracksFormat(*frame);
+  MaybeUpdateTracksFormat(*video_frame);
 
-  double frame_rate;
-  if (!frame->metadata()->GetDouble(media::VideoFrameMetadata::FRAME_RATE,
-                                    &frame_rate)) {
-    frame_rate = MediaStreamVideoSource::kUnknownFrameRate;
-  }
+  double frame_rate = video_frame->metadata().frame_rate.value_or(
+      MediaStreamVideoSource::kUnknownFrameRate);
 
   auto frame_drop_reason = media::VideoCaptureFrameDropReason::kNone;
-  if (MaybeDropFrame(*frame, frame_rate, &frame_drop_reason)) {
-    PostFrameDroppedToMainTaskRunner(frame_drop_reason);
+  if (MaybeDropFrame(*video_frame, frame_rate, &frame_drop_reason)) {
+    OnFrameDropped(frame_drop_reason);
     return;
   }
 
-  // TODO(perkj): Allow cropping / scaling of textures once
-  // https://crbug/362521 is fixed.
-  if (frame->HasTextures()) {
-    DoDeliverFrame(std::move(frame), estimated_capture_time);
+  // If the frame is a texture not backed up by GPU memory we don't apply
+  // cropping/scaling and deliver the frame as-is, leaving it up to the
+  // destination to rescale it. Otherwise, cropping and scaling is soft-applied
+  // before delivery for efficiency.
+  //
+  // TODO(crbug.com/362521): Allow cropping/scaling of non-GPU memory backed
+  // textures.
+  if (video_frame->HasTextures() &&
+      video_frame->storage_type() !=
+          media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER) {
+    DoDeliverFrame(std::move(video_frame), estimated_capture_time);
     return;
   }
-  scoped_refptr<media::VideoFrame> video_frame(frame);
+  // The video frame we deliver may or may not get cropping and scaling
+  // soft-applied. Ultimately the listener will decide whether to use the
+  // |delivered_video_frame|.
+  scoped_refptr<media::VideoFrame> delivered_video_frame = video_frame;
 
   gfx::Size desired_size;
-  CalculateDesiredSize(is_device_rotated, frame->natural_size(), settings_,
-                       &desired_size);
-  if (desired_size != frame->natural_size()) {
+  CalculateDesiredSize(is_device_rotated, video_frame->natural_size(),
+                       settings_, &desired_size);
+  if (desired_size != video_frame->natural_size()) {
     // Get the largest centered rectangle with the same aspect ratio of
-    // |desired_size| that fits entirely inside of |frame->visible_rect()|.
-    // This will be the rect we need to crop the original frame to.
-    // From this rect, the original frame can be scaled down to |desired_size|.
-    const gfx::Rect region_in_frame =
-        media::ComputeLetterboxRegion(frame->visible_rect(), desired_size);
-
-    video_frame = media::VideoFrame::WrapVideoFrame(
-        *frame, frame->format(), region_in_frame, desired_size);
-    if (!video_frame) {
-      PostFrameDroppedToMainTaskRunner(
-          media::VideoCaptureFrameDropReason::
-              kResolutionAdapterWrappingFrameForCroppingFailed);
+    // |desired_size| that fits entirely inside of
+    // |video_frame->visible_rect()|. This will be the rect we need to crop the
+    // original frame to. From this rect, the original frame can be scaled down
+    // to |desired_size|.
+    gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
+        video_frame->visible_rect(), desired_size);
+
+    // Some consumers (for example
+    // ImageCaptureFrameGrabber::SingleShotFrameHandler::ConvertAndDeliverFrame)
+    // don't support pixel format conversions when the source format is YUV with
+    // UV subsampled and vsible_rect().x() being odd. The conversion ends up
+    // miscomputing the UV plane and ends up with a VU plane leading to a blue
+    // face tint. Round x() to even to avoid. See crbug.com/1307304.
+    region_in_frame.set_x(region_in_frame.x() & ~1);
+    region_in_frame.set_y(region_in_frame.y() & ~1);
+
+    // ComputeLetterboxRegion() sometimes produces odd dimensions due to
+    // internal rounding errors; allow to round upwards if there's slack
+    // otherwise round downwards.
+    bool width_has_slack =
+        region_in_frame.right() < video_frame->visible_rect().right();
+    region_in_frame.set_width((region_in_frame.width() + width_has_slack) & ~1);
+    bool height_has_slack =
+        region_in_frame.bottom() < video_frame->visible_rect().bottom();
+    region_in_frame.set_height((region_in_frame.height() + height_has_slack) &
+                               ~1);
+
+    delivered_video_frame = media::VideoFrame::WrapVideoFrame(
+        video_frame, video_frame->format(), region_in_frame, desired_size);
+    if (!delivered_video_frame) {
+      OnFrameDropped(media::VideoCaptureFrameDropReason::
+                         kResolutionAdapterWrappingFrameForCroppingFailed);
       return;
     }
-    video_frame->AddDestructionObserver(ConvertToBaseOnceCallback(
-        CrossThreadBindOnce(&TrackReleaseOriginalFrame, frame)));
 
     DVLOG(3) << "desired size  " << desired_size.ToString()
              << " output natural size "
-             << video_frame->natural_size().ToString()
+             << delivered_video_frame->natural_size().ToString()
              << " output visible rect  "
-             << video_frame->visible_rect().ToString();
+             << delivered_video_frame->visible_rect().ToString();
+  }
+  DoDeliverFrame(std::move(delivered_video_frame), estimated_capture_time);
+}
+
+void VideoTrackAdapter::VideoFrameResolutionAdapter::DeliverEncodedVideoFrame(
+    scoped_refptr<EncodedVideoFrame> frame,
+    base::TimeTicks estimated_capture_time) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
+  for (const auto& callback : callbacks_) {
+    callback.second.encoded_frame_callback.Run(frame, estimated_capture_time);
+  }
+}
+
+void VideoTrackAdapter::VideoFrameResolutionAdapter::
+    NewSubCaptureTargetVersionOnVideoTaskRunner(
+        uint32_t sub_capture_target_version) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
+  for (const auto& callback : callbacks_) {
+    callback.second.sub_capture_target_version_callback.Run(
+        sub_capture_target_version);
   }
-  DoDeliverFrame(std::move(video_frame), estimated_capture_time);
 }
 
 bool VideoTrackAdapter::VideoFrameResolutionAdapter::SettingsMatch(
     const VideoTrackAdapterSettings& settings) const {
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
   return settings_ == settings;
 }
 
 bool VideoTrackAdapter::VideoFrameResolutionAdapter::IsEmpty() const {
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
   return callbacks_.empty();
 }
 
 void VideoTrackAdapter::VideoFrameResolutionAdapter::DoDeliverFrame(
-    scoped_refptr<media::VideoFrame> frame,
+    scoped_refptr<media::VideoFrame> video_frame,
     const base::TimeTicks& estimated_capture_time) {
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
   if (callbacks_.empty()) {
-    PostFrameDroppedToMainTaskRunner(
+    OnFrameDropped(
         media::VideoCaptureFrameDropReason::kResolutionAdapterHasNoCallbacks);
   }
   for (const auto& callback : callbacks_) {
-    MaybeUpdateTrackSettings(callback.second.settings_callback, *frame);
-    callback.second.frame_callback.Run(frame, estimated_capture_time);
+    MaybeUpdateTrackSettings(callback.second.settings_callback, *video_frame);
+    callback.second.frame_callback.Run(video_frame, estimated_capture_time);
+  }
+}
+
+void VideoTrackAdapter::VideoFrameResolutionAdapter::OnFrameDropped(
+    media::VideoCaptureFrameDropReason reason) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
+  // Notify callbacks, such as
+  // MediaStreamVideoTrack::FrameDeliverer::NotifyFrameDroppedOnVideoTaskRunner.
+  for (const auto& callback : callbacks_) {
+    callback.second.notify_frame_dropped_callback.Run(reason);
   }
 }
 
@@ -388,70 +518,51 @@ bool VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeDropFrame(
     const media::VideoFrame& frame,
     float source_frame_rate,
     media::VideoCaptureFrameDropReason* reason) {
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
 
-  // Do not drop frames if max frame rate hasn't been specified or the source
-  // frame rate is known and is lower than max.
-  if (settings_.max_frame_rate() == 0.0f ||
-      (source_frame_rate > 0 &&
-       source_frame_rate <= settings_.max_frame_rate())) {
+  // Never drop frames if the max frame rate has not been specified.
+  if (!settings_.max_frame_rate().has_value()) {
+    timestamp_last_delivered_frame_ = frame.timestamp();
     return false;
   }
 
-  const double delta_ms =
-      (frame.timestamp() - last_time_stamp_).InMillisecondsF();
-
-  // Check if the time since the last frame is completely off.
-  if (delta_ms < 0 || delta_ms > kMaxTimeInMsBetweenFrames) {
-    // Reset |last_time_stamp_| and fps calculation.
-    last_time_stamp_ = frame.timestamp();
-    frame_rate_ = MediaStreamVideoSource::kDefaultFrameRate;
-    keep_frame_counter_ = 0.0;
+  const base::TimeDelta delta =
+      (frame.timestamp() - timestamp_last_delivered_frame_);
+
+  // Keep the frame if the time since the last frame is completely off.
+  if (delta.is_negative() || delta > kMaxTimeBetweenFrames) {
+    // Reset |timestamp_last_delivered_frame_| and |accumulated_drift|.
+    timestamp_last_delivered_frame_ = frame.timestamp();
+    accumulated_drift_ = base::Milliseconds(0.0);
     return false;
   }
 
-  if (delta_ms < kMinTimeInMsBetweenFrames) {
-    // We have seen video frames being delivered from camera devices back to
-    // back. The simple AR filter for frame rate calculation is too short to
-    // handle that. https://crbug/394315
-    // TODO(perkj): Can we come up with a way to fix the times stamps and the
-    // timing when frames are delivered so all frames can be used?
-    // The time stamps are generated by Chrome and not the actual device.
-    // Most likely the back to back problem is caused by software and not the
-    // actual camera.
-    DVLOG(3) << "Drop frame since delta time since previous frame is "
-             << delta_ms << "ms.";
+  DCHECK(target_delta_ && max_delta_deviation_);
+  if (delta < target_delta_.value() - max_delta_deviation_.value() -
+                  accumulated_drift_) {
+    // Drop the frame because the input frame rate is too high.
     *reason = media::VideoCaptureFrameDropReason::
-        kResolutionAdapterTimestampTooCloseToPrevious;
+        kResolutionAdapterFrameRateIsHigherThanRequested;
     return true;
   }
-  last_time_stamp_ = frame.timestamp();
-  // Calculate the frame rate using a simple AR filter.
-  // Use a simple filter with 0.1 weight of the current sample.
-  frame_rate_ = 100 / delta_ms + 0.9 * frame_rate_;
-
-  // Prefer to not drop frames.
-  if (settings_.max_frame_rate() + 0.5f > frame_rate_)
-    return false;  // Keep this frame.
-
-  // The input frame rate is higher than requested.
-  // Decide if we should keep this frame or drop it.
-  keep_frame_counter_ += settings_.max_frame_rate() / frame_rate_;
-  if (keep_frame_counter_ >= 1) {
-    keep_frame_counter_ -= 1;
-    // Keep the frame.
-    return false;
-  }
-  DVLOG(3) << "Drop frame. Input frame_rate_ " << frame_rate_ << ".";
-  *reason = media::VideoCaptureFrameDropReason::
-      kResolutionAdapterFrameRateIsHigherThanRequested;
-  return true;
+
+  // Keep the frame and store the accumulated drift.
+  timestamp_last_delivered_frame_ = frame.timestamp();
+  accumulated_drift_ += delta - target_delta_.value();
+  DCHECK_GE(accumulated_drift_, -max_delta_deviation_.value());
+  // Limit the maximum accumulated drift to half of the target delta. If we
+  // don't do this, it may happen that we output a series of frames too quickly
+  // after a period of no frames. There is no need to actively limit the minimum
+  // accumulated drift because that happens automatically when we drop frames
+  // that are too close in time.
+  accumulated_drift_ = std::min(accumulated_drift_, target_delta_.value() / 2);
+  return false;
 }
 
 void VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeUpdateTrackSettings(
     const VideoTrackSettingsInternalCallback& settings_callback,
     const media::VideoFrame& frame) {
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
   ComputeFrameRate(frame.timestamp(), &track_settings_.frame_rate,
                    &track_settings_.prev_frame_timestamp);
   if (MaybeUpdateFrameRate(&track_settings_) ||
@@ -463,7 +574,7 @@ void VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeUpdateTrackSettings(
 }
 void VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeUpdateTracksFormat(
     const media::VideoFrame& frame) {
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
   if (MaybeUpdateFrameRate(&source_format_settings_) ||
       frame.natural_size() != track_settings_.frame_size) {
     source_format_settings_.frame_size = frame.natural_size();
@@ -476,62 +587,67 @@ void VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeUpdateTracksFormat(
 }
 
 void VideoTrackAdapter::VideoFrameResolutionAdapter::ResetFrameRate() {
-  DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(video_sequence_checker_);
   for (const auto& callback : callbacks_) {
     callback.second.settings_callback.Run(track_settings_.frame_size, 0.0);
   }
 }
 
-void VideoTrackAdapter::VideoFrameResolutionAdapter::
-    PostFrameDroppedToMainTaskRunner(
-        media::VideoCaptureFrameDropReason reason) {
-  PostCrossThreadTask(
-      *renderer_task_runner_, FROM_HERE,
-      CrossThreadBindOnce(&MediaStreamVideoSource::OnFrameDropped,
-                          media_stream_video_source_, reason));
-}
-
 VideoTrackAdapter::VideoTrackAdapter(
-    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+    scoped_refptr<base::SequencedTaskRunner> video_task_runner,
     base::WeakPtr<MediaStreamVideoSource> media_stream_video_source)
-    : io_task_runner_(io_task_runner),
+    : video_task_runner_(video_task_runner),
       media_stream_video_source_(media_stream_video_source),
-      renderer_task_runner_(base::ThreadTaskRunnerHandle::Get()),
-      monitoring_frame_rate_(false),
+      renderer_task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()),
       muted_state_(false),
       frame_counter_(0),
+      old_frame_counter_snapshot_(0),
       source_frame_rate_(0.0f) {
-  DCHECK(io_task_runner);
+  DCHECK(video_task_runner);
 }
 
 VideoTrackAdapter::~VideoTrackAdapter() {
-  DCHECK(adapters_.IsEmpty());
+  DCHECK(adapters_.empty());
+  DCHECK(!monitoring_frame_rate_timer_);
 }
 
-void VideoTrackAdapter::AddTrack(const MediaStreamVideoTrack* track,
-                                 VideoCaptureDeliverFrameCB frame_callback,
-                                 VideoTrackSettingsCallback settings_callback,
-                                 VideoTrackFormatCallback format_callback,
-                                 const VideoTrackAdapterSettings& settings) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+void VideoTrackAdapter::AddTrack(
+    const MediaStreamVideoTrack* track,
+    VideoCaptureDeliverFrameCB frame_callback,
+    VideoCaptureNotifyFrameDroppedCB notify_frame_dropped_callback,
+    EncodedVideoFrameCB encoded_frame_callback,
+    VideoCaptureSubCaptureTargetVersionCB sub_capture_target_version_callback,
+    VideoTrackSettingsCallback settings_callback,
+    VideoTrackFormatCallback format_callback,
+    const VideoTrackAdapterSettings& settings) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   PostCrossThreadTask(
-      *io_task_runner_, FROM_HERE,
+      *video_task_runner_, FROM_HERE,
       CrossThreadBindOnce(
-          &VideoTrackAdapter::AddTrackOnIO, CrossThreadUnretained(this),
-          CrossThreadUnretained(track),
-          WTF::Passed(CrossThreadBind(std::move(frame_callback))),
-          WTF::Passed(CrossThreadBind(std::move(settings_callback))),
-          WTF::Passed(CrossThreadBind(std::move(format_callback))), settings));
-}
-
-void VideoTrackAdapter::AddTrackOnIO(
+          &VideoTrackAdapter::AddTrackOnVideoTaskRunner,
+          WTF::CrossThreadUnretained(this), WTF::CrossThreadUnretained(track),
+          CrossThreadBindRepeating(std::move(frame_callback)),
+          CrossThreadBindRepeating(std::move(notify_frame_dropped_callback)),
+          CrossThreadBindRepeating(std::move(encoded_frame_callback)),
+          CrossThreadBindRepeating(
+              std::move(sub_capture_target_version_callback)),
+          CrossThreadBindRepeating(std::move(settings_callback)),
+          CrossThreadBindRepeating(std::move(format_callback)), settings));
+}
+
+void VideoTrackAdapter::AddTrackOnVideoTaskRunner(
     const MediaStreamVideoTrack* track,
     VideoCaptureDeliverFrameInternalCallback frame_callback,
+    VideoCaptureNotifyFrameDroppedInternalCallback
+        notify_frame_dropped_callback,
+    DeliverEncodedVideoFrameInternalCallback encoded_frame_callback,
+    VideoCaptureSubCaptureTargetVersionInternalCallback
+        sub_capture_target_version_callback,
     VideoTrackSettingsInternalCallback settings_callback,
     VideoTrackFormatInternalCallback format_callback,
     const VideoTrackAdapterSettings& settings) {
-  DCHECK(io_task_runner_->BelongsToCurrentThread());
+  DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
   scoped_refptr<VideoFrameResolutionAdapter> adapter;
   for (const auto& frame_adapter : adapters_) {
     if (frame_adapter->SettingsMatch(settings)) {
@@ -546,26 +662,29 @@ void VideoTrackAdapter::AddTrackOnIO(
   }
 
   adapter->AddCallbacks(track, std::move(frame_callback),
+                        std::move(notify_frame_dropped_callback),
+                        std::move(encoded_frame_callback),
+                        std::move(sub_capture_target_version_callback),
                         std::move(settings_callback),
                         std::move(format_callback));
 }
 
 void VideoTrackAdapter::RemoveTrack(const MediaStreamVideoTrack* track) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   PostCrossThreadTask(
-      *io_task_runner_, FROM_HERE,
-      CrossThreadBindOnce(&VideoTrackAdapter::RemoveTrackOnIO,
+      *video_task_runner_, FROM_HERE,
+      CrossThreadBindOnce(&VideoTrackAdapter::RemoveTrackOnVideoTaskRunner,
                           WrapRefCounted(this), CrossThreadUnretained(track)));
 }
 
 void VideoTrackAdapter::ReconfigureTrack(
     const MediaStreamVideoTrack* track,
     const VideoTrackAdapterSettings& settings) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   PostCrossThreadTask(
-      *io_task_runner_, FROM_HERE,
-      CrossThreadBindOnce(&VideoTrackAdapter::ReconfigureTrackOnIO,
+      *video_task_runner_, FROM_HERE,
+      CrossThreadBindOnce(&VideoTrackAdapter::ReconfigureTrackOnVideoTaskRunner,
                           WrapRefCounted(this), CrossThreadUnretained(track),
                           settings));
 }
@@ -573,33 +692,36 @@ void VideoTrackAdapter::ReconfigureTrack(
 void VideoTrackAdapter::StartFrameMonitoring(
     double source_frame_rate,
     const OnMutedCallback& on_muted_callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   VideoTrackAdapter::OnMutedCallback bound_on_muted_callback =
-      media::BindToCurrentLoop(on_muted_callback);
+      base::BindPostTaskToCurrentDefault(on_muted_callback);
 
   PostCrossThreadTask(
-      *io_task_runner_, FROM_HERE,
+      *video_task_runner_, FROM_HERE,
       CrossThreadBindOnce(
-          &VideoTrackAdapter::StartFrameMonitoringOnIO, WrapRefCounted(this),
-          WTF::Passed(CrossThreadBind(std::move(bound_on_muted_callback))),
+          &VideoTrackAdapter::StartFrameMonitoringOnVideoTaskRunner,
+          WrapRefCounted(this),
+          CrossThreadBindRepeating(std::move(bound_on_muted_callback)),
           source_frame_rate));
 }
 
 void VideoTrackAdapter::StopFrameMonitoring() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   PostCrossThreadTask(
-      *io_task_runner_, FROM_HERE,
-      CrossThreadBindOnce(&VideoTrackAdapter::StopFrameMonitoringOnIO,
-                          WrapRefCounted(this)));
+      *video_task_runner_, FROM_HERE,
+      CrossThreadBindOnce(
+          &VideoTrackAdapter::StopFrameMonitoringOnVideoTaskRunner,
+          WrapRefCounted(this)));
 }
 
 void VideoTrackAdapter::SetSourceFrameSize(const gfx::Size& source_frame_size) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   PostCrossThreadTask(
-      *io_task_runner_, FROM_HERE,
-      CrossThreadBindOnce(&VideoTrackAdapter::SetSourceFrameSizeOnIO,
-                          WrapRefCounted(this), source_frame_size));
+      *video_task_runner_, FROM_HERE,
+      CrossThreadBindOnce(
+          &VideoTrackAdapter::SetSourceFrameSizeOnVideoTaskRunner,
+          WrapRefCounted(this), source_frame_size));
 }
 
 bool VideoTrackAdapter::CalculateDesiredSize(
@@ -663,13 +785,18 @@ bool VideoTrackAdapter::CalculateDesiredSize(
   return true;
 }
 
-void VideoTrackAdapter::StartFrameMonitoringOnIO(
+void VideoTrackAdapter::StartFrameMonitoringOnVideoTaskRunner(
     OnMutedInternalCallback on_muted_callback,
     double source_frame_rate) {
-  DCHECK(io_task_runner_->BelongsToCurrentThread());
-  DCHECK(!monitoring_frame_rate_);
+  DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(!monitoring_frame_rate_timer_);
 
-  monitoring_frame_rate_ = true;
+  on_muted_callback_ = std::move(on_muted_callback);
+  monitoring_frame_rate_timer_ = std::make_unique<LowPrecisionTimer>(
+      video_task_runner_,
+      ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
+          &VideoTrackAdapter::CheckFramesReceivedOnVideoTaskRunner,
+          WrapRefCounted(this))));
 
   // If the source does not know the frame rate, set one by default.
   if (source_frame_rate == 0.0f)
@@ -677,28 +804,31 @@ void VideoTrackAdapter::StartFrameMonitoringOnIO(
   source_frame_rate_ = source_frame_rate;
   DVLOG(1) << "Monitoring frame creation, first (large) delay: "
            << (kFirstFrameTimeoutInFrameIntervals / source_frame_rate_) << "s";
-  PostDelayedCrossThreadTask(
-      *io_task_runner_, FROM_HERE,
-      CrossThreadBind(
-          &VideoTrackAdapter::CheckFramesReceivedOnIO, WrapRefCounted(this),
-          WTF::Passed(std::move(on_muted_callback)), frame_counter_),
-      base::TimeDelta::FromSecondsD(kFirstFrameTimeoutInFrameIntervals /
-                                    source_frame_rate_));
+  old_frame_counter_snapshot_ = frame_counter_;
+  monitoring_frame_rate_timer_->StartOneShot(
+      base::Seconds(kFirstFrameTimeoutInFrameIntervals / source_frame_rate_));
 }
 
-void VideoTrackAdapter::StopFrameMonitoringOnIO() {
-  DCHECK(io_task_runner_->BelongsToCurrentThread());
-  monitoring_frame_rate_ = false;
+void VideoTrackAdapter::StopFrameMonitoringOnVideoTaskRunner() {
+  DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
+  if (!monitoring_frame_rate_timer_) {
+    // Already stopped.
+    return;
+  }
+  monitoring_frame_rate_timer_->Shutdown();
+  monitoring_frame_rate_timer_.reset();
+  on_muted_callback_ = OnMutedInternalCallback();
 }
 
-void VideoTrackAdapter::SetSourceFrameSizeOnIO(
+void VideoTrackAdapter::SetSourceFrameSizeOnVideoTaskRunner(
     const gfx::Size& source_frame_size) {
-  DCHECK(io_task_runner_->BelongsToCurrentThread());
+  DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
   source_frame_size_ = source_frame_size;
 }
 
-void VideoTrackAdapter::RemoveTrackOnIO(const MediaStreamVideoTrack* track) {
-  DCHECK(io_task_runner_->BelongsToCurrentThread());
+void VideoTrackAdapter::RemoveTrackOnVideoTaskRunner(
+    const MediaStreamVideoTrack* track) {
+  DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
   for (auto* it = adapters_.begin(); it != adapters_.end(); ++it) {
     (*it)->RemoveCallbacks(track);
     if ((*it)->IsEmpty()) {
@@ -708,10 +838,10 @@ void VideoTrackAdapter::RemoveTrackOnIO(const MediaStreamVideoTrack* track) {
   }
 }
 
-void VideoTrackAdapter::ReconfigureTrackOnIO(
+void VideoTrackAdapter::ReconfigureTrackOnVideoTaskRunner(
     const MediaStreamVideoTrack* track,
     const VideoTrackAdapterSettings& settings) {
-  DCHECK(io_task_runner_->BelongsToCurrentThread());
+  DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
 
   VideoFrameResolutionAdapter::VideoTrackCallbacks track_callbacks;
   // Remove the track.
@@ -728,53 +858,76 @@ void VideoTrackAdapter::ReconfigureTrackOnIO(
 
   // If the track was found, re-add it with new settings.
   if (track_callbacks.frame_callback) {
-    AddTrackOnIO(track, std::move(track_callbacks.frame_callback),
-                 std::move(track_callbacks.settings_callback),
-                 std::move(track_callbacks.format_callback), settings);
+    AddTrackOnVideoTaskRunner(
+        track, std::move(track_callbacks.frame_callback),
+        std::move(track_callbacks.notify_frame_dropped_callback),
+        std::move(track_callbacks.encoded_frame_callback),
+        std::move(track_callbacks.sub_capture_target_version_callback),
+        std::move(track_callbacks.settings_callback),
+        std::move(track_callbacks.format_callback), settings);
   }
 }
 
-void VideoTrackAdapter::DeliverFrameOnIO(
-    scoped_refptr<media::VideoFrame> frame,
+void VideoTrackAdapter::DeliverFrameOnVideoTaskRunner(
+    scoped_refptr<media::VideoFrame> video_frame,
     base::TimeTicks estimated_capture_time) {
-  DCHECK(io_task_runner_->BelongsToCurrentThread());
-  TRACE_EVENT0("media", "VideoTrackAdapter::DeliverFrameOnIO");
+  DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
+  TRACE_EVENT0("media", "VideoTrackAdapter::DeliverFrameOnVideoTaskRunner");
   ++frame_counter_;
 
   bool is_device_rotated = false;
   // TODO(guidou): Use actual device information instead of this heuristic to
   // detect frames from rotated devices. https://crbug.com/722748
   if (source_frame_size_ &&
-      frame->natural_size().width() == source_frame_size_->height() &&
-      frame->natural_size().height() == source_frame_size_->width()) {
+      video_frame->natural_size().width() == source_frame_size_->height() &&
+      video_frame->natural_size().height() == source_frame_size_->width()) {
     is_device_rotated = true;
   }
-  if (adapters_.IsEmpty()) {
-    PostCrossThreadTask(
-        *renderer_task_runner_, FROM_HERE,
-        CrossThreadBindOnce(&MediaStreamVideoSource::OnFrameDropped,
-                            media_stream_video_source_,
-                            media::VideoCaptureFrameDropReason::
-                                kVideoTrackAdapterHasNoResolutionAdapters));
+  for (const auto& adapter : adapters_) {
+    adapter->DeliverFrame(video_frame, estimated_capture_time,
+                          is_device_rotated);
   }
+}
+
+void VideoTrackAdapter::DeliverEncodedVideoFrameOnVideoTaskRunner(
+    scoped_refptr<EncodedVideoFrame> frame,
+    base::TimeTicks estimated_capture_time) {
+  DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
+  TRACE_EVENT0("media",
+               "VideoTrackAdapter::DeliverEncodedVideoFrameOnVideoTaskRunner");
   for (const auto& adapter : adapters_)
-    adapter->DeliverFrame(frame, estimated_capture_time, is_device_rotated);
+    adapter->DeliverEncodedVideoFrame(frame, estimated_capture_time);
 }
 
-void VideoTrackAdapter::CheckFramesReceivedOnIO(
-    OnMutedInternalCallback set_muted_state_callback,
-    uint64_t old_frame_counter_snapshot) {
-  DCHECK(io_task_runner_->BelongsToCurrentThread());
+void VideoTrackAdapter::OnFrameDroppedOnVideoTaskRunner(
+    media::VideoCaptureFrameDropReason reason) {
+  DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
+  TRACE_EVENT0("media", "VideoTrackAdapter::OnFrameDroppedOnVideoTaskRunner");
+  for (const auto& adapter : adapters_) {
+    adapter->OnFrameDropped(reason);
+  }
+}
 
-  if (!monitoring_frame_rate_)
-    return;
+void VideoTrackAdapter::NewSubCaptureTargetVersionOnVideoTaskRunner(
+    uint32_t sub_capture_target_version) {
+  DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
+  TRACE_EVENT0(
+      "media",
+      "VideoTrackAdapter::NewSubCaptureTargetVersionOnVideoTaskRunner");
+  for (const auto& adapter : adapters_) {
+    adapter->NewSubCaptureTargetVersionOnVideoTaskRunner(
+        sub_capture_target_version);
+  }
+}
 
-  DVLOG_IF(1, old_frame_counter_snapshot == frame_counter_)
-      << "No frames have passed, setting source as Muted.";
+void VideoTrackAdapter::CheckFramesReceivedOnVideoTaskRunner() {
+  DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
 
-  bool muted_state = old_frame_counter_snapshot == frame_counter_;
+  DVLOG_IF(1, old_frame_counter_snapshot_ == frame_counter_)
+      << "No frames have passed, setting source as Muted.";
+  bool muted_state = old_frame_counter_snapshot_ == frame_counter_;
   if (muted_state_ != muted_state) {
-    set_muted_state_callback.Run(muted_state);
+    on_muted_callback_.Run(muted_state);
     muted_state_ = muted_state;
     if (muted_state_) {
       for (const auto& adapter : adapters_)
@@ -782,13 +935,9 @@ void VideoTrackAdapter::CheckFramesReceivedOnIO(
     }
   }
 
-  PostDelayedCrossThreadTask(
-      *io_task_runner_, FROM_HERE,
-      CrossThreadBindOnce(
-          &VideoTrackAdapter::CheckFramesReceivedOnIO, WrapRefCounted(this),
-          WTF::Passed(std::move(set_muted_state_callback)), frame_counter_),
-      base::TimeDelta::FromSecondsD(kNormalFrameTimeoutInFrameIntervals /
-                                    source_frame_rate_));
+  old_frame_counter_snapshot_ = frame_counter_;
+  monitoring_frame_rate_timer_->StartOneShot(
+      base::Seconds(kNormalFrameTimeoutInFrameIntervals / source_frame_rate_));
 }
 
 }  // namespace blink