Home | History | Annotate | Download | only in media
      1 // Copyright (c) 2012 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/rtc_video_capturer.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/debug/trace_event.h"
      9 #include "media/base/video_frame.h"
     10 
     11 namespace content {
     12 
     13 RtcVideoCapturer::RtcVideoCapturer(const media::VideoCaptureSessionId id,
     14                                    VideoCaptureImplManager* vc_manager,
     15                                    bool is_screencast)
     16     : is_screencast_(is_screencast),
     17       delegate_(new RtcVideoCaptureDelegate(id, vc_manager)),
     18       state_(VIDEO_CAPTURE_STATE_STOPPED) {}
     19 
     20 RtcVideoCapturer::~RtcVideoCapturer() {
     21   DCHECK(VIDEO_CAPTURE_STATE_STOPPED);
     22   DVLOG(3) << " RtcVideoCapturer::dtor";
     23 }
     24 
     25 cricket::CaptureState RtcVideoCapturer::Start(
     26     const cricket::VideoFormat& capture_format) {
     27   DVLOG(3) << " RtcVideoCapturer::Start ";
     28   if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
     29     DVLOG(1) << "Got a StartCapture when already started!!! ";
     30     return cricket::CS_FAILED;
     31   }
     32 
     33   media::VideoCaptureParams request;
     34   request.requested_format = media::VideoCaptureFormat(
     35       gfx::Size(capture_format.width, capture_format.height),
     36       capture_format.framerate(),
     37       media::PIXEL_FORMAT_I420);
     38 
     39   SetCaptureFormat(&capture_format);
     40 
     41   state_ = VIDEO_CAPTURE_STATE_STARTED;
     42   first_frame_timestamp_ = media::kNoTimestamp();
     43   delegate_->StartCapture(
     44       request,
     45       base::Bind(&RtcVideoCapturer::OnFrameCaptured, base::Unretained(this)),
     46       base::Bind(&RtcVideoCapturer::OnStateChange, base::Unretained(this)));
     47   // Update the desired aspect ratio so that later the video frame can be
     48   // cropped to meet the requirement if the camera returns a different
     49   // resolution than the |request|.
     50   UpdateAspectRatio(capture_format.width, capture_format.height);
     51   return cricket::CS_STARTING;
     52 }
     53 
     54 void RtcVideoCapturer::Stop() {
     55   DVLOG(3) << " RtcVideoCapturer::Stop ";
     56   if (state_ == VIDEO_CAPTURE_STATE_STOPPED) {
     57     DVLOG(1) << "Got a StopCapture while not started.";
     58     return;
     59   }
     60 
     61   SetCaptureFormat(NULL);
     62   state_ = VIDEO_CAPTURE_STATE_STOPPED;
     63   delegate_->StopCapture();
     64   SignalStateChange(this, cricket::CS_STOPPED);
     65 }
     66 
     67 bool RtcVideoCapturer::IsRunning() {
     68   return state_ == VIDEO_CAPTURE_STATE_STARTED;
     69 }
     70 
     71 bool RtcVideoCapturer::GetPreferredFourccs(std::vector<uint32>* fourccs) {
     72   if (!fourccs)
     73     return false;
     74   fourccs->push_back(cricket::FOURCC_I420);
     75   return true;
     76 }
     77 
     78 bool RtcVideoCapturer::IsScreencast() const {
     79   return is_screencast_;
     80 }
     81 
     82 bool RtcVideoCapturer::GetBestCaptureFormat(const cricket::VideoFormat& desired,
     83                                             cricket::VideoFormat* best_format) {
     84   if (!best_format) {
     85     return false;
     86   }
     87 
     88   // Chrome does not support capability enumeration.
     89   // Use the desired format as the best format.
     90   best_format->width = desired.width;
     91   best_format->height = desired.height;
     92   best_format->fourcc = cricket::FOURCC_I420;
     93   best_format->interval = desired.interval;
     94   return true;
     95 }
     96 
     97 void RtcVideoCapturer::OnFrameCaptured(
     98     const scoped_refptr<media::VideoFrame>& frame) {
     99   if (first_frame_timestamp_ == media::kNoTimestamp())
    100     first_frame_timestamp_ = frame->GetTimestamp();
    101 
    102   // Currently, |fourcc| is always I420.
    103   cricket::CapturedFrame captured_frame;
    104   captured_frame.width = frame->coded_size().width();
    105   captured_frame.height = frame->coded_size().height();
    106   captured_frame.fourcc = cricket::FOURCC_I420;
    107   // cricket::CapturedFrame time is in nanoseconds.
    108   captured_frame.elapsed_time =
    109       (frame->GetTimestamp() - first_frame_timestamp_).InMicroseconds() *
    110       base::Time::kNanosecondsPerMicrosecond;
    111   captured_frame.time_stamp = frame->GetTimestamp().InMicroseconds() *
    112                               base::Time::kNanosecondsPerMicrosecond;
    113   // TODO(sheu): we assume contiguous layout of image planes.
    114   captured_frame.data = frame->data(0);
    115   captured_frame.data_size =
    116       media::VideoFrame::AllocationSize(frame->format(), frame->coded_size());
    117   captured_frame.pixel_height = 1;
    118   captured_frame.pixel_width = 1;
    119 
    120   TRACE_EVENT_INSTANT2(
    121       "rtc_video_capturer",
    122       "OnFrameCaptured",
    123       TRACE_EVENT_SCOPE_THREAD,
    124       "elapsed time",
    125       captured_frame.elapsed_time,
    126       "timestamp_ms",
    127       captured_frame.time_stamp / talk_base::kNumNanosecsPerMillisec);
    128 
    129   // This signals to libJingle that a new VideoFrame is available.
    130   // libJingle have no assumptions on what thread this signal come from.
    131   SignalFrameCaptured(this, &captured_frame);
    132 }
    133 
    134 void RtcVideoCapturer::OnStateChange(
    135     RtcVideoCaptureDelegate::CaptureState state) {
    136   cricket::CaptureState converted_state = cricket::CS_FAILED;
    137   DVLOG(3) << " RtcVideoCapturer::OnStateChange " << state;
    138   switch (state) {
    139     case RtcVideoCaptureDelegate::CAPTURE_STOPPED:
    140       converted_state = cricket::CS_STOPPED;
    141       break;
    142     case RtcVideoCaptureDelegate::CAPTURE_RUNNING:
    143       converted_state = cricket::CS_RUNNING;
    144       break;
    145     case RtcVideoCaptureDelegate::CAPTURE_FAILED:
    146       // TODO(perkj): Update the comments in the the definition of
    147       // cricket::CS_FAILED. According to the comments, cricket::CS_FAILED
    148       // means that the capturer failed to start. But here and in libjingle it
    149       // is also used if an error occur during capturing.
    150       converted_state = cricket::CS_FAILED;
    151       break;
    152     default:
    153       NOTREACHED();
    154       break;
    155   }
    156   SignalStateChange(this, converted_state);
    157 }
    158 
    159 }  // namespace content
    160