• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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