OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "remoting/host/cast_video_capturer_adapter.h" | |
6 | |
7 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | |
8 | |
9 namespace remoting { | |
10 | |
11 // Number of frames to be captured per second. | |
12 const int kFramesPerSec = 10; | |
13 | |
14 CastVideoCapturerAdapter::CastVideoCapturerAdapter( | |
15 scoped_ptr<webrtc::DesktopCapturer> capturer) | |
16 : desktop_capturer_(capturer.Pass()) { | |
17 DCHECK(desktop_capturer_); | |
18 | |
19 thread_checker_.DetachFromThread(); | |
20 | |
21 // Disable video adaptation since we don't intend to use it. | |
22 set_enable_video_adapter(false); | |
23 } | |
24 | |
25 CastVideoCapturerAdapter::~CastVideoCapturerAdapter() { | |
26 DCHECK(!capture_timer_); | |
27 } | |
28 | |
29 webrtc::SharedMemory* CastVideoCapturerAdapter::CreateSharedMemory( | |
30 size_t size) { | |
31 return nullptr; | |
32 } | |
33 | |
34 void CastVideoCapturerAdapter::OnCaptureCompleted(webrtc::DesktopFrame* frame) { | |
35 scoped_ptr<webrtc::DesktopFrame> owned_frame(frame); | |
36 | |
37 // Drop the owned_frame if there were no changes. | |
38 if (!owned_frame || owned_frame->updated_region().is_empty()) { | |
39 owned_frame.reset(); | |
40 return; | |
41 } | |
42 | |
43 // Convert the webrtc::DesktopFrame to a cricket::CapturedFrame. | |
44 cricket::CapturedFrame captured_frame; | |
45 captured_frame.width = owned_frame->size().width(); | |
46 captured_frame.height = owned_frame->size().height(); | |
47 base::TimeTicks current_time = base::TimeTicks::Now(); | |
48 captured_frame.time_stamp = | |
49 current_time.ToInternalValue() * base::Time::kNanosecondsPerMicrosecond; | |
50 captured_frame.data = owned_frame->data(); | |
51 | |
52 // The data_size attribute must be set. If multiple formats are supported, | |
53 // this should be set appropriately for each one. | |
54 captured_frame.data_size = | |
55 (captured_frame.width * webrtc::DesktopFrame::kBytesPerPixel * 8 + 7) / | |
56 8 * captured_frame.height; | |
57 captured_frame.fourcc = cricket::FOURCC_ARGB; | |
58 | |
59 SignalFrameCaptured(this, &captured_frame); | |
60 } | |
61 | |
62 bool CastVideoCapturerAdapter::GetBestCaptureFormat( | |
63 const cricket::VideoFormat& desired, | |
64 cricket::VideoFormat* best_format) { | |
65 DCHECK(thread_checker_.CalledOnValidThread()); | |
66 | |
67 // For now, just used the desired width and height. | |
68 best_format->width = desired.width; | |
69 best_format->height = desired.height; | |
70 best_format->fourcc = cricket::FOURCC_ARGB; | |
71 best_format->interval = FPS_TO_INTERVAL(kFramesPerSec); | |
72 return true; | |
73 } | |
74 | |
75 cricket::CaptureState CastVideoCapturerAdapter::Start( | |
76 const cricket::VideoFormat& capture_format) { | |
77 DCHECK(thread_checker_.CalledOnValidThread()); | |
78 DCHECK(!capture_timer_); | |
79 DCHECK_EQ(capture_format.fourcc, (static_cast<uint32>(cricket::FOURCC_ARGB))); | |
80 | |
81 if (!desktop_capturer_) { | |
82 VLOG(1) << "CastVideoCapturerAdapter failed to start."; | |
83 return cricket::CS_FAILED; | |
84 } | |
85 | |
86 // This is required to tell the cricket::VideoCapturer base class what the | |
87 // capture format will be. | |
88 SetCaptureFormat(&capture_format); | |
89 | |
90 desktop_capturer_->Start(this); | |
91 | |
92 capture_timer_.reset(new base::RepeatingTimer()); | |
93 capture_timer_->Start(FROM_HERE, | |
94 base::TimeDelta::FromMicroseconds( | |
95 GetCaptureFormat()->interval / | |
96 (base::Time::kNanosecondsPerMicrosecond)), | |
97 this, | |
98 &CastVideoCapturerAdapter::CaptureNextFrame); | |
99 | |
100 return cricket::CS_RUNNING; | |
101 } | |
102 | |
103 // Similar to the base class implementation with some important differences: | |
104 // 1. Does not call either Stop() or Start(), as those would affect the state of | |
105 // |desktop_capturer_|. | |
106 // 2. Does not support unpausing after stopping the capturer. It is unclear | |
107 // if that flow needs to be supported. | |
108 bool CastVideoCapturerAdapter::Pause(bool pause) { | |
109 DCHECK(thread_checker_.CalledOnValidThread()); | |
110 | |
111 if (pause) { | |
112 if (capture_state() == cricket::CS_PAUSED) | |
113 return true; | |
114 | |
115 bool running = capture_state() == cricket::CS_STARTING || | |
116 capture_state() == cricket::CS_RUNNING; | |
117 | |
118 DCHECK_EQ(running, IsRunning()); | |
119 | |
120 if (!running) { | |
121 LOG(ERROR) | |
122 << "Cannot pause CastVideoCapturerAdapter."; | |
123 return false; | |
124 } | |
125 | |
126 // Stop |capture_timer_| and set capture state to cricket::CS_PAUSED. | |
127 capture_timer_->Stop(); | |
128 SetCaptureState(cricket::CS_PAUSED); | |
129 | |
130 VLOG(1) << "CastVideoCapturerAdapter paused."; | |
131 | |
132 return true; | |
133 } else { // Unpausing. | |
134 if (capture_state() != cricket::CS_PAUSED || !GetCaptureFormat() || | |
135 !capture_timer_) { | |
136 LOG(ERROR) << "Cannot unpause CastVideoCapturerAdapter."; | |
137 return false; | |
138 } | |
139 | |
140 // Restart |capture_timer_| and set capture state to cricket::CS_RUNNING; | |
141 capture_timer_->Start(FROM_HERE, | |
142 base::TimeDelta::FromMicroseconds( | |
143 GetCaptureFormat()->interval / | |
144 (base::Time::kNanosecondsPerMicrosecond)), | |
145 this, | |
146 &CastVideoCapturerAdapter::CaptureNextFrame); | |
147 SetCaptureState(cricket::CS_RUNNING); | |
148 | |
149 VLOG(1) << "CastVideoCapturerAdapter unpaused."; | |
150 } | |
151 return true; | |
152 } | |
153 | |
154 void CastVideoCapturerAdapter::Stop() { | |
155 DCHECK(thread_checker_.CalledOnValidThread()); | |
156 DCHECK_NE(capture_state(), cricket::CS_STOPPED); | |
157 | |
158 capture_timer_.reset(); | |
159 | |
160 SetCaptureFormat(nullptr); | |
161 SetCaptureState(cricket::CS_STOPPED); | |
162 | |
163 VLOG(1) << "CastVideoCapturerAdapter stopped."; | |
164 } | |
165 | |
166 | |
167 bool CastVideoCapturerAdapter::IsRunning() { | |
168 DCHECK(thread_checker_.CalledOnValidThread()); | |
169 | |
170 return capture_timer_->IsRunning(); | |
171 } | |
172 | |
173 bool CastVideoCapturerAdapter::IsScreencast() const { | |
174 return true; | |
175 } | |
176 | |
177 bool CastVideoCapturerAdapter::GetPreferredFourccs( | |
178 std::vector<uint32>* fourccs) { | |
179 DCHECK(thread_checker_.CalledOnValidThread()); | |
180 if (!fourccs) | |
181 return false; | |
182 fourccs->push_back(cricket::FOURCC_ARGB); | |
183 return true; | |
184 } | |
185 | |
186 void CastVideoCapturerAdapter::CaptureNextFrame() { | |
187 // If we are paused, then don't capture. | |
188 if (!IsRunning()) | |
189 return; | |
190 | |
191 desktop_capturer_->Capture(webrtc::DesktopRegion()); | |
192 } | |
193 | |
194 } // namespace remoting | |
195 | |
OLD | NEW |