blob: 8bd65c4fa4c5688bbf6b33a4f7fb6ab77188149a [file] [log] [blame]
Per8e16e612016-02-11 15:56:51 +01001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/media/base/videobroadcaster.h"
12
perkj2d5f0912016-02-29 00:04:41 -080013#include <limits>
14
nisseaf916892017-01-10 07:44:26 -080015#include "webrtc/api/video/i420_buffer.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020016#include "webrtc/rtc_base/checks.h"
17#include "webrtc/rtc_base/logging.h"
Per8e16e612016-02-11 15:56:51 +010018
Pera5092412016-02-12 13:30:57 +010019namespace rtc {
20
21VideoBroadcaster::VideoBroadcaster() {
22 thread_checker_.DetachFromThread();
23}
24
25void VideoBroadcaster::AddOrUpdateSink(
nisseacd935b2016-11-11 03:55:13 -080026 VideoSinkInterface<webrtc::VideoFrame>* sink,
Pera5092412016-02-12 13:30:57 +010027 const VideoSinkWants& wants) {
28 RTC_DCHECK(thread_checker_.CalledOnValidThread());
29 RTC_DCHECK(sink != nullptr);
perkjf0dcfe22016-03-10 18:32:00 +010030 rtc::CritScope cs(&sinks_and_wants_lock_);
perkjd6c39542016-03-17 10:35:23 +010031 VideoSourceBase::AddOrUpdateSink(sink, wants);
perkj2d5f0912016-02-29 00:04:41 -080032 UpdateWants();
Pera5092412016-02-12 13:30:57 +010033}
34
35void VideoBroadcaster::RemoveSink(
nisseacd935b2016-11-11 03:55:13 -080036 VideoSinkInterface<webrtc::VideoFrame>* sink) {
Pera5092412016-02-12 13:30:57 +010037 RTC_DCHECK(thread_checker_.CalledOnValidThread());
38 RTC_DCHECK(sink != nullptr);
perkjf0dcfe22016-03-10 18:32:00 +010039 rtc::CritScope cs(&sinks_and_wants_lock_);
perkjd6c39542016-03-17 10:35:23 +010040 VideoSourceBase::RemoveSink(sink);
perkj2d5f0912016-02-29 00:04:41 -080041 UpdateWants();
Pera5092412016-02-12 13:30:57 +010042}
43
44bool VideoBroadcaster::frame_wanted() const {
perkjf0dcfe22016-03-10 18:32:00 +010045 rtc::CritScope cs(&sinks_and_wants_lock_);
perkjd6c39542016-03-17 10:35:23 +010046 return !sink_pairs().empty();
Pera5092412016-02-12 13:30:57 +010047}
48
49VideoSinkWants VideoBroadcaster::wants() const {
perkjf0dcfe22016-03-10 18:32:00 +010050 rtc::CritScope cs(&sinks_and_wants_lock_);
Pera5092412016-02-12 13:30:57 +010051 return current_wants_;
52}
53
nisseacd935b2016-11-11 03:55:13 -080054void VideoBroadcaster::OnFrame(const webrtc::VideoFrame& frame) {
perkjf0dcfe22016-03-10 18:32:00 +010055 rtc::CritScope cs(&sinks_and_wants_lock_);
perkjd6c39542016-03-17 10:35:23 +010056 for (auto& sink_pair : sink_pairs()) {
nisse6f5a6c32016-09-22 01:25:59 -070057 if (sink_pair.wants.rotation_applied &&
58 frame.rotation() != webrtc::kVideoRotation_0) {
59 // Calls to OnFrame are not synchronized with changes to the sink wants.
60 // When rotation_applied is set to true, one or a few frames may get here
61 // with rotation still pending. Protect sinks that don't expect any
62 // pending rotation.
63 LOG(LS_VERBOSE) << "Discarding frame with unexpected rotation.";
64 continue;
65 }
perkjd6c39542016-03-17 10:35:23 +010066 if (sink_pair.wants.black_frames) {
nisseacd935b2016-11-11 03:55:13 -080067 sink_pair.sink->OnFrame(webrtc::VideoFrame(
Sergey Ulanov19ee1e6eb2016-08-01 13:35:55 -070068 GetBlackFrameBuffer(frame.width(), frame.height()), frame.rotation(),
nisse09347852016-10-19 00:30:30 -070069 frame.timestamp_us()));
perkjd6c39542016-03-17 10:35:23 +010070 } else {
71 sink_pair.sink->OnFrame(frame);
72 }
Pera5092412016-02-12 13:30:57 +010073 }
74}
75
perkj2d5f0912016-02-29 00:04:41 -080076void VideoBroadcaster::UpdateWants() {
77 RTC_DCHECK(thread_checker_.CalledOnValidThread());
78
79 VideoSinkWants wants;
80 wants.rotation_applied = false;
perkjd6c39542016-03-17 10:35:23 +010081 for (auto& sink : sink_pairs()) {
perkj2d5f0912016-02-29 00:04:41 -080082 // wants.rotation_applied == ANY(sink.wants.rotation_applied)
83 if (sink.wants.rotation_applied) {
84 wants.rotation_applied = true;
85 }
86 // wants.max_pixel_count == MIN(sink.wants.max_pixel_count)
sprangc5d62e22017-04-02 23:53:04 -070087 if (sink.wants.max_pixel_count < wants.max_pixel_count) {
perkj2d5f0912016-02-29 00:04:41 -080088 wants.max_pixel_count = sink.wants.max_pixel_count;
89 }
sprang84a37592017-02-10 07:04:27 -080090 // Select the minimum requested target_pixel_count, if any, of all sinks so
91 // that we don't over utilize the resources for any one.
92 // TODO(sprang): Consider using the median instead, since the limit can be
93 // expressed by max_pixel_count.
94 if (sink.wants.target_pixel_count &&
95 (!wants.target_pixel_count ||
96 (*sink.wants.target_pixel_count < *wants.target_pixel_count))) {
97 wants.target_pixel_count = sink.wants.target_pixel_count;
perkj2d5f0912016-02-29 00:04:41 -080098 }
sprangc5d62e22017-04-02 23:53:04 -070099 // Select the minimum for the requested max framerates.
100 if (sink.wants.max_framerate_fps < wants.max_framerate_fps) {
101 wants.max_framerate_fps = sink.wants.max_framerate_fps;
102 }
perkj2d5f0912016-02-29 00:04:41 -0800103 }
104
sprangc5d62e22017-04-02 23:53:04 -0700105 if (wants.target_pixel_count &&
106 *wants.target_pixel_count >= wants.max_pixel_count) {
107 wants.target_pixel_count.emplace(wants.max_pixel_count);
perkj2d5f0912016-02-29 00:04:41 -0800108 }
109 current_wants_ = wants;
110}
111
nisseefec5902016-06-09 00:31:39 -0700112const rtc::scoped_refptr<webrtc::VideoFrameBuffer>&
113VideoBroadcaster::GetBlackFrameBuffer(int width, int height) {
114 if (!black_frame_buffer_ || black_frame_buffer_->width() != width ||
115 black_frame_buffer_->height() != height) {
116 rtc::scoped_refptr<webrtc::I420Buffer> buffer =
nisseaf916892017-01-10 07:44:26 -0800117 webrtc::I420Buffer::Create(width, height);
118 webrtc::I420Buffer::SetBlack(buffer.get());
nisseefec5902016-06-09 00:31:39 -0700119 black_frame_buffer_ = buffer;
perkjd6c39542016-03-17 10:35:23 +0100120 }
nisseefec5902016-06-09 00:31:39 -0700121
122 return black_frame_buffer_;
perkjd6c39542016-03-17 10:35:23 +0100123}
124
Pera5092412016-02-12 13:30:57 +0100125} // namespace rtc