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 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 54 VideoCapturerDelegate::~VideoCapturerDelegate() { 55 DVLOG(3) << "VideoCapturerDelegate::dtor"; 56 if (!release_device_cb_.is_null()) 57 release_device_cb_.Run(); 58 } 59 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 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 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 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 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 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 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 215 MediaStreamVideoCapturerSource::~MediaStreamVideoCapturerSource() { 216 } 217 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 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 243 void MediaStreamVideoCapturerSource::StopSourceImpl() { 244 delegate_->StopCapture(); 245 } 246 247 } // namespace content 248