Home | History | Annotate | Download | only in media
      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