OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/media/base/videobroadcaster.h" | 11 #include "webrtc/media/base/videobroadcaster.h" |
12 | 12 |
13 #include <limits> | 13 #include <limits> |
14 | 14 |
15 #include "webrtc/base/checks.h" | 15 #include "webrtc/base/checks.h" |
16 | 16 |
17 namespace rtc { | 17 namespace rtc { |
18 | 18 |
19 VideoBroadcaster::VideoBroadcaster() { | 19 VideoBroadcaster::VideoBroadcaster() { |
20 thread_checker_.DetachFromThread(); | 20 thread_checker_.DetachFromThread(); |
21 } | 21 } |
22 | 22 |
23 void VideoBroadcaster::AddOrUpdateSink( | 23 void VideoBroadcaster::AddOrUpdateSink( |
24 VideoSinkInterface<cricket::VideoFrame>* sink, | 24 VideoSinkInterface<cricket::VideoFrame>* sink, |
25 const VideoSinkWants& wants) { | 25 const VideoSinkWants& wants) { |
26 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 26 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
27 RTC_DCHECK(sink != nullptr); | 27 RTC_DCHECK(sink != nullptr); |
28 rtc::CritScope cs(&sinks_and_wants_lock_); | 28 rtc::CritScope cs(&sinks_and_wants_lock_); |
29 | 29 VideoSourceBase::AddOrUpdateSink(sink, wants); |
30 SinkPair* sink_pair = FindSinkPair(sink); | |
31 if (!sink_pair) { | |
32 sinks_.push_back(SinkPair(sink, wants)); | |
33 } else { | |
34 sink_pair->wants = wants; | |
35 } | |
36 UpdateWants(); | 30 UpdateWants(); |
37 } | 31 } |
38 | 32 |
39 void VideoBroadcaster::RemoveSink( | 33 void VideoBroadcaster::RemoveSink( |
40 VideoSinkInterface<cricket::VideoFrame>* sink) { | 34 VideoSinkInterface<cricket::VideoFrame>* sink) { |
41 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 35 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
42 RTC_DCHECK(sink != nullptr); | 36 RTC_DCHECK(sink != nullptr); |
43 rtc::CritScope cs(&sinks_and_wants_lock_); | 37 rtc::CritScope cs(&sinks_and_wants_lock_); |
44 RTC_DCHECK(FindSinkPair(sink)); | 38 VideoSourceBase::RemoveSink(sink); |
45 sinks_.erase(std::remove_if(sinks_.begin(), sinks_.end(), | |
46 [sink](const SinkPair& sink_pair) { | |
47 return sink_pair.sink == sink; | |
48 }), | |
49 sinks_.end()); | |
50 UpdateWants(); | 39 UpdateWants(); |
51 } | 40 } |
52 | 41 |
53 bool VideoBroadcaster::frame_wanted() const { | 42 bool VideoBroadcaster::frame_wanted() const { |
54 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 43 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
55 rtc::CritScope cs(&sinks_and_wants_lock_); | 44 rtc::CritScope cs(&sinks_and_wants_lock_); |
56 return !sinks_.empty(); | 45 return !sink_pairs().empty(); |
57 } | 46 } |
58 | 47 |
59 VideoSinkWants VideoBroadcaster::wants() const { | 48 VideoSinkWants VideoBroadcaster::wants() const { |
60 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 49 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
61 rtc::CritScope cs(&sinks_and_wants_lock_); | 50 rtc::CritScope cs(&sinks_and_wants_lock_); |
62 return current_wants_; | 51 return current_wants_; |
63 } | 52 } |
64 | 53 |
65 void VideoBroadcaster::OnFrame(const cricket::VideoFrame& frame) { | 54 void VideoBroadcaster::OnFrame(const cricket::VideoFrame& frame) { |
66 rtc::CritScope cs(&sinks_and_wants_lock_); | 55 rtc::CritScope cs(&sinks_and_wants_lock_); |
67 for (auto& sink_pair : sinks_) { | 56 for (auto& sink_pair : sink_pairs()) { |
68 sink_pair.sink->OnFrame(frame); | 57 if (sink_pair.wants.black_frames) { |
| 58 sink_pair.sink->OnFrame(GetBlackFrame(frame)); |
| 59 } else { |
| 60 sink_pair.sink->OnFrame(frame); |
| 61 } |
69 } | 62 } |
70 } | 63 } |
71 | 64 |
72 VideoBroadcaster::SinkPair* VideoBroadcaster::FindSinkPair( | |
73 const VideoSinkInterface<cricket::VideoFrame>* sink) { | |
74 auto sink_pair_it = std::find_if( | |
75 sinks_.begin(), sinks_.end(), | |
76 [sink](const SinkPair& sink_pair) { return sink_pair.sink == sink; }); | |
77 if (sink_pair_it != sinks_.end()) { | |
78 return &*sink_pair_it; | |
79 } | |
80 return nullptr; | |
81 } | |
82 | |
83 void VideoBroadcaster::UpdateWants() { | 65 void VideoBroadcaster::UpdateWants() { |
84 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 66 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
85 | 67 |
86 VideoSinkWants wants; | 68 VideoSinkWants wants; |
87 wants.rotation_applied = false; | 69 wants.rotation_applied = false; |
88 for (auto& sink : sinks_) { | 70 for (auto& sink : sink_pairs()) { |
89 // wants.rotation_applied == ANY(sink.wants.rotation_applied) | 71 // wants.rotation_applied == ANY(sink.wants.rotation_applied) |
90 if (sink.wants.rotation_applied) { | 72 if (sink.wants.rotation_applied) { |
91 wants.rotation_applied = true; | 73 wants.rotation_applied = true; |
92 } | 74 } |
93 // wants.max_pixel_count == MIN(sink.wants.max_pixel_count) | 75 // wants.max_pixel_count == MIN(sink.wants.max_pixel_count) |
94 if (sink.wants.max_pixel_count && | 76 if (sink.wants.max_pixel_count && |
95 (!wants.max_pixel_count || | 77 (!wants.max_pixel_count || |
96 (*sink.wants.max_pixel_count < *wants.max_pixel_count))) { | 78 (*sink.wants.max_pixel_count < *wants.max_pixel_count))) { |
97 wants.max_pixel_count = sink.wants.max_pixel_count; | 79 wants.max_pixel_count = sink.wants.max_pixel_count; |
98 } | 80 } |
99 // wants.max_pixel_count_step_up == MIN(sink.wants.max_pixel_count_step_up) | 81 // wants.max_pixel_count_step_up == MIN(sink.wants.max_pixel_count_step_up) |
100 if (sink.wants.max_pixel_count_step_up && | 82 if (sink.wants.max_pixel_count_step_up && |
101 (!wants.max_pixel_count_step_up || | 83 (!wants.max_pixel_count_step_up || |
102 (*sink.wants.max_pixel_count_step_up < | 84 (*sink.wants.max_pixel_count_step_up < |
103 *wants.max_pixel_count_step_up))) { | 85 *wants.max_pixel_count_step_up))) { |
104 wants.max_pixel_count_step_up = sink.wants.max_pixel_count_step_up; | 86 wants.max_pixel_count_step_up = sink.wants.max_pixel_count_step_up; |
105 } | 87 } |
106 } | 88 } |
107 | 89 |
108 if (wants.max_pixel_count && wants.max_pixel_count_step_up && | 90 if (wants.max_pixel_count && wants.max_pixel_count_step_up && |
109 *wants.max_pixel_count_step_up >= *wants.max_pixel_count) { | 91 *wants.max_pixel_count_step_up >= *wants.max_pixel_count) { |
110 wants.max_pixel_count_step_up = Optional<int>(); | 92 wants.max_pixel_count_step_up = Optional<int>(); |
111 } | 93 } |
112 current_wants_ = wants; | 94 current_wants_ = wants; |
113 } | 95 } |
114 | 96 |
| 97 const cricket::VideoFrame& VideoBroadcaster::GetBlackFrame( |
| 98 const cricket::VideoFrame& frame) { |
| 99 if (black_frame_ && black_frame_->GetWidth() == frame.GetWidth() && |
| 100 black_frame_->GetHeight() == frame.GetHeight() && |
| 101 black_frame_->GetVideoRotation() == frame.GetVideoRotation()) { |
| 102 black_frame_->SetTimeStamp(frame.GetTimeStamp()); |
| 103 return *black_frame_; |
| 104 } |
| 105 black_frame_.reset(new cricket::WebRtcVideoFrame( |
| 106 new rtc::RefCountedObject<webrtc::I420Buffer>( |
| 107 static_cast<int>(frame.GetWidth()), |
| 108 static_cast<int>(frame.GetHeight())), |
| 109 frame.GetTimeStamp(), frame.GetVideoRotation())); |
| 110 black_frame_->SetToBlack(); |
| 111 return *black_frame_; |
| 112 } |
| 113 |
115 } // namespace rtc | 114 } // namespace rtc |
OLD | NEW |