Line data Source code
1 : /*
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 :
13 : #include <limits>
14 :
15 : #include "webrtc/api/video/i420_buffer.h"
16 : #include "webrtc/base/checks.h"
17 : #include "webrtc/base/logging.h"
18 :
19 : namespace rtc {
20 :
21 0 : VideoBroadcaster::VideoBroadcaster() {
22 0 : thread_checker_.DetachFromThread();
23 0 : }
24 :
25 0 : void VideoBroadcaster::AddOrUpdateSink(
26 : VideoSinkInterface<webrtc::VideoFrame>* sink,
27 : const VideoSinkWants& wants) {
28 0 : RTC_DCHECK(thread_checker_.CalledOnValidThread());
29 0 : RTC_DCHECK(sink != nullptr);
30 0 : rtc::CritScope cs(&sinks_and_wants_lock_);
31 0 : VideoSourceBase::AddOrUpdateSink(sink, wants);
32 0 : UpdateWants();
33 0 : }
34 :
35 0 : void VideoBroadcaster::RemoveSink(
36 : VideoSinkInterface<webrtc::VideoFrame>* sink) {
37 0 : RTC_DCHECK(thread_checker_.CalledOnValidThread());
38 0 : RTC_DCHECK(sink != nullptr);
39 0 : rtc::CritScope cs(&sinks_and_wants_lock_);
40 0 : VideoSourceBase::RemoveSink(sink);
41 0 : UpdateWants();
42 0 : }
43 :
44 0 : bool VideoBroadcaster::frame_wanted() const {
45 0 : rtc::CritScope cs(&sinks_and_wants_lock_);
46 0 : return !sink_pairs().empty();
47 : }
48 :
49 0 : VideoSinkWants VideoBroadcaster::wants() const {
50 0 : rtc::CritScope cs(&sinks_and_wants_lock_);
51 0 : return current_wants_;
52 : }
53 :
54 0 : void VideoBroadcaster::OnFrame(const webrtc::VideoFrame& frame) {
55 0 : rtc::CritScope cs(&sinks_and_wants_lock_);
56 0 : for (auto& sink_pair : sink_pairs()) {
57 0 : if (sink_pair.wants.rotation_applied &&
58 0 : 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 0 : LOG(LS_VERBOSE) << "Discarding frame with unexpected rotation.";
64 0 : continue;
65 : }
66 0 : if (sink_pair.wants.black_frames) {
67 0 : sink_pair.sink->OnFrame(webrtc::VideoFrame(
68 : GetBlackFrameBuffer(frame.width(), frame.height()), frame.rotation(),
69 0 : frame.timestamp_us()));
70 : } else {
71 0 : sink_pair.sink->OnFrame(frame);
72 : }
73 : }
74 0 : }
75 :
76 0 : void VideoBroadcaster::UpdateWants() {
77 0 : RTC_DCHECK(thread_checker_.CalledOnValidThread());
78 :
79 0 : VideoSinkWants wants;
80 0 : wants.rotation_applied = false;
81 0 : for (auto& sink : sink_pairs()) {
82 : // wants.rotation_applied == ANY(sink.wants.rotation_applied)
83 0 : if (sink.wants.rotation_applied) {
84 0 : wants.rotation_applied = true;
85 : }
86 : // wants.max_pixel_count == MIN(sink.wants.max_pixel_count)
87 0 : if (sink.wants.max_pixel_count &&
88 0 : (!wants.max_pixel_count ||
89 0 : (*sink.wants.max_pixel_count < *wants.max_pixel_count))) {
90 0 : wants.max_pixel_count = sink.wants.max_pixel_count;
91 : }
92 : // wants.max_pixel_count_step_up == MIN(sink.wants.max_pixel_count_step_up)
93 0 : if (sink.wants.max_pixel_count_step_up &&
94 0 : (!wants.max_pixel_count_step_up ||
95 0 : (*sink.wants.max_pixel_count_step_up <
96 0 : *wants.max_pixel_count_step_up))) {
97 0 : wants.max_pixel_count_step_up = sink.wants.max_pixel_count_step_up;
98 : }
99 : }
100 :
101 0 : if (wants.max_pixel_count && wants.max_pixel_count_step_up &&
102 0 : *wants.max_pixel_count_step_up >= *wants.max_pixel_count) {
103 0 : wants.max_pixel_count_step_up = Optional<int>();
104 : }
105 0 : current_wants_ = wants;
106 0 : }
107 :
108 : const rtc::scoped_refptr<webrtc::VideoFrameBuffer>&
109 0 : VideoBroadcaster::GetBlackFrameBuffer(int width, int height) {
110 0 : if (!black_frame_buffer_ || black_frame_buffer_->width() != width ||
111 0 : black_frame_buffer_->height() != height) {
112 : rtc::scoped_refptr<webrtc::I420Buffer> buffer =
113 0 : webrtc::I420Buffer::Create(width, height);
114 0 : webrtc::I420Buffer::SetBlack(buffer.get());
115 0 : black_frame_buffer_ = buffer;
116 : }
117 :
118 0 : return black_frame_buffer_;
119 : }
120 :
121 : } // namespace rtc
|