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.
5 #include "content/renderer/media/media_stream_video_capturer_source.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"
17 struct SourceVideoResolution
{
22 // Resolutions used if the source doesn't support capability enumeration.
23 const SourceVideoResolution kVideoResolutions
[] = {{1920, 1080},
30 // Frame rates for sources with no support for capability enumeration.
31 const int kVideoFrameRates
[] = {30, 60};
33 // Hard upper-bound frame rate for tab/desktop capture.
34 const double kMaxScreenCastFrameRate
= 120.0;
40 VideoCapturerDelegate::VideoCapturerDelegate(
41 const StreamDeviceInfo
& device_info
)
42 : session_id_(device_info
.session_id
),
43 is_screen_cast_(device_info
.device
.type
== MEDIA_TAB_VIDEO_CAPTURE
||
44 device_info
.device
.type
== MEDIA_DESKTOP_VIDEO_CAPTURE
),
46 DVLOG(3) << "VideoCapturerDelegate::ctor";
49 if (RenderThreadImpl::current()) {
50 VideoCaptureImplManager
* manager
=
51 RenderThreadImpl::current()->video_capture_impl_manager();
53 release_device_cb_
= manager
->UseDevice(session_id_
);
57 VideoCapturerDelegate::~VideoCapturerDelegate() {
58 DCHECK(thread_checker_
.CalledOnValidThread());
59 DVLOG(3) << "VideoCapturerDelegate::dtor";
60 if (!release_device_cb_
.is_null())
61 release_device_cb_
.Run();
64 void VideoCapturerDelegate::GetCurrentSupportedFormats(
65 int max_requested_width
,
66 int max_requested_height
,
67 double max_requested_frame_rate
,
68 const VideoCaptureDeviceFormatsCB
& callback
) {
70 << "GetCurrentSupportedFormats("
71 << " { max_requested_height = " << max_requested_height
<< "})"
72 << " { max_requested_width = " << max_requested_width
<< "})"
73 << " { max_requested_frame_rate = " << max_requested_frame_rate
<< "})";
75 if (is_screen_cast_
) {
76 const int width
= max_requested_width
?
77 max_requested_width
: MediaStreamVideoSource::kDefaultWidth
;
78 const int height
= max_requested_height
?
79 max_requested_height
: MediaStreamVideoSource::kDefaultHeight
;
80 callback
.Run(media::VideoCaptureFormats(1, media::VideoCaptureFormat(
81 gfx::Size(width
, height
),
82 static_cast<float>(std::min(kMaxScreenCastFrameRate
,
83 max_requested_frame_rate
)),
84 media::PIXEL_FORMAT_I420
)));
89 if (!RenderThreadImpl::current())
91 VideoCaptureImplManager
* manager
=
92 RenderThreadImpl::current()->video_capture_impl_manager();
95 DCHECK(source_formats_callback_
.is_null());
96 source_formats_callback_
= callback
;
97 manager
->GetDeviceFormatsInUse(
99 media::BindToCurrentLoop(
101 &VideoCapturerDelegate::OnDeviceFormatsInUseReceived
,
102 weak_factory_
.GetWeakPtr())));
105 void VideoCapturerDelegate::StartCapture(
106 const media::VideoCaptureParams
& params
,
107 const VideoCaptureDeliverFrameCB
& new_frame_callback
,
108 scoped_refptr
<base::SingleThreadTaskRunner
> frame_callback_task_runner
,
109 const RunningCallback
& running_callback
) {
110 DCHECK(params
.requested_format
.IsValid());
111 DCHECK(thread_checker_
.CalledOnValidThread());
112 running_callback_
= running_callback
;
114 // NULL in unit test.
115 if (!RenderThreadImpl::current())
117 VideoCaptureImplManager
* manager
=
118 RenderThreadImpl::current()->video_capture_impl_manager();
121 if (frame_callback_task_runner
!=
122 RenderThreadImpl::current()->GetIOMessageLoopProxy()) {
123 DCHECK(false) << "Only IO thread supported right now.";
124 running_callback
.Run(false);
129 manager
->StartCapture(
132 media::BindToCurrentLoop(base::Bind(
133 &VideoCapturerDelegate::OnStateUpdateOnRenderThread
,
134 weak_factory_
.GetWeakPtr())),
138 void VideoCapturerDelegate::StopCapture() {
139 // Immediately make sure we don't provide more frames.
140 DVLOG(3) << "VideoCapturerDelegate::StopCapture()";
141 DCHECK(thread_checker_
.CalledOnValidThread());
142 if (!stop_capture_cb_
.is_null()) {
143 base::ResetAndReturn(&stop_capture_cb_
).Run();
145 running_callback_
.Reset();
146 source_formats_callback_
.Reset();
149 void VideoCapturerDelegate::OnStateUpdateOnRenderThread(
150 VideoCaptureState state
) {
151 DCHECK(thread_checker_
.CalledOnValidThread());
152 DVLOG(3) << "OnStateUpdateOnRenderThread state = " << state
;
153 if (state
== VIDEO_CAPTURE_STATE_STARTED
&& !running_callback_
.is_null()) {
154 running_callback_
.Run(true);
157 if (state
> VIDEO_CAPTURE_STATE_STARTED
&& !running_callback_
.is_null()) {
158 base::ResetAndReturn(&running_callback_
).Run(false);
162 void VideoCapturerDelegate::OnDeviceFormatsInUseReceived(
163 const media::VideoCaptureFormats
& formats_in_use
) {
164 DVLOG(3) << "OnDeviceFormatsInUseReceived: " << formats_in_use
.size();
165 DCHECK(thread_checker_
.CalledOnValidThread());
166 // StopCapture() might have destroyed |source_formats_callback_| before
168 if (source_formats_callback_
.is_null())
170 // If there are no formats in use, try to retrieve the whole list of
172 if (!formats_in_use
.empty()) {
173 source_formats_callback_
.Run(formats_in_use
);
174 source_formats_callback_
.Reset();
178 // NULL in unit test.
179 if (!RenderThreadImpl::current())
181 VideoCaptureImplManager
* manager
=
182 RenderThreadImpl::current()->video_capture_impl_manager();
186 manager
->GetDeviceSupportedFormats(
188 media::BindToCurrentLoop(
190 &VideoCapturerDelegate::OnDeviceSupportedFormatsEnumerated
,
191 weak_factory_
.GetWeakPtr())));
194 void VideoCapturerDelegate::OnDeviceSupportedFormatsEnumerated(
195 const media::VideoCaptureFormats
& formats
) {
196 DVLOG(3) << "OnDeviceSupportedFormatsEnumerated: " << formats
.size()
198 DCHECK(thread_checker_
.CalledOnValidThread());
199 // StopCapture() might have destroyed |source_formats_callback_| before
201 if (source_formats_callback_
.is_null())
203 if (formats
.size()) {
204 base::ResetAndReturn(&source_formats_callback_
).Run(formats
);
206 // The capture device doesn't seem to support capability enumeration,
207 // compose a fallback list of capabilities.
208 media::VideoCaptureFormats default_formats
;
209 for (size_t i
= 0; i
< arraysize(kVideoResolutions
); ++i
) {
210 for (size_t j
= 0; j
< arraysize(kVideoFrameRates
); ++j
) {
211 default_formats
.push_back(media::VideoCaptureFormat(
212 gfx::Size(kVideoResolutions
[i
].width
, kVideoResolutions
[i
].height
),
213 kVideoFrameRates
[j
], media::PIXEL_FORMAT_I420
));
216 base::ResetAndReturn(&source_formats_callback_
).Run(default_formats
);
220 MediaStreamVideoCapturerSource::MediaStreamVideoCapturerSource(
221 const SourceStoppedCallback
& stop_callback
,
222 scoped_ptr
<media::VideoCapturerSource
> delegate
)
223 : delegate_(delegate
.Pass()) {
224 SetStopCallback(stop_callback
);
227 void MediaStreamVideoCapturerSource::SetDeviceInfo(
228 const StreamDeviceInfo
& device_info
) {
229 MediaStreamVideoSource::SetDeviceInfo(device_info
);
232 MediaStreamVideoCapturerSource::~MediaStreamVideoCapturerSource() {
235 void MediaStreamVideoCapturerSource::GetCurrentSupportedFormats(
236 int max_requested_width
,
237 int max_requested_height
,
238 double max_requested_frame_rate
,
239 const VideoCaptureDeviceFormatsCB
& callback
) {
240 delegate_
->GetCurrentSupportedFormats(
242 max_requested_height
,
243 max_requested_frame_rate
,
247 void MediaStreamVideoCapturerSource::StartSourceImpl(
248 const media::VideoCaptureFormat
& format
,
249 const VideoCaptureDeliverFrameCB
& frame_callback
) {
250 media::VideoCaptureParams new_params
;
251 new_params
.requested_format
= format
;
252 if (device_info().device
.type
== MEDIA_TAB_VIDEO_CAPTURE
||
253 device_info().device
.type
== MEDIA_DESKTOP_VIDEO_CAPTURE
) {
254 new_params
.resolution_change_policy
=
255 media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT
;
257 delegate_
->StartCapture(
260 RenderThreadImpl::current() ?
261 RenderThreadImpl::current()->GetIOMessageLoopProxy() :
263 base::Bind(&MediaStreamVideoCapturerSource::OnStarted
,
264 base::Unretained(this)));
267 void MediaStreamVideoCapturerSource::OnStarted(bool result
) {
268 OnStartDone(result
? MEDIA_DEVICE_OK
: MEDIA_DEVICE_TRACK_START_FAILURE
);
271 void MediaStreamVideoCapturerSource::StopSourceImpl() {
272 delegate_
->StopCapture();
275 } // namespace content