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 10namespace content { 11 12RtcVideoCapturer::RtcVideoCapturer( 13 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 21RtcVideoCapturer::~RtcVideoCapturer() { 22 DCHECK(VIDEO_CAPTURE_STATE_STOPPED); 23 DVLOG(3) << " RtcVideoCapturer::dtor"; 24} 25 26cricket::CaptureState RtcVideoCapturer::Start( 27 const cricket::VideoFormat& capture_format) { 28 DVLOG(3) << " RtcVideoCapturer::Start "; 29 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { 30 DVLOG(1) << "Got a StartCapture when already started!!! "; 31 return cricket::CS_FAILED; 32 } 33 34 media::VideoCaptureCapability cap; 35 cap.width = capture_format.width; 36 cap.height = capture_format.height; 37 cap.frame_rate = capture_format.framerate(); 38 cap.color = media::VideoCaptureCapability::kI420; 39 40 SetCaptureFormat(&capture_format); 41 42 state_ = VIDEO_CAPTURE_STATE_STARTED; 43 start_time_ = base::Time::Now(); 44 delegate_->StartCapture(cap, 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 |cap|. 50 UpdateAspectRatio(cap.width, cap.height); 51 return cricket::CS_STARTING; 52} 53 54void 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 67bool RtcVideoCapturer::IsRunning() { 68 return state_ == VIDEO_CAPTURE_STATE_STARTED; 69} 70 71bool RtcVideoCapturer::GetPreferredFourccs(std::vector<uint32>* fourccs) { 72 if (!fourccs) 73 return false; 74 fourccs->push_back(cricket::FOURCC_I420); 75 return true; 76} 77 78bool RtcVideoCapturer::IsScreencast() const { 79 return is_screencast_; 80} 81 82bool 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 97void RtcVideoCapturer::OnFrameCaptured( 98 const media::VideoCapture::VideoFrameBuffer& buf) { 99 // Currently, |fourcc| is always I420. 100 cricket::CapturedFrame frame; 101 frame.width = buf.width; 102 frame.height = buf.height; 103 frame.fourcc = cricket::FOURCC_I420; 104 frame.data_size = buf.buffer_size; 105 // cricket::CapturedFrame time is in nanoseconds. 106 frame.elapsed_time = (buf.timestamp - start_time_).InMicroseconds() * 107 base::Time::kNanosecondsPerMicrosecond; 108 frame.time_stamp = 109 (buf.timestamp - base::Time::UnixEpoch()).InMicroseconds() * 110 base::Time::kNanosecondsPerMicrosecond; 111 frame.data = buf.memory_pointer; 112 frame.pixel_height = 1; 113 frame.pixel_width = 1; 114 115 TRACE_EVENT_INSTANT2("rtc_video_capturer", 116 "OnFrameCaptured", 117 TRACE_EVENT_SCOPE_THREAD, 118 "elapsed time", 119 frame.elapsed_time, 120 "timestamp_ms", 121 frame.time_stamp / talk_base::kNumNanosecsPerMillisec); 122 123 // This signals to libJingle that a new VideoFrame is available. 124 // libJingle have no assumptions on what thread this signal come from. 125 SignalFrameCaptured(this, &frame); 126} 127 128void RtcVideoCapturer::OnStateChange( 129 RtcVideoCaptureDelegate::CaptureState state) { 130 cricket::CaptureState converted_state = cricket::CS_FAILED; 131 DVLOG(3) << " RtcVideoCapturer::OnStateChange " << state; 132 switch (state) { 133 case RtcVideoCaptureDelegate::CAPTURE_STOPPED: 134 converted_state = cricket::CS_STOPPED; 135 break; 136 case RtcVideoCaptureDelegate::CAPTURE_RUNNING: 137 converted_state = cricket::CS_RUNNING; 138 break; 139 case RtcVideoCaptureDelegate::CAPTURE_FAILED: 140 // TODO(perkj): Update the comments in the the definition of 141 // cricket::CS_FAILED. According to the comments, cricket::CS_FAILED 142 // means that the capturer failed to start. But here and in libjingle it 143 // is also used if an error occur during capturing. 144 converted_state = cricket::CS_FAILED; 145 break; 146 default: 147 NOTREACHED(); 148 break; 149 } 150 SignalStateChange(this, converted_state); 151} 152 153} // namespace content 154