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 "content/renderer/media/media_stream_video_capturer_source.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/location.h"
10 #include "content/renderer/media/video_capture_impl_manager.h"
11 #include "content/renderer/render_thread_impl.h"
12 #include "media/base/bind_to_current_loop.h"
13 #include "media/base/video_frame.h"
14
15 namespace {
16
17 struct SourceVideoResolution {
18 int width;
19 int height;
20 };
21
22 // Resolutions used if the source doesn't support capability enumeration.
23 const SourceVideoResolution kVideoResolutions[] = {{1920, 1080},
24 {1280, 720},
25 {960, 720},
26 {640, 480},
27 {640, 360},
28 {320, 240},
29 {320, 180}};
30 // Frame rates for sources with no support for capability enumeration.
31 const int kVideoFrameRates[] = {30, 60};
32
33 } // namespace
34
35 namespace content {
36
VideoCapturerDelegate(const StreamDeviceInfo & device_info)37 VideoCapturerDelegate::VideoCapturerDelegate(
38 const StreamDeviceInfo& device_info)
39 : session_id_(device_info.session_id),
40 is_screen_cast_(device_info.device.type == MEDIA_TAB_VIDEO_CAPTURE ||
41 device_info.device.type == MEDIA_DESKTOP_VIDEO_CAPTURE),
42 got_first_frame_(false) {
43 DVLOG(3) << "VideoCapturerDelegate::ctor";
44
45 // NULL in unit test.
46 if (RenderThreadImpl::current()) {
47 VideoCaptureImplManager* manager =
48 RenderThreadImpl::current()->video_capture_impl_manager();
49 if (manager)
50 release_device_cb_ = manager->UseDevice(session_id_);
51 }
52 }
53
~VideoCapturerDelegate()54 VideoCapturerDelegate::~VideoCapturerDelegate() {
55 DVLOG(3) << "VideoCapturerDelegate::dtor";
56 if (!release_device_cb_.is_null())
57 release_device_cb_.Run();
58 }
59
GetCurrentSupportedFormats(int max_requested_width,int max_requested_height,const VideoCaptureDeviceFormatsCB & callback)60 void VideoCapturerDelegate::GetCurrentSupportedFormats(
61 int max_requested_width,
62 int max_requested_height,
63 const VideoCaptureDeviceFormatsCB& callback) {
64 DVLOG(3) << "GetCurrentSupportedFormats("
65 << " { max_requested_height = " << max_requested_height << "})"
66 << " { max_requested_width = " << max_requested_width << "})";
67
68 if (is_screen_cast_) {
69 media::VideoCaptureFormats formats;
70 const int width = max_requested_width ?
71 max_requested_width : MediaStreamVideoSource::kDefaultWidth;
72 const int height = max_requested_height ?
73 max_requested_height : MediaStreamVideoSource::kDefaultHeight;
74 formats.push_back(
75 media::VideoCaptureFormat(
76 gfx::Size(width, height),
77 MediaStreamVideoSource::kDefaultFrameRate,
78 media::PIXEL_FORMAT_I420));
79 callback.Run(formats);
80 return;
81 }
82
83 // NULL in unit test.
84 if (!RenderThreadImpl::current())
85 return;
86 VideoCaptureImplManager* manager =
87 RenderThreadImpl::current()->video_capture_impl_manager();
88 if (!manager)
89 return;
90 DCHECK(source_formats_callback_.is_null());
91 source_formats_callback_ = callback;
92 manager->GetDeviceFormatsInUse(
93 session_id_,
94 media::BindToCurrentLoop(
95 base::Bind(
96 &VideoCapturerDelegate::OnDeviceFormatsInUseReceived, this)));
97 }
98
StartCapture(const media::VideoCaptureParams & params,const VideoCaptureDeliverFrameCB & new_frame_callback,const RunningCallback & running_callback)99 void VideoCapturerDelegate::StartCapture(
100 const media::VideoCaptureParams& params,
101 const VideoCaptureDeliverFrameCB& new_frame_callback,
102 const RunningCallback& running_callback) {
103 DCHECK(params.requested_format.IsValid());
104 DCHECK(thread_checker_.CalledOnValidThread());
105 running_callback_ = running_callback;
106 got_first_frame_ = false;
107
108 // NULL in unit test.
109 if (!RenderThreadImpl::current())
110 return;
111 VideoCaptureImplManager* manager =
112 RenderThreadImpl::current()->video_capture_impl_manager();
113 if (!manager)
114 return;
115 stop_capture_cb_ =
116 manager->StartCapture(
117 session_id_,
118 params,
119 media::BindToCurrentLoop(base::Bind(
120 &VideoCapturerDelegate::OnStateUpdateOnRenderThread, this)),
121 new_frame_callback);
122 }
123
StopCapture()124 void VideoCapturerDelegate::StopCapture() {
125 // Immediately make sure we don't provide more frames.
126 DVLOG(3) << "VideoCapturerDelegate::StopCapture()";
127 DCHECK(thread_checker_.CalledOnValidThread());
128 if (!stop_capture_cb_.is_null()) {
129 base::ResetAndReturn(&stop_capture_cb_).Run();
130 }
131 running_callback_.Reset();
132 source_formats_callback_.Reset();
133 }
134
OnStateUpdateOnRenderThread(VideoCaptureState state)135 void VideoCapturerDelegate::OnStateUpdateOnRenderThread(
136 VideoCaptureState state) {
137 DCHECK(thread_checker_.CalledOnValidThread());
138 DVLOG(3) << "OnStateUpdateOnRenderThread state = " << state;
139 if (state == VIDEO_CAPTURE_STATE_STARTED && !running_callback_.is_null()) {
140 running_callback_.Run(true);
141 return;
142 }
143 if (state > VIDEO_CAPTURE_STATE_STARTED && !running_callback_.is_null()) {
144 base::ResetAndReturn(&running_callback_).Run(false);
145 }
146 }
147
OnDeviceFormatsInUseReceived(const media::VideoCaptureFormats & formats_in_use)148 void VideoCapturerDelegate::OnDeviceFormatsInUseReceived(
149 const media::VideoCaptureFormats& formats_in_use) {
150 DVLOG(3) << "OnDeviceFormatsInUseReceived: " << formats_in_use.size();
151 DCHECK(thread_checker_.CalledOnValidThread());
152 // StopCapture() might have destroyed |source_formats_callback_| before
153 // arriving here.
154 if (source_formats_callback_.is_null())
155 return;
156 // If there are no formats in use, try to retrieve the whole list of
157 // supported form.
158 if (!formats_in_use.empty()) {
159 source_formats_callback_.Run(formats_in_use);
160 source_formats_callback_.Reset();
161 return;
162 }
163
164 // NULL in unit test.
165 if (!RenderThreadImpl::current())
166 return;
167 VideoCaptureImplManager* manager =
168 RenderThreadImpl::current()->video_capture_impl_manager();
169 if (!manager)
170 return;
171 manager->GetDeviceSupportedFormats(
172 session_id_,
173 media::BindToCurrentLoop(
174 base::Bind(
175 &VideoCapturerDelegate::OnDeviceSupportedFormatsEnumerated,
176 this)));
177 }
178
OnDeviceSupportedFormatsEnumerated(const media::VideoCaptureFormats & formats)179 void VideoCapturerDelegate::OnDeviceSupportedFormatsEnumerated(
180 const media::VideoCaptureFormats& formats) {
181 DVLOG(3) << "OnDeviceSupportedFormatsEnumerated: " << formats.size()
182 << " received";
183 DCHECK(thread_checker_.CalledOnValidThread());
184 // StopCapture() might have destroyed |source_formats_callback_| before
185 // arriving here.
186 if (source_formats_callback_.is_null())
187 return;
188 if (formats.size()) {
189 source_formats_callback_.Run(formats);
190 } else {
191 // The capture device doesn't seem to support capability enumeration,
192 // compose a fallback list of capabilities.
193 media::VideoCaptureFormats default_formats;
194 for (size_t i = 0; i < arraysize(kVideoResolutions); ++i) {
195 for (size_t j = 0; j < arraysize(kVideoFrameRates); ++j) {
196 default_formats.push_back(media::VideoCaptureFormat(
197 gfx::Size(kVideoResolutions[i].width, kVideoResolutions[i].height),
198 kVideoFrameRates[j], media::PIXEL_FORMAT_I420));
199 }
200 }
201 source_formats_callback_.Run(default_formats);
202 }
203 source_formats_callback_.Reset();
204 }
205
MediaStreamVideoCapturerSource(const StreamDeviceInfo & device_info,const SourceStoppedCallback & stop_callback,const scoped_refptr<VideoCapturerDelegate> & delegate)206 MediaStreamVideoCapturerSource::MediaStreamVideoCapturerSource(
207 const StreamDeviceInfo& device_info,
208 const SourceStoppedCallback& stop_callback,
209 const scoped_refptr<VideoCapturerDelegate>& delegate)
210 : delegate_(delegate) {
211 SetDeviceInfo(device_info);
212 SetStopCallback(stop_callback);
213 }
214
~MediaStreamVideoCapturerSource()215 MediaStreamVideoCapturerSource::~MediaStreamVideoCapturerSource() {
216 }
217
GetCurrentSupportedFormats(int max_requested_width,int max_requested_height,const VideoCaptureDeviceFormatsCB & callback)218 void MediaStreamVideoCapturerSource::GetCurrentSupportedFormats(
219 int max_requested_width,
220 int max_requested_height,
221 const VideoCaptureDeviceFormatsCB& callback) {
222 delegate_->GetCurrentSupportedFormats(
223 max_requested_width,
224 max_requested_height,
225 callback);
226 }
227
StartSourceImpl(const media::VideoCaptureParams & params,const VideoCaptureDeliverFrameCB & frame_callback)228 void MediaStreamVideoCapturerSource::StartSourceImpl(
229 const media::VideoCaptureParams& params,
230 const VideoCaptureDeliverFrameCB& frame_callback) {
231 media::VideoCaptureParams new_params(params);
232 if (device_info().device.type == MEDIA_TAB_VIDEO_CAPTURE ||
233 device_info().device.type == MEDIA_DESKTOP_VIDEO_CAPTURE) {
234 new_params.allow_resolution_change = true;
235 }
236 delegate_->StartCapture(
237 new_params,
238 frame_callback,
239 base::Bind(&MediaStreamVideoCapturerSource::OnStartDone,
240 base::Unretained(this)));
241 }
242
StopSourceImpl()243 void MediaStreamVideoCapturerSource::StopSourceImpl() {
244 delegate_->StopCapture();
245 }
246
247 } // namespace content
248