1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
10 #include "base/containers/contains.h"
11 #include "base/functional/bind.h"
12 #include "base/location.h"
13 #include "base/metrics/histogram_functions.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/ranges/algorithm.h"
16 #include "base/task/bind_post_task.h"
17 #include "base/task/sequenced_task_runner.h"
18 #include "base/task/single_thread_task_runner.h"
19 #include "base/time/time.h"
20 #include "build/build_config.h"
21 #include "media/base/limits.h"
22 #include "media/capture/video_capture_types.h"
23 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h"
24 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_sink.h"
25 #include "third_party/blink/public/web/web_local_frame.h"
26 #include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h"
27 #include "third_party/blink/renderer/platform/allow_discouraged_type.h"
28 #include "third_party/blink/renderer/platform/mediastream/media_stream_component_impl.h"
29 #include "third_party/blink/renderer/platform/scheduler/public/main_thread.h"
30 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
31 #include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h"
32 #include "third_party/blink/renderer/platform/wtf/cross_thread_copier_std.h"
33 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
34 #include "third_party/blink/renderer/platform/wtf/vector.h"
39 // A lower-bound for the refresh interval.
40 constexpr base::TimeDelta kLowerBoundRefreshInterval =
41 base::Hertz(media::limits::kMaxFramesPerSecond);
43 // This alias mimics the definition of VideoCaptureDeliverFrameCB.
44 using VideoCaptureDeliverFrameInternalCallback = WTF::CrossThreadFunction<void(
45 scoped_refptr<media::VideoFrame> video_frame,
46 base::TimeTicks estimated_capture_time)>;
48 // This alias mimics the definition of VideoCaptureNotifyFrameDroppedCB.
49 using VideoCaptureNotifyFrameDroppedInternalCallback =
50 WTF::CrossThreadFunction<void(media::VideoCaptureFrameDropReason)>;
52 // Mimics blink::EncodedVideoFrameCB
53 using EncodedVideoFrameInternalCallback =
54 WTF::CrossThreadFunction<void(scoped_refptr<EncodedVideoFrame> frame,
55 base::TimeTicks estimated_capture_time)>;
57 base::TimeDelta ComputeRefreshIntervalFromBounds(
58 const base::TimeDelta required_min_refresh_interval,
59 const absl::optional<double>& min_frame_rate,
60 const absl::optional<double>& max_frame_rate) {
61 // Start with the default required refresh interval, and refine based on
62 // constraints. If a minimum frameRate is provided, use that. Otherwise, use
63 // the maximum frameRate if it happens to be less than the default.
64 base::TimeDelta refresh_interval = required_min_refresh_interval;
65 if (min_frame_rate.has_value())
66 refresh_interval = base::Hertz(*min_frame_rate);
68 if (max_frame_rate.has_value()) {
69 refresh_interval = std::max(refresh_interval, base::Hertz(*max_frame_rate));
72 if (refresh_interval < kLowerBoundRefreshInterval)
73 refresh_interval = kLowerBoundRefreshInterval;
75 return refresh_interval;
78 void LogVideoFrameDropUMA(media::VideoCaptureFrameDropReason reason,
79 mojom::blink::MediaStreamType stream_type) {
80 const int kEnumCount =
81 static_cast<int>(media::VideoCaptureFrameDropReason::kMaxValue) + 1;
82 UMA_HISTOGRAM_ENUMERATION("Media.VideoCapture.Track.FrameDrop", reason,
84 switch (stream_type) {
85 case mojom::blink::MediaStreamType::DEVICE_VIDEO_CAPTURE:
86 UMA_HISTOGRAM_ENUMERATION(
87 "Media.VideoCapture.Track.FrameDrop.DeviceCapture", reason,
90 case mojom::blink::MediaStreamType::GUM_TAB_VIDEO_CAPTURE:
91 UMA_HISTOGRAM_ENUMERATION(
92 "Media.VideoCapture.Track.FrameDrop.GumTabCapture", reason,
95 case mojom::blink::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE:
96 UMA_HISTOGRAM_ENUMERATION(
97 "Media.VideoCapture.Track.FrameDrop.GumDesktopCapture", reason,
100 case mojom::blink::MediaStreamType::DISPLAY_VIDEO_CAPTURE:
101 UMA_HISTOGRAM_ENUMERATION(
102 "Media.VideoCapture.Track.FrameDrop.DisplayCapture", reason,
105 case mojom::blink::MediaStreamType::DISPLAY_VIDEO_CAPTURE_THIS_TAB:
106 UMA_HISTOGRAM_ENUMERATION(
107 "Media.VideoCapture.Track.FrameDrop.DisplayCaptureCurrentTab", reason,
110 case mojom::blink::MediaStreamType::DISPLAY_VIDEO_CAPTURE_SET:
111 UMA_HISTOGRAM_ENUMERATION(
112 "Media.VideoCapture.Track.FrameDrop.DisplayCaptureSet", reason,
115 case mojom::blink::MediaStreamType::NO_SERVICE:
116 case mojom::blink::MediaStreamType::DEVICE_AUDIO_CAPTURE:
117 case mojom::blink::MediaStreamType::GUM_TAB_AUDIO_CAPTURE:
118 case mojom::blink::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE:
119 case mojom::blink::MediaStreamType::DISPLAY_AUDIO_CAPTURE:
120 case mojom::blink::MediaStreamType::NUM_MEDIA_TYPES:
127 // MediaStreamVideoTrack::FrameDeliverer is a helper class used for registering
128 // VideoCaptureDeliverFrameCB/EncodedVideoFrameCB callbacks on the main render
129 // thread to receive video frames on the video task runner. Frames are only
130 // delivered to the sinks if the track is enabled. If the track is disabled, a
131 // black frame is instead forwarded to the sinks at the same frame rate. A
132 // disabled track does not forward data to encoded sinks.
133 class MediaStreamVideoTrack::FrameDeliverer
134 : public WTF::ThreadSafeRefCounted<FrameDeliverer> {
136 using VideoSinkId = WebMediaStreamSink*;
139 scoped_refptr<base::SingleThreadTaskRunner> main_render_task_runner,
140 scoped_refptr<base::SequencedTaskRunner> video_task_runner,
141 base::WeakPtr<MediaStreamVideoTrack> media_stream_video_track,
142 base::WeakPtr<MediaStreamVideoSource> media_stream_video_source,
144 uint32_t sub_capture_target_version);
146 FrameDeliverer(const FrameDeliverer&) = delete;
147 FrameDeliverer& operator=(const FrameDeliverer&) = delete;
149 // Sets whether the track is enabled or not. If getting enabled and encoded
150 // output is enabled, the deliverer will wait until the next key frame before
151 // it resumes producing encoded data.
152 void SetEnabled(bool enabled, bool await_key_frame);
154 // Add |callback| to receive video frames on the video task runner.
155 // Must be called on the main render thread.
156 void AddCallback(VideoSinkId id, VideoCaptureDeliverFrameCB callback);
158 // Sets the frame dropped callback of the sink of frame |id].
159 void SetNotifyFrameDroppedCallback(VideoSinkId id,
160 VideoCaptureNotifyFrameDroppedCB callback);
162 // Add |callback| to receive encoded video frames on the video task runner.
163 // Must be called on the main render thread.
164 void AddEncodedCallback(VideoSinkId id, EncodedVideoFrameCB callback);
166 // Removes |callback| associated with |id| from receiving video frames if |id|
167 // has been added. It is ok to call RemoveCallback even if the |id| has not
168 // been added. Note that the added callback will be reset on the main thread.
169 // Must be called on the main render thread.
170 void RemoveCallback(VideoSinkId id);
172 // Removes encoded callback associated with |id| from receiving video frames
173 // if |id| has been added. It is ok to call RemoveEncodedCallback even if the
174 // |id| has not been added. Note that the added callback will be reset on the
175 // main thread. Must be called on the main render thread.
176 void RemoveEncodedCallback(VideoSinkId id);
178 // Triggers all registered callbacks with |frame| and |estimated_capture_time|
179 // as parameters. Must be called on the video task runner.
180 void DeliverFrameOnVideoTaskRunner(
181 scoped_refptr<media::VideoFrame> frame,
182 base::TimeTicks estimated_capture_time);
184 // A frame was dropped instead of delivered. This is the main handler of frame
185 // drops: it updates dropped/discarded counters, invokes
186 // LogFrameDroppedOnVideoTaskRunner() and notifies `callbacks_` (i.e. sinks)
187 // that a frame was dropped.
188 void OnFrameDroppedOnVideoTaskRunner(
189 media::VideoCaptureFrameDropReason reason);
191 // Can be called from any task runner (is atomic).
192 size_t deliverable_frames() const { return deliverable_frames_; }
193 size_t discarded_frames() const { return discarded_frames_; }
194 size_t dropped_frames() const { return dropped_frames_; }
196 // Triggers all encoded callbacks with |frame| and |estimated_capture_time|.
197 // Must be called on the video task runner.
198 void DeliverEncodedVideoFrameOnVideoTaskRunner(
199 scoped_refptr<EncodedVideoFrame> frame,
200 base::TimeTicks estimated_capture_time);
202 // Called when a sub-capture-target-version is acknowledged by the capture
203 // module. After this, it is guaranteed that all subsequent frames will be
204 // associated with a sub-capture-target-version that is >=
205 // |sub_capture_target_version|. Must be called on the video task runner.
206 void NewSubCaptureTargetVersionOnVideoTaskRunner(
207 uint32_t sub_capture_target_version);
209 void SetIsRefreshingForMinFrameRate(bool is_refreshing_for_min_frame_rate);
211 void AddSubCaptureTargetVersionCallback(uint32_t sub_capture_target_version,
212 base::OnceClosure callback);
213 void RemoveSubCaptureTargetVersionCallback(
214 uint32_t sub_capture_target_version);
216 // Performs logging and UMAs relating to frame drops. This includes both
217 // frames dropped prior to delivery (OnFrameDroppedOnVideoTaskRunner) and
218 // MediaStreamVideoTrack::OnSinkDroppedFrame().
219 void LogFrameDroppedOnVideoTaskRunner(
220 media::VideoCaptureFrameDropReason reason);
222 void SetEmitLogMessage(
223 base::RepeatingCallback<void(const std::string&)> emit_log_message);
226 friend class WTF::ThreadSafeRefCounted<FrameDeliverer>;
228 // Struct containing sink id, frame delivery and frame dropped callbacks.
229 struct VideoIdCallbacks {
231 VideoCaptureDeliverFrameInternalCallback deliver_frame;
232 VideoCaptureNotifyFrameDroppedInternalCallback notify_frame_dropped;
235 virtual ~FrameDeliverer();
236 void AddCallbackOnVideoTaskRunner(
238 VideoCaptureDeliverFrameInternalCallback callback);
239 void SetNotifyFrameDroppedCallbackOnVideoTaskRunner(
241 VideoCaptureNotifyFrameDroppedInternalCallback callback,
242 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
243 void RemoveCallbackOnVideoTaskRunner(
245 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
247 void AddEncodedCallbackOnVideoTaskRunner(
249 EncodedVideoFrameInternalCallback callback);
250 void RemoveEncodedCallbackOnVideoTaskRunner(
252 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
254 void SetEnabledOnVideoTaskRunner(bool enabled, bool await_key_frame);
256 void SetIsRefreshingForMinFrameRateOnVideoTaskRunner(
257 bool is_refreshing_for_min_frame_rate);
259 void AddSubCaptureTargetVersionCallbackOnVideoTaskRunner(
260 uint32_t sub_capture_target_version,
261 WTF::CrossThreadOnceClosure callback);
262 void RemoveSubCaptureTargetVersionCallbackOnVideoTaskRunner(
263 uint32_t sub_capture_target_version);
265 // Returns a black frame where the size and time stamp is set to the same as
266 // as in |reference_frame|.
267 scoped_refptr<media::VideoFrame> GetBlackFrame(
268 const media::VideoFrame& reference_frame);
270 // Used to DCHECK that AddCallback and RemoveCallback are called on the main
272 THREAD_CHECKER(main_render_thread_checker_);
273 const scoped_refptr<base::SequencedTaskRunner> video_task_runner_;
274 const scoped_refptr<base::SingleThreadTaskRunner> main_render_task_runner_;
276 base::WeakPtr<MediaStreamVideoTrack> media_stream_video_track_;
277 base::WeakPtr<MediaStreamVideoSource> media_stream_video_source_;
278 const mojom::blink::MediaStreamType stream_type_;
281 scoped_refptr<media::VideoFrame> black_frame_;
282 bool emit_frame_drop_events_;
284 Vector<VideoIdCallbacks> callbacks_;
285 HashMap<VideoSinkId, EncodedVideoFrameInternalCallback> encoded_callbacks_;
287 // Frame counters for the MediaStreamTrack Statistics API. The counters are
288 // only incremented when the track is enabled (even though a disabled track
289 // delivers black frames).
290 std::atomic<size_t> deliverable_frames_ = 0;
291 std::atomic<size_t> discarded_frames_ = 0;
292 std::atomic<size_t> dropped_frames_ = 0;
294 // Helper methods for LogFrameDroppedOnVideoTaskRunner().
295 void MaybeEmitFrameDropLogMessage(media::VideoCaptureFrameDropReason reason);
296 void EmitLogMessage(const std::string& message);
297 base::RepeatingCallback<void(const std::string&)> emit_log_message_;
298 // States relating to frame drop logging and UMAs.
299 struct FrameDropLogState {
300 explicit FrameDropLogState(media::VideoCaptureFrameDropReason reason =
301 media::VideoCaptureFrameDropReason::kNone);
304 media::VideoCaptureFrameDropReason drop_reason =
305 media::VideoCaptureFrameDropReason::kNone;
306 bool max_log_count_exceeded = false;
308 FrameDropLogState frame_drop_log_state_;
309 // Tracks how often each frame-drop reason was encountered to decide whether
310 // or not to LOG the console.
311 std::map<media::VideoCaptureFrameDropReason, int> frame_drop_log_counters_
312 ALLOW_DISCOURAGED_TYPE("TODO(crbug.com/1481448)");
314 // Callbacks that will be invoked a single time when a
315 // sub-capture-target-version is observed that is at least equal to the key.
316 // The map itself (sub_capture_target_version_callbacks_) is bound to the
317 // video task runner. The callbacks are bound to their respective threads
319 HashMap<uint32_t, WTF::CrossThreadOnceClosure>
320 sub_capture_target_version_callbacks_;
322 bool await_next_key_frame_;
324 // This should only be accessed on the video task runner.
325 bool is_refreshing_for_min_frame_rate_ = false;
327 // This monotonously increasing value indicates which
328 // sub-capture-target-version is expected for delivered frames.
329 uint32_t sub_capture_target_version_ = 0;
332 MediaStreamVideoTrack::FrameDeliverer::FrameDropLogState::FrameDropLogState(
333 media::VideoCaptureFrameDropReason reason)
334 : drop_count((reason == media::VideoCaptureFrameDropReason::kNone) ? 0 : 1),
336 max_log_count_exceeded(false) {}
338 MediaStreamVideoTrack::FrameDeliverer::FrameDeliverer(
339 scoped_refptr<base::SingleThreadTaskRunner> main_render_task_runner,
340 scoped_refptr<base::SequencedTaskRunner> video_task_runner,
341 base::WeakPtr<MediaStreamVideoTrack> media_stream_video_track,
342 base::WeakPtr<MediaStreamVideoSource> media_stream_video_source,
344 uint32_t sub_capture_target_version)
345 : video_task_runner_(std::move(video_task_runner)),
346 main_render_task_runner_(main_render_task_runner),
347 media_stream_video_track_(media_stream_video_track),
348 media_stream_video_source_(media_stream_video_source),
349 stream_type_(media_stream_video_source_->device().type),
351 emit_frame_drop_events_(true),
352 await_next_key_frame_(false),
353 sub_capture_target_version_(sub_capture_target_version) {
354 DCHECK(video_task_runner_.get());
355 DCHECK(main_render_task_runner_);
356 SetEmitLogMessage(ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
357 &MediaStreamVideoTrack::FrameDeliverer::EmitLogMessage,
358 WTF::CrossThreadUnretained(this))));
361 MediaStreamVideoTrack::FrameDeliverer::~FrameDeliverer() {
362 DCHECK(callbacks_.empty());
365 void MediaStreamVideoTrack::FrameDeliverer::AddCallback(
367 VideoCaptureDeliverFrameCB callback) {
368 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
370 *video_task_runner_, FROM_HERE,
371 CrossThreadBindOnce(&FrameDeliverer::AddCallbackOnVideoTaskRunner,
372 WrapRefCounted(this), WTF::CrossThreadUnretained(id),
373 CrossThreadBindRepeating(std::move(callback))));
376 void MediaStreamVideoTrack::FrameDeliverer::AddCallbackOnVideoTaskRunner(
378 VideoCaptureDeliverFrameInternalCallback callback) {
379 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
380 callbacks_.push_back(VideoIdCallbacks{
381 id, std::move(callback),
382 CrossThreadBindRepeating([](media::VideoCaptureFrameDropReason) {})});
385 void MediaStreamVideoTrack::FrameDeliverer::SetNotifyFrameDroppedCallback(
387 VideoCaptureNotifyFrameDroppedCB callback) {
388 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
390 *video_task_runner_, FROM_HERE,
392 &FrameDeliverer::SetNotifyFrameDroppedCallbackOnVideoTaskRunner,
393 WrapRefCounted(this), WTF::CrossThreadUnretained(id),
394 CrossThreadBindRepeating(std::move(callback)),
395 main_render_task_runner_));
398 void MediaStreamVideoTrack::FrameDeliverer::
399 SetNotifyFrameDroppedCallbackOnVideoTaskRunner(
401 VideoCaptureNotifyFrameDroppedInternalCallback callback,
402 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
403 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
404 DVLOG(1) << __func__;
405 for (auto& entry : callbacks_) {
406 if (entry.id == id) {
407 // Old callback destruction needs to happen on the specified task
410 *task_runner, FROM_HERE,
412 [](VideoCaptureNotifyFrameDroppedInternalCallback) {},
413 std::move(entry.notify_frame_dropped)));
414 entry.notify_frame_dropped = std::move(callback);
419 void MediaStreamVideoTrack::FrameDeliverer::AddEncodedCallback(
421 EncodedVideoFrameCB callback) {
422 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
424 *video_task_runner_, FROM_HERE,
425 CrossThreadBindOnce(&FrameDeliverer::AddEncodedCallbackOnVideoTaskRunner,
426 WrapRefCounted(this), WTF::CrossThreadUnretained(id),
427 CrossThreadBindRepeating(std::move(callback))));
430 void MediaStreamVideoTrack::FrameDeliverer::AddEncodedCallbackOnVideoTaskRunner(
432 EncodedVideoFrameInternalCallback callback) {
433 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
434 encoded_callbacks_.insert(id, std::move(callback));
437 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallback(VideoSinkId id) {
438 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
440 *video_task_runner_, FROM_HERE,
441 CrossThreadBindOnce(&FrameDeliverer::RemoveCallbackOnVideoTaskRunner,
442 WrapRefCounted(this), WTF::CrossThreadUnretained(id),
443 main_render_task_runner_));
446 void MediaStreamVideoTrack::FrameDeliverer::RemoveCallbackOnVideoTaskRunner(
448 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
449 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
450 auto* it = callbacks_.begin();
451 for (; it != callbacks_.end(); ++it) {
453 // Callback destruction needs to happen on the specified task runner.
455 *task_runner, FROM_HERE,
457 [](VideoCaptureDeliverFrameInternalCallback frame,
458 VideoCaptureNotifyFrameDroppedInternalCallback dropped) {},
459 std::move(it->deliver_frame),
460 std::move(it->notify_frame_dropped)));
461 callbacks_.erase(it);
467 void MediaStreamVideoTrack::FrameDeliverer::RemoveEncodedCallback(
469 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
471 *video_task_runner_, FROM_HERE,
473 &FrameDeliverer::RemoveEncodedCallbackOnVideoTaskRunner,
474 WrapRefCounted(this), WTF::CrossThreadUnretained(id),
475 main_render_task_runner_));
478 void MediaStreamVideoTrack::FrameDeliverer::
479 RemoveEncodedCallbackOnVideoTaskRunner(
481 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
482 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
484 // Callback destruction needs to happen on the specified task runner.
485 auto it = encoded_callbacks_.find(id);
486 if (it == encoded_callbacks_.end())
489 *task_runner, FROM_HERE,
490 CrossThreadBindOnce([](EncodedVideoFrameInternalCallback callback) {},
491 std::move(it->value)));
492 encoded_callbacks_.erase(it);
495 void MediaStreamVideoTrack::FrameDeliverer::SetEnabled(bool enabled,
496 bool await_key_frame) {
497 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
499 *video_task_runner_, FROM_HERE,
500 CrossThreadBindOnce(&FrameDeliverer::SetEnabledOnVideoTaskRunner,
501 WrapRefCounted(this), enabled, await_key_frame));
504 void MediaStreamVideoTrack::FrameDeliverer::SetEnabledOnVideoTaskRunner(
506 bool await_key_frame) {
507 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
508 if (enabled != enabled_) {
510 emit_frame_drop_events_ = true;
513 black_frame_ = nullptr;
514 await_next_key_frame_ = await_key_frame;
518 void MediaStreamVideoTrack::FrameDeliverer::SetIsRefreshingForMinFrameRate(
519 bool is_refreshing_for_min_frame_rate) {
520 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
522 *video_task_runner_, FROM_HERE,
524 &FrameDeliverer::SetIsRefreshingForMinFrameRateOnVideoTaskRunner,
525 WrapRefCounted(this), is_refreshing_for_min_frame_rate));
528 void MediaStreamVideoTrack::FrameDeliverer::AddSubCaptureTargetVersionCallback(
529 uint32_t sub_capture_target_version,
530 base::OnceClosure callback) {
531 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
534 *video_task_runner_, FROM_HERE,
536 &FrameDeliverer::AddSubCaptureTargetVersionCallbackOnVideoTaskRunner,
537 WrapRefCounted(this), sub_capture_target_version,
538 CrossThreadBindOnce(std::move(callback))));
541 void MediaStreamVideoTrack::FrameDeliverer::
542 RemoveSubCaptureTargetVersionCallback(uint32_t sub_capture_target_version) {
543 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
546 *video_task_runner_, FROM_HERE,
549 RemoveSubCaptureTargetVersionCallbackOnVideoTaskRunner,
550 WrapRefCounted(this), sub_capture_target_version));
553 void MediaStreamVideoTrack::FrameDeliverer::
554 SetIsRefreshingForMinFrameRateOnVideoTaskRunner(
555 bool is_refreshing_for_min_frame_rate) {
556 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
557 is_refreshing_for_min_frame_rate_ = is_refreshing_for_min_frame_rate;
560 void MediaStreamVideoTrack::FrameDeliverer::
561 AddSubCaptureTargetVersionCallbackOnVideoTaskRunner(
562 uint32_t sub_capture_target_version,
563 WTF::CrossThreadOnceClosure callback) {
564 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
565 DCHECK(!base::Contains(sub_capture_target_version_callbacks_,
566 sub_capture_target_version));
568 sub_capture_target_version_callbacks_.Set(sub_capture_target_version,
569 std::move(callback));
572 void MediaStreamVideoTrack::FrameDeliverer::
573 RemoveSubCaptureTargetVersionCallbackOnVideoTaskRunner(
574 uint32_t sub_capture_target_version) {
575 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
577 // Note: Might or might not be here, depending on whether a later crop
578 // version has already been observed or not.
579 sub_capture_target_version_callbacks_.erase(sub_capture_target_version);
582 void MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnVideoTaskRunner(
583 scoped_refptr<media::VideoFrame> frame,
584 base::TimeTicks estimated_capture_time) {
585 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
587 frame_drop_log_state_ = FrameDropLogState();
589 // TODO(crbug.com/1369085): Understand why we sometimes see old
590 // sub-capture-target versions.
591 if (frame->metadata().sub_capture_target_version !=
592 sub_capture_target_version_) {
593 OnFrameDroppedOnVideoTaskRunner(
594 media::VideoCaptureFrameDropReason::kSubCaptureTargetVersionNotCurrent);
598 if (!enabled_ && emit_frame_drop_events_) {
599 emit_frame_drop_events_ = false;
600 LogFrameDroppedOnVideoTaskRunner(
601 media::VideoCaptureFrameDropReason::
602 kVideoTrackFrameDelivererNotEnabledReplacingWithBlackFrame);
604 scoped_refptr<media::VideoFrame> video_frame;
605 if (enabled_ || frame->metadata().end_of_stream) {
606 video_frame = std::move(frame);
607 ++deliverable_frames_;
609 // When disabled, a black video frame is passed along instead. The original
610 // frames are dropped.
611 video_frame = GetBlackFrame(*frame);
613 for (const auto& entry : callbacks_) {
614 entry.deliver_frame.Run(video_frame, estimated_capture_time);
616 // The delay on refresh timer is reset each time a frame is received so that
617 // it will not fire for at least an additional period. This means refresh
618 // frames will only be requested when the source has halted delivery (e.g., a
619 // screen capturer stops sending frames because the screen is not being
621 if (is_refreshing_for_min_frame_rate_) {
623 *main_render_task_runner_, FROM_HERE,
624 CrossThreadBindOnce(&MediaStreamVideoTrack::ResetRefreshTimer,
625 media_stream_video_track_));
629 void MediaStreamVideoTrack::FrameDeliverer::OnFrameDroppedOnVideoTaskRunner(
630 media::VideoCaptureFrameDropReason reason) {
631 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
632 DVLOG(1) << __func__;
633 LogFrameDroppedOnVideoTaskRunner(reason);
635 if (reason == media::VideoCaptureFrameDropReason::
636 kResolutionAdapterFrameRateIsHigherThanRequested) {
642 // Notify sinks that care about frame drops, i.e. WebRTC.
643 for (const auto& entry : callbacks_) {
644 entry.notify_frame_dropped.Run(reason);
648 void MediaStreamVideoTrack::FrameDeliverer::LogFrameDroppedOnVideoTaskRunner(
649 media::VideoCaptureFrameDropReason reason) {
650 MaybeEmitFrameDropLogMessage(reason);
652 if (reason == frame_drop_log_state_.drop_reason) {
653 if (frame_drop_log_state_.max_log_count_exceeded) {
657 if (++frame_drop_log_state_.drop_count >
658 kMaxConsecutiveFrameDropForSameReasonCount) {
659 frame_drop_log_state_.max_log_count_exceeded = true;
663 frame_drop_log_state_ = FrameDropLogState(reason);
666 LogVideoFrameDropUMA(reason, stream_type_);
669 void MediaStreamVideoTrack::FrameDeliverer::MaybeEmitFrameDropLogMessage(
670 media::VideoCaptureFrameDropReason reason) {
671 using Type = std::underlying_type<media::VideoCaptureFrameDropReason>::type;
673 static_cast<Type>(media::VideoCaptureFrameDropReason::kMaxValue) <= 100,
674 "Risk of memory overuse.");
676 static_assert(kMaxEmittedLogsForDroppedFramesBeforeSuppressing <
677 kFrequencyForSuppressedLogs,
680 DCHECK_GE(static_cast<Type>(reason), 0);
681 DCHECK_LE(reason, media::VideoCaptureFrameDropReason::kMaxValue);
683 int& occurrences = frame_drop_log_counters_[reason];
684 if (++occurrences > kMaxEmittedLogsForDroppedFramesBeforeSuppressing &&
685 occurrences % kFrequencyForSuppressedLogs != 0) {
689 std::ostringstream string_stream;
690 string_stream << "Frame dropped with reason code "
691 << static_cast<Type>(reason) << ".";
692 if (occurrences == kMaxEmittedLogsForDroppedFramesBeforeSuppressing) {
693 string_stream << " Additional logs will be partially suppressed.";
696 // EmitLogMessage() unless overridden by testing.
697 emit_log_message_.Run(string_stream.str());
700 void MediaStreamVideoTrack::FrameDeliverer::SetEmitLogMessage(
701 base::RepeatingCallback<void(const std::string&)> emit_log_message) {
702 emit_log_message_ = std::move(emit_log_message);
705 void MediaStreamVideoTrack::FrameDeliverer::EmitLogMessage(
706 const std::string& message) {
707 PostCrossThreadTask(*main_render_task_runner_, FROM_HERE,
708 CrossThreadBindOnce(&MediaStreamVideoSource::OnLog,
709 media_stream_video_source_, message));
712 void MediaStreamVideoTrack::FrameDeliverer::
713 DeliverEncodedVideoFrameOnVideoTaskRunner(
714 scoped_refptr<EncodedVideoFrame> frame,
715 base::TimeTicks estimated_capture_time) {
716 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
720 if (await_next_key_frame_ && !frame->IsKeyFrame()) {
723 await_next_key_frame_ = false;
724 for (const auto& entry : encoded_callbacks_.Values()) {
725 entry.Run(frame, estimated_capture_time);
729 void MediaStreamVideoTrack::FrameDeliverer::
730 NewSubCaptureTargetVersionOnVideoTaskRunner(
731 uint32_t sub_capture_target_version) {
732 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
733 DCHECK_GT(sub_capture_target_version, sub_capture_target_version_);
735 sub_capture_target_version_ = sub_capture_target_version;
737 Vector<uint32_t> to_be_removed_keys;
738 for (auto& iter : sub_capture_target_version_callbacks_) {
739 if (iter.key > sub_capture_target_version) {
742 std::move(iter.value).Run();
743 to_be_removed_keys.push_back(iter.key);
745 sub_capture_target_version_callbacks_.RemoveAll(to_be_removed_keys);
748 scoped_refptr<media::VideoFrame>
749 MediaStreamVideoTrack::FrameDeliverer::GetBlackFrame(
750 const media::VideoFrame& reference_frame) {
751 DCHECK(video_task_runner_->RunsTasksInCurrentSequence());
752 if (!black_frame_.get() ||
753 black_frame_->natural_size() != reference_frame.natural_size()) {
755 media::VideoFrame::CreateBlackFrame(reference_frame.natural_size());
758 // Wrap |black_frame_| so we get a fresh timestamp we can modify. Frames
759 // returned from this function may still be in use.
760 scoped_refptr<media::VideoFrame> wrapped_black_frame =
761 media::VideoFrame::WrapVideoFrame(black_frame_, black_frame_->format(),
762 black_frame_->visible_rect(),
763 black_frame_->natural_size());
764 if (!wrapped_black_frame)
767 wrapped_black_frame->set_timestamp(reference_frame.timestamp());
768 wrapped_black_frame->metadata().reference_time =
769 reference_frame.metadata().reference_time;
771 return wrapped_black_frame;
775 WebMediaStreamTrack MediaStreamVideoTrack::CreateVideoTrack(
776 MediaStreamVideoSource* source,
777 MediaStreamVideoSource::ConstraintsOnceCallback callback,
779 auto* component = MakeGarbageCollected<MediaStreamComponentImpl>(
780 source->Owner(), std::make_unique<MediaStreamVideoTrack>(
781 source, std::move(callback), enabled));
782 return WebMediaStreamTrack(component);
786 WebMediaStreamTrack MediaStreamVideoTrack::CreateVideoTrack(
787 MediaStreamVideoSource* source,
788 const VideoTrackAdapterSettings& adapter_settings,
789 const absl::optional<bool>& noise_reduction,
791 const absl::optional<double>& min_frame_rate,
792 const absl::optional<double>& pan,
793 const absl::optional<double>& tilt,
794 const absl::optional<double>& zoom,
795 bool pan_tilt_zoom_allowed,
796 MediaStreamVideoSource::ConstraintsOnceCallback callback,
798 WebMediaStreamTrack track;
799 auto* component = MakeGarbageCollected<MediaStreamComponentImpl>(
801 std::make_unique<MediaStreamVideoTrack>(
802 source, adapter_settings, noise_reduction, is_screencast,
803 min_frame_rate, pan, tilt, zoom, pan_tilt_zoom_allowed,
804 std::move(callback), enabled));
805 return WebMediaStreamTrack(component);
809 MediaStreamVideoTrack* MediaStreamVideoTrack::From(
810 const MediaStreamComponent* component) {
812 component->GetSourceType() != MediaStreamSource::kTypeVideo) {
816 return static_cast<MediaStreamVideoTrack*>(component->GetPlatformTrack());
819 MediaStreamVideoTrack::MediaStreamVideoTrack(
820 MediaStreamVideoSource* source,
821 MediaStreamVideoSource::ConstraintsOnceCallback callback,
823 : MediaStreamTrackPlatform(true),
824 is_screencast_(false),
825 source_(source->GetWeakPtr()) {
827 base::MakeRefCounted<MediaStreamVideoTrack::FrameDeliverer>(
828 source->GetTaskRunner(), source->video_task_runner(),
829 weak_factory_.GetWeakPtr(), source->GetWeakPtr(), enabled,
830 source->GetSubCaptureTargetVersion());
832 this, VideoTrackAdapterSettings(),
833 ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
834 &MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnVideoTaskRunner,
836 ConvertToBaseRepeatingCallback(
837 CrossThreadBindRepeating(&MediaStreamVideoTrack::FrameDeliverer::
838 OnFrameDroppedOnVideoTaskRunner,
840 ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
841 &MediaStreamVideoTrack::FrameDeliverer::
842 DeliverEncodedVideoFrameOnVideoTaskRunner,
844 ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
845 &MediaStreamVideoTrack::FrameDeliverer::
846 NewSubCaptureTargetVersionOnVideoTaskRunner,
848 base::BindPostTaskToCurrentDefault(WTF::BindRepeating(
849 &MediaStreamVideoTrack::SetSizeAndComputedFrameRate,
850 weak_factory_.GetWeakPtr())),
851 base::BindPostTaskToCurrentDefault(
852 WTF::BindRepeating(&MediaStreamVideoTrack::set_computed_source_format,
853 weak_factory_.GetWeakPtr())),
854 std::move(callback));
857 MediaStreamVideoTrack::MediaStreamVideoTrack(
858 MediaStreamVideoSource* source,
859 const VideoTrackAdapterSettings& adapter_settings,
860 const absl::optional<bool>& noise_reduction,
862 const absl::optional<double>& min_frame_rate,
863 const absl::optional<double>& pan,
864 const absl::optional<double>& tilt,
865 const absl::optional<double>& zoom,
866 bool pan_tilt_zoom_allowed,
867 MediaStreamVideoSource::ConstraintsOnceCallback callback,
869 : MediaStreamTrackPlatform(true),
870 adapter_settings_(adapter_settings),
871 noise_reduction_(noise_reduction),
872 is_screencast_(is_screen_cast),
873 min_frame_rate_(min_frame_rate),
877 pan_tilt_zoom_allowed_(pan_tilt_zoom_allowed),
878 source_(source->GetWeakPtr()) {
880 base::MakeRefCounted<MediaStreamVideoTrack::FrameDeliverer>(
881 source->GetTaskRunner(), source->video_task_runner(),
882 weak_factory_.GetWeakPtr(), source->GetWeakPtr(), enabled,
883 source->GetSubCaptureTargetVersion());
885 this, adapter_settings,
886 ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
887 &MediaStreamVideoTrack::FrameDeliverer::DeliverFrameOnVideoTaskRunner,
889 ConvertToBaseRepeatingCallback(
890 CrossThreadBindRepeating(&MediaStreamVideoTrack::FrameDeliverer::
891 OnFrameDroppedOnVideoTaskRunner,
893 ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
894 &MediaStreamVideoTrack::FrameDeliverer::
895 DeliverEncodedVideoFrameOnVideoTaskRunner,
897 ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
898 &MediaStreamVideoTrack::FrameDeliverer::
899 NewSubCaptureTargetVersionOnVideoTaskRunner,
901 base::BindPostTaskToCurrentDefault(WTF::BindRepeating(
902 &MediaStreamVideoTrack::SetSizeAndComputedFrameRate,
903 weak_factory_.GetWeakPtr())),
904 base::BindPostTaskToCurrentDefault(
905 WTF::BindRepeating(&MediaStreamVideoTrack::set_computed_source_format,
906 weak_factory_.GetWeakPtr())),
907 std::move(callback));
910 MediaStreamVideoTrack::~MediaStreamVideoTrack() {
911 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
912 DCHECK(sinks_.empty());
913 DCHECK(encoded_sinks_.empty());
915 DVLOG(3) << "~MediaStreamVideoTrack()";
918 std::unique_ptr<MediaStreamTrackPlatform>
919 MediaStreamVideoTrack::CreateFromComponent(
920 const MediaStreamComponent* component,
922 MediaStreamSource* source = component->Source();
923 DCHECK_EQ(source->GetType(), MediaStreamSource::kTypeVideo);
924 MediaStreamVideoSource* native_source =
925 MediaStreamVideoSource::GetVideoSource(source);
926 DCHECK(native_source);
927 MediaStreamVideoTrack* original_track =
928 MediaStreamVideoTrack::From(component);
929 DCHECK(original_track);
930 return std::make_unique<MediaStreamVideoTrack>(
931 native_source, original_track->adapter_settings(),
932 original_track->noise_reduction(), original_track->is_screencast(),
933 original_track->min_frame_rate(), original_track->pan(),
934 original_track->tilt(), original_track->zoom(),
935 original_track->pan_tilt_zoom_allowed(),
936 MediaStreamVideoSource::ConstraintsOnceCallback(), component->Enabled());
939 static void AddSinkInternal(Vector<WebMediaStreamSink*>* sinks,
940 WebMediaStreamSink* sink) {
941 DCHECK(!base::Contains(*sinks, sink));
942 sinks->push_back(sink);
945 static void RemoveSinkInternal(Vector<WebMediaStreamSink*>* sinks,
946 WebMediaStreamSink* sink) {
947 auto** it = base::ranges::find(*sinks, sink);
948 DCHECK(it != sinks->end());
952 void MediaStreamVideoTrack::AddSink(
953 WebMediaStreamSink* sink,
954 const VideoCaptureDeliverFrameCB& callback,
955 MediaStreamVideoSink::IsSecure is_secure,
956 MediaStreamVideoSink::UsesAlpha uses_alpha) {
957 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
958 AddSinkInternal(&sinks_, sink);
959 frame_deliverer_->AddCallback(sink, callback);
960 secure_tracker_.Add(sink, is_secure == MediaStreamVideoSink::IsSecure::kYes);
961 if (uses_alpha == MediaStreamVideoSink::UsesAlpha::kDefault) {
962 alpha_using_sinks_.insert(sink);
963 } else if (uses_alpha == MediaStreamVideoSink::UsesAlpha::kNo) {
964 alpha_discarding_sinks_.insert(sink);
967 // Ensure sink gets told about any constraints set.
968 sink->OnVideoConstraintsChanged(min_frame_rate_,
969 adapter_settings_.max_frame_rate());
971 // Request source to deliver a frame because a new sink is added.
974 UpdateSourceHasConsumers();
975 RequestRefreshFrame();
976 source_->UpdateCapturingLinkSecure(this,
977 secure_tracker_.is_capturing_secure());
979 source_->UpdateCanDiscardAlpha();
982 StartTimerForRequestingFrames();
985 bool MediaStreamVideoTrack::UsingAlpha() {
986 // Alpha can't be discarded if any sink uses alpha, or if the only sinks
987 // connected are kDependsOnOtherSinks.
988 bool only_sinks_with_alpha_depending_on_other_sinks =
989 !sinks_.empty() && alpha_using_sinks_.empty() &&
990 alpha_discarding_sinks_.empty();
991 return !alpha_using_sinks_.empty() ||
992 only_sinks_with_alpha_depending_on_other_sinks;
995 void MediaStreamVideoTrack::SetSinkNotifyFrameDroppedCallback(
996 WebMediaStreamSink* sink,
997 const VideoCaptureNotifyFrameDroppedCB& callback) {
998 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
999 DVLOG(1) << __func__;
1000 frame_deliverer_->SetNotifyFrameDroppedCallback(sink, callback);
1003 void MediaStreamVideoTrack::AddEncodedSink(WebMediaStreamSink* sink,
1004 EncodedVideoFrameCB callback) {
1005 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1006 AddSinkInternal(&encoded_sinks_, sink);
1007 frame_deliverer_->AddEncodedCallback(sink, std::move(callback));
1009 source_->UpdateNumEncodedSinks();
1010 UpdateSourceHasConsumers();
1013 void MediaStreamVideoTrack::RemoveSink(WebMediaStreamSink* sink) {
1014 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1015 RemoveSinkInternal(&sinks_, sink);
1016 alpha_using_sinks_.erase(sink);
1017 alpha_discarding_sinks_.erase(sink);
1018 frame_deliverer_->RemoveCallback(sink);
1019 secure_tracker_.Remove(sink);
1022 UpdateSourceHasConsumers();
1023 source_->UpdateCapturingLinkSecure(this,
1024 secure_tracker_.is_capturing_secure());
1026 source_->UpdateCanDiscardAlpha();
1027 // Restart the timer with existing sinks.
1029 StartTimerForRequestingFrames();
1032 void MediaStreamVideoTrack::RemoveEncodedSink(WebMediaStreamSink* sink) {
1033 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1034 RemoveSinkInternal(&encoded_sinks_, sink);
1035 frame_deliverer_->RemoveEncodedCallback(sink);
1037 source_->UpdateNumEncodedSinks();
1038 UpdateSourceHasConsumers();
1041 void MediaStreamVideoTrack::UpdateSourceHasConsumers() {
1042 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1045 bool has_consumers = !sinks_.empty() || !encoded_sinks_.empty();
1046 source_->UpdateHasConsumers(this, has_consumers);
1049 void MediaStreamVideoTrack::SetEnabled(bool enabled) {
1050 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1051 // If enabled, encoded sinks exist and the source supports encoded output, we
1052 // need a new keyframe from the source as we may have dropped data making the
1053 // stream undecodable.
1054 bool maybe_await_key_frame = false;
1055 if (enabled && source_ && source_->SupportsEncodedOutput() &&
1056 !encoded_sinks_.empty()) {
1057 RequestRefreshFrame();
1058 maybe_await_key_frame = true;
1060 frame_deliverer_->SetEnabled(enabled, maybe_await_key_frame);
1061 for (auto* sink : sinks_)
1062 sink->OnEnabledChanged(enabled);
1063 for (auto* encoded_sink : encoded_sinks_)
1064 encoded_sink->OnEnabledChanged(enabled);
1067 size_t MediaStreamVideoTrack::CountSinks() const {
1068 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1069 return sinks_.size();
1072 size_t MediaStreamVideoTrack::CountEncodedSinks() const {
1073 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1074 return encoded_sinks_.size();
1077 void MediaStreamVideoTrack::SetContentHint(
1078 WebMediaStreamTrack::ContentHintType content_hint) {
1079 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1080 for (auto* sink : sinks_)
1081 sink->OnContentHintChanged(content_hint);
1082 for (auto* encoded_sink : encoded_sinks_)
1083 encoded_sink->OnContentHintChanged(content_hint);
1086 void MediaStreamVideoTrack::StopAndNotify(base::OnceClosure callback) {
1087 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1089 source_->RemoveTrack(this, std::move(callback));
1091 } else if (callback) {
1092 std::move(callback).Run();
1094 OnReadyStateChanged(WebMediaStreamSource::kReadyStateEnded);
1095 refresh_timer_.Stop();
1098 void MediaStreamVideoTrack::GetSettings(
1099 MediaStreamTrackPlatform::Settings& settings) const {
1100 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1104 if (width_ && height_) {
1105 settings.width = width_;
1106 settings.height = height_;
1107 settings.aspect_ratio = static_cast<double>(width_) / height_;
1110 if (absl::optional<media::VideoCaptureFormat> format =
1111 source_->GetCurrentFormat()) {
1112 // For local capture-based tracks, the frame rate returned by
1113 // MediaStreamTrack.getSettings() must be the configured frame rate. In case
1114 // of frame rate decimation, the configured frame rate is the decimated
1115 // frame rate (i.e., the adapter frame rate). If there is no decimation, the
1116 // configured frame rate is the frame rate reported by the device.
1117 // Decimation occurs only when the adapter frame rate is lower than the
1118 // device frame rate.
1119 absl::optional<double> adapter_frame_rate =
1120 adapter_settings_.max_frame_rate();
1121 settings.frame_rate =
1122 (!adapter_frame_rate || *adapter_frame_rate > format->frame_rate)
1123 ? format->frame_rate
1124 : *adapter_frame_rate;
1126 // For other tracks, use the computed frame rate reported via
1127 // SetSizeAndComputedFrameRate().
1128 if (computed_frame_rate_)
1129 settings.frame_rate = *computed_frame_rate_;
1132 settings.facing_mode = ToPlatformFacingMode(
1133 static_cast<mojom::blink::FacingMode>(source_->device().video_facing));
1134 settings.resize_mode = WebString::FromASCII(std::string(
1135 adapter_settings().target_size() ? WebMediaStreamTrack::kResizeModeRescale
1136 : WebMediaStreamTrack::kResizeModeNone));
1137 if (source_->device().display_media_info) {
1138 const auto& info = source_->device().display_media_info;
1139 settings.display_surface = info->display_surface;
1140 settings.logical_surface = info->logical_surface;
1141 settings.cursor = info->cursor;
1145 MediaStreamTrackPlatform::VideoFrameStats
1146 MediaStreamVideoTrack::GetVideoFrameStats() const {
1147 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1148 MediaStreamTrackPlatform::VideoFrameStats stats;
1149 stats.deliverable_frames = frame_deliverer_->deliverable_frames();
1150 stats.discarded_frames = frame_deliverer_->discarded_frames();
1151 stats.dropped_frames = frame_deliverer_->dropped_frames();
1155 MediaStreamTrackPlatform::CaptureHandle
1156 MediaStreamVideoTrack::GetCaptureHandle() {
1157 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1159 MediaStreamTrackPlatform::CaptureHandle capture_handle;
1162 return capture_handle;
1165 const MediaStreamDevice& device = source_->device();
1166 if (!device.display_media_info) {
1167 return capture_handle;
1169 const media::mojom::DisplayMediaInformationPtr& info =
1170 device.display_media_info;
1172 if (!info->capture_handle) {
1173 return capture_handle;
1176 if (!info->capture_handle->origin.opaque()) {
1177 capture_handle.origin =
1178 String::FromUTF8(info->capture_handle->origin.Serialize());
1180 capture_handle.handle =
1181 WebString::FromUTF16(info->capture_handle->capture_handle);
1183 return capture_handle;
1186 void MediaStreamVideoTrack::AddSubCaptureTargetVersionCallback(
1187 uint32_t sub_capture_target_version,
1188 base::OnceClosure callback) {
1189 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1191 frame_deliverer_->AddSubCaptureTargetVersionCallback(
1192 sub_capture_target_version,
1193 base::BindPostTask(base::SingleThreadTaskRunner::GetCurrentDefault(),
1194 std::move(callback)));
1197 void MediaStreamVideoTrack::RemoveSubCaptureTargetVersionCallback(
1198 uint32_t sub_capture_target_version) {
1199 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1201 frame_deliverer_->RemoveSubCaptureTargetVersionCallback(
1202 sub_capture_target_version);
1205 void MediaStreamVideoTrack::OnReadyStateChanged(
1206 WebMediaStreamSource::ReadyState state) {
1207 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1209 // Copy the vectors first, since sinks might DisconnectFromTrack() and
1210 // invalidate iterators.
1212 Vector<WebMediaStreamSink*> sinks_copy(sinks_);
1213 for (auto* sink : sinks_copy)
1214 sink->OnReadyStateChanged(state);
1216 Vector<WebMediaStreamSink*> encoded_sinks_copy(encoded_sinks_);
1217 for (auto* encoded_sink : encoded_sinks_copy)
1218 encoded_sink->OnReadyStateChanged(state);
1221 void MediaStreamVideoTrack::SetMinimumFrameRate(double min_frame_rate) {
1222 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1223 min_frame_rate_ = min_frame_rate;
1226 void MediaStreamVideoTrack::SetTrackAdapterSettings(
1227 const VideoTrackAdapterSettings& settings) {
1228 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1229 adapter_settings_ = settings;
1232 void MediaStreamVideoTrack::NotifyConstraintsConfigurationComplete() {
1233 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1234 for (auto* sink : sinks_) {
1235 sink->OnVideoConstraintsChanged(min_frame_rate_,
1236 adapter_settings_.max_frame_rate());
1239 if (is_screencast_) {
1240 StartTimerForRequestingFrames();
1244 media::VideoCaptureFormat MediaStreamVideoTrack::GetComputedSourceFormat() {
1245 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1246 return computed_source_format_;
1249 void MediaStreamVideoTrack::OnSinkDroppedFrame(
1250 media::VideoCaptureFrameDropReason reason) {
1251 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1255 PostCrossThreadTask(
1256 *source_->video_task_runner(), FROM_HERE,
1257 CrossThreadBindOnce(&FrameDeliverer::LogFrameDroppedOnVideoTaskRunner,
1258 frame_deliverer_, reason));
1261 void MediaStreamVideoTrack::SetEmitLogMessageForTesting(
1262 base::RepeatingCallback<void(const std::string&)> emit_log_message) {
1263 frame_deliverer_->SetEmitLogMessage(std::move(emit_log_message));
1266 void MediaStreamVideoTrack::StartTimerForRequestingFrames() {
1267 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1269 // Find the maximum of all the required min frames per second in the attached
1271 double required_min_fps = 0;
1272 for (auto* web_sink : sinks_) {
1273 auto* sink = static_cast<MediaStreamVideoSink*>(web_sink);
1275 std::max(required_min_fps, sink->GetRequiredMinFramesPerSec());
1278 base::TimeDelta refresh_interval = ComputeRefreshIntervalFromBounds(
1279 base::Hertz(required_min_fps), min_frame_rate(), max_frame_rate());
1281 if (refresh_interval.is_max()) {
1282 refresh_timer_.Stop();
1283 frame_deliverer_->SetIsRefreshingForMinFrameRate(false);
1285 DVLOG(1) << "Starting frame refresh timer with interval "
1286 << refresh_interval.InMillisecondsF() << " ms.";
1287 refresh_timer_.Start(FROM_HERE, refresh_interval, this,
1288 &MediaStreamVideoTrack::RequestRefreshFrame);
1289 frame_deliverer_->SetIsRefreshingForMinFrameRate(true);
1293 void MediaStreamVideoTrack::RequestRefreshFrame() {
1294 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1296 source_->RequestRefreshFrame();
1299 void MediaStreamVideoTrack::ResetRefreshTimer() {
1300 DCHECK_CALLED_ON_VALID_THREAD(main_render_thread_checker_);
1301 if (refresh_timer_.IsRunning())
1302 refresh_timer_.Reset();
1305 } // namespace blink