Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / media_stream_video_capturer_source.cc
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 // Hard upper-bound frame rate for tab/desktop capture.
34 const double kMaxScreenCastFrameRate = 120.0;
35
36 }  // namespace
37
38 namespace content {
39
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";
46
47   // NULL in unit test.
48   if (RenderThreadImpl::current()) {
49     VideoCaptureImplManager* manager =
50         RenderThreadImpl::current()->video_capture_impl_manager();
51     if (manager)
52       release_device_cb_ = manager->UseDevice(session_id_);
53   }
54 }
55
56 VideoCapturerDelegate::~VideoCapturerDelegate() {
57   DVLOG(3) << "VideoCapturerDelegate::dtor";
58   if (!release_device_cb_.is_null())
59     release_device_cb_.Run();
60 }
61
62 void VideoCapturerDelegate::GetCurrentSupportedFormats(
63     int max_requested_width,
64     int max_requested_height,
65     double max_requested_frame_rate,
66     const VideoCaptureDeviceFormatsCB& callback) {
67   DVLOG(3)
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 << "})";
72
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)));
83     return;
84   }
85
86   // NULL in unit test.
87   if (!RenderThreadImpl::current())
88     return;
89   VideoCaptureImplManager* manager =
90       RenderThreadImpl::current()->video_capture_impl_manager();
91   if (!manager)
92     return;
93   DCHECK(source_formats_callback_.is_null());
94   source_formats_callback_ = callback;
95   manager->GetDeviceFormatsInUse(
96       session_id_,
97       media::BindToCurrentLoop(
98           base::Bind(
99               &VideoCapturerDelegate::OnDeviceFormatsInUseReceived, this)));
100 }
101
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;
109
110   // NULL in unit test.
111   if (!RenderThreadImpl::current())
112     return;
113   VideoCaptureImplManager* manager =
114       RenderThreadImpl::current()->video_capture_impl_manager();
115   if (!manager)
116     return;
117   stop_capture_cb_ =
118       manager->StartCapture(
119           session_id_,
120           params,
121           media::BindToCurrentLoop(base::Bind(
122               &VideoCapturerDelegate::OnStateUpdateOnRenderThread, this)),
123           new_frame_callback);
124 }
125
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();
132   }
133   running_callback_.Reset();
134   source_formats_callback_.Reset();
135 }
136
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);
143     return;
144   }
145   if (state > VIDEO_CAPTURE_STATE_STARTED && !running_callback_.is_null()) {
146     base::ResetAndReturn(&running_callback_).Run(
147         MEDIA_DEVICE_TRACK_START_FAILURE);
148   }
149 }
150
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
156   // arriving here.
157   if (source_formats_callback_.is_null())
158     return;
159   // If there are no formats in use, try to retrieve the whole list of
160   // supported form.
161   if (!formats_in_use.empty()) {
162     source_formats_callback_.Run(formats_in_use);
163     source_formats_callback_.Reset();
164     return;
165   }
166
167   // NULL in unit test.
168   if (!RenderThreadImpl::current())
169     return;
170   VideoCaptureImplManager* manager =
171       RenderThreadImpl::current()->video_capture_impl_manager();
172   if (!manager)
173     return;
174   manager->GetDeviceSupportedFormats(
175       session_id_,
176       media::BindToCurrentLoop(
177           base::Bind(
178               &VideoCapturerDelegate::OnDeviceSupportedFormatsEnumerated,
179               this)));
180 }
181
182 void VideoCapturerDelegate::OnDeviceSupportedFormatsEnumerated(
183     const media::VideoCaptureFormats& formats) {
184   DVLOG(3) << "OnDeviceSupportedFormatsEnumerated: " << formats.size()
185            << " received";
186   DCHECK(thread_checker_.CalledOnValidThread());
187   // StopCapture() might have destroyed |source_formats_callback_| before
188   // arriving here.
189   if (source_formats_callback_.is_null())
190     return;
191   if (formats.size()) {
192     source_formats_callback_.Run(formats);
193   } else {
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));
202       }
203     }
204     source_formats_callback_.Run(default_formats);
205   }
206   source_formats_callback_.Reset();
207 }
208
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);
216 }
217
218 MediaStreamVideoCapturerSource::~MediaStreamVideoCapturerSource() {
219 }
220
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(
227       max_requested_width,
228       max_requested_height,
229       max_requested_frame_rate,
230       callback);
231 }
232
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;
240   }
241   delegate_->StartCapture(
242       new_params,
243       frame_callback,
244       base::Bind(&MediaStreamVideoCapturerSource::OnStartDone,
245                  base::Unretained(this)));
246 }
247
248 void MediaStreamVideoCapturerSource::StopSourceImpl() {
249   delegate_->StopCapture();
250 }
251
252 }  // namespace content