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