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
) {
45 DVLOG(3) << "VideoCapturerDelegate::ctor";
48 if (RenderThreadImpl::current()) {
49 VideoCaptureImplManager
* manager
=
50 RenderThreadImpl::current()->video_capture_impl_manager();
52 release_device_cb_
= manager
->UseDevice(session_id_
);
56 VideoCapturerDelegate::~VideoCapturerDelegate() {
57 DVLOG(3) << "VideoCapturerDelegate::dtor";
58 if (!release_device_cb_
.is_null())
59 release_device_cb_
.Run();
62 void VideoCapturerDelegate::GetCurrentSupportedFormats(
63 int max_requested_width
,
64 int max_requested_height
,
65 double max_requested_frame_rate
,
66 const VideoCaptureDeviceFormatsCB
& callback
) {
68 << "GetCurrentSupportedFormats("
69 << " { max_requested_height = " << max_requested_height
<< "})"
70 << " { max_requested_width = " << max_requested_width
<< "})"
71 << " { max_requested_frame_rate = " << max_requested_frame_rate
<< "})";
73 if (is_screen_cast_
) {
74 const int width
= max_requested_width
?
75 max_requested_width
: MediaStreamVideoSource::kDefaultWidth
;
76 const int height
= max_requested_height
?
77 max_requested_height
: MediaStreamVideoSource::kDefaultHeight
;
78 callback
.Run(media::VideoCaptureFormats(1, media::VideoCaptureFormat(
79 gfx::Size(width
, height
),
80 static_cast<float>(std::min(kMaxScreenCastFrameRate
,
81 max_requested_frame_rate
)),
82 media::PIXEL_FORMAT_I420
)));
87 if (!RenderThreadImpl::current())
89 VideoCaptureImplManager
* manager
=
90 RenderThreadImpl::current()->video_capture_impl_manager();
93 DCHECK(source_formats_callback_
.is_null());
94 source_formats_callback_
= callback
;
95 manager
->GetDeviceFormatsInUse(
97 media::BindToCurrentLoop(
99 &VideoCapturerDelegate::OnDeviceFormatsInUseReceived
, this)));
102 void VideoCapturerDelegate::StartCapture(
103 const media::VideoCaptureParams
& params
,
104 const VideoCaptureDeliverFrameCB
& new_frame_callback
,
105 const RunningCallback
& running_callback
) {
106 DCHECK(params
.requested_format
.IsValid());
107 DCHECK(thread_checker_
.CalledOnValidThread());
108 running_callback_
= running_callback
;
110 // NULL in unit test.
111 if (!RenderThreadImpl::current())
113 VideoCaptureImplManager
* manager
=
114 RenderThreadImpl::current()->video_capture_impl_manager();
118 manager
->StartCapture(
121 media::BindToCurrentLoop(base::Bind(
122 &VideoCapturerDelegate::OnStateUpdateOnRenderThread
, this)),
126 void VideoCapturerDelegate::StopCapture() {
127 // Immediately make sure we don't provide more frames.
128 DVLOG(3) << "VideoCapturerDelegate::StopCapture()";
129 DCHECK(thread_checker_
.CalledOnValidThread());
130 if (!stop_capture_cb_
.is_null()) {
131 base::ResetAndReturn(&stop_capture_cb_
).Run();
133 running_callback_
.Reset();
134 source_formats_callback_
.Reset();
137 void VideoCapturerDelegate::OnStateUpdateOnRenderThread(
138 VideoCaptureState state
) {
139 DCHECK(thread_checker_
.CalledOnValidThread());
140 DVLOG(3) << "OnStateUpdateOnRenderThread state = " << state
;
141 if (state
== VIDEO_CAPTURE_STATE_STARTED
&& !running_callback_
.is_null()) {
142 running_callback_
.Run(MEDIA_DEVICE_OK
);
145 if (state
> VIDEO_CAPTURE_STATE_STARTED
&& !running_callback_
.is_null()) {
146 base::ResetAndReturn(&running_callback_
).Run(
147 MEDIA_DEVICE_TRACK_START_FAILURE
);
151 void VideoCapturerDelegate::OnDeviceFormatsInUseReceived(
152 const media::VideoCaptureFormats
& formats_in_use
) {
153 DVLOG(3) << "OnDeviceFormatsInUseReceived: " << formats_in_use
.size();
154 DCHECK(thread_checker_
.CalledOnValidThread());
155 // StopCapture() might have destroyed |source_formats_callback_| before
157 if (source_formats_callback_
.is_null())
159 // If there are no formats in use, try to retrieve the whole list of
161 if (!formats_in_use
.empty()) {
162 source_formats_callback_
.Run(formats_in_use
);
163 source_formats_callback_
.Reset();
167 // NULL in unit test.
168 if (!RenderThreadImpl::current())
170 VideoCaptureImplManager
* manager
=
171 RenderThreadImpl::current()->video_capture_impl_manager();
174 manager
->GetDeviceSupportedFormats(
176 media::BindToCurrentLoop(
178 &VideoCapturerDelegate::OnDeviceSupportedFormatsEnumerated
,
182 void VideoCapturerDelegate::OnDeviceSupportedFormatsEnumerated(
183 const media::VideoCaptureFormats
& formats
) {
184 DVLOG(3) << "OnDeviceSupportedFormatsEnumerated: " << formats
.size()
186 DCHECK(thread_checker_
.CalledOnValidThread());
187 // StopCapture() might have destroyed |source_formats_callback_| before
189 if (source_formats_callback_
.is_null())
191 if (formats
.size()) {
192 source_formats_callback_
.Run(formats
);
194 // The capture device doesn't seem to support capability enumeration,
195 // compose a fallback list of capabilities.
196 media::VideoCaptureFormats default_formats
;
197 for (size_t i
= 0; i
< arraysize(kVideoResolutions
); ++i
) {
198 for (size_t j
= 0; j
< arraysize(kVideoFrameRates
); ++j
) {
199 default_formats
.push_back(media::VideoCaptureFormat(
200 gfx::Size(kVideoResolutions
[i
].width
, kVideoResolutions
[i
].height
),
201 kVideoFrameRates
[j
], media::PIXEL_FORMAT_I420
));
204 source_formats_callback_
.Run(default_formats
);
206 source_formats_callback_
.Reset();
209 MediaStreamVideoCapturerSource::MediaStreamVideoCapturerSource(
210 const StreamDeviceInfo
& device_info
,
211 const SourceStoppedCallback
& stop_callback
,
212 const scoped_refptr
<VideoCapturerDelegate
>& delegate
)
213 : delegate_(delegate
) {
214 SetDeviceInfo(device_info
);
215 SetStopCallback(stop_callback
);
218 MediaStreamVideoCapturerSource::~MediaStreamVideoCapturerSource() {
221 void MediaStreamVideoCapturerSource::GetCurrentSupportedFormats(
222 int max_requested_width
,
223 int max_requested_height
,
224 double max_requested_frame_rate
,
225 const VideoCaptureDeviceFormatsCB
& callback
) {
226 delegate_
->GetCurrentSupportedFormats(
228 max_requested_height
,
229 max_requested_frame_rate
,
233 void MediaStreamVideoCapturerSource::StartSourceImpl(
234 const media::VideoCaptureParams
& params
,
235 const VideoCaptureDeliverFrameCB
& frame_callback
) {
236 media::VideoCaptureParams
new_params(params
);
237 if (device_info().device
.type
== MEDIA_TAB_VIDEO_CAPTURE
||
238 device_info().device
.type
== MEDIA_DESKTOP_VIDEO_CAPTURE
) {
239 new_params
.allow_resolution_change
= true;
241 delegate_
->StartCapture(
244 base::Bind(&MediaStreamVideoCapturerSource::OnStartDone
,
245 base::Unretained(this)));
248 void MediaStreamVideoCapturerSource::StopSourceImpl() {
249 delegate_
->StopCapture();
252 } // namespace content