webrtc_video_capturer_adapter.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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/webrtc/webrtc_video_capturer_adapter.h" 6 7#include "base/bind.h" 8#include "base/debug/trace_event.h" 9#include "base/memory/aligned_memory.h" 10#include "media/base/video_frame.h" 11#include "third_party/libyuv/include/libyuv/convert.h" 12 13namespace content { 14 15WebRtcVideoCapturerAdapter::WebRtcVideoCapturerAdapter(bool is_screencast) 16 : is_screencast_(is_screencast), 17 running_(false), 18 buffer_(NULL), 19 buffer_size_(0) { 20} 21 22WebRtcVideoCapturerAdapter::~WebRtcVideoCapturerAdapter() { 23 DVLOG(3) << " WebRtcVideoCapturerAdapter::dtor"; 24 base::AlignedFree(buffer_); 25} 26 27void WebRtcVideoCapturerAdapter::SetRequestedFormat( 28 const media::VideoCaptureFormat& format) { 29 DCHECK_EQ(media::PIXEL_FORMAT_I420, format.pixel_format); 30 DVLOG(3) << "WebRtcVideoCapturerAdapter::SetRequestedFormat" 31 << " w = " << format.frame_size.width() 32 << " h = " << format.frame_size.height(); 33 cricket::VideoFormat supported_format(format.frame_size.width(), 34 format.frame_size.height(), 35 cricket::VideoFormat::FpsToInterval( 36 format.frame_rate), 37 cricket::FOURCC_I420); 38 SetCaptureFormat(&supported_format); 39 40 // Update the desired aspect ratio so that later the video frame can be 41 // cropped to meet the requirement if the camera returns a different 42 // resolution than the |request|. 43 UpdateAspectRatio(format.frame_size.width(), format.frame_size.height()); 44} 45 46cricket::CaptureState WebRtcVideoCapturerAdapter::Start( 47 const cricket::VideoFormat& capture_format) { 48 DCHECK(!running_); 49 DVLOG(3) << " WebRtcVideoCapturerAdapter::Start w = " << capture_format.width 50 << " h = " << capture_format.height; 51 52 running_ = true; 53 return cricket::CS_RUNNING; 54} 55 56void WebRtcVideoCapturerAdapter::Stop() { 57 DVLOG(3) << " WebRtcVideoCapturerAdapter::Stop "; 58 DCHECK(running_); 59 running_ = false; 60 SetCaptureFormat(NULL); 61 SignalStateChange(this, cricket::CS_STOPPED); 62} 63 64bool WebRtcVideoCapturerAdapter::IsRunning() { 65 return running_; 66} 67 68bool WebRtcVideoCapturerAdapter::GetPreferredFourccs( 69 std::vector<uint32>* fourccs) { 70 if (!fourccs) 71 return false; 72 fourccs->push_back(cricket::FOURCC_I420); 73 return true; 74} 75 76bool WebRtcVideoCapturerAdapter::IsScreencast() const { 77 return is_screencast_; 78} 79 80bool WebRtcVideoCapturerAdapter::GetBestCaptureFormat( 81 const cricket::VideoFormat& desired, 82 cricket::VideoFormat* best_format) { 83 DVLOG(3) << " GetBestCaptureFormat:: " 84 << " w = " << desired.width 85 << " h = " << desired.height; 86 87 // Capability enumeration is done in MediaStreamVideoSource. The adapter can 88 // just use what is provided. 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 WebRtcVideoCapturerAdapter::OnFrameCaptured( 98 const scoped_refptr<media::VideoFrame>& frame) { 99 DCHECK(media::VideoFrame::I420 == frame->format() || 100 media::VideoFrame::YV12 == frame->format()); 101 if (first_frame_timestamp_ == media::kNoTimestamp()) 102 first_frame_timestamp_ = frame->GetTimestamp(); 103 104 cricket::CapturedFrame captured_frame; 105 captured_frame.width = frame->visible_rect().width(); 106 captured_frame.height = frame->visible_rect().height(); 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 captured_frame.pixel_height = 1; 114 captured_frame.pixel_width = 1; 115 116 // TODO(perkj): 117 // Libjingle expects contiguous layout of image planes as input. 118 // The only format where that is true in Chrome is I420 where the 119 // coded_size == visible_rect().size(). 120 if (frame->format() != media::VideoFrame::I420 || 121 frame->coded_size() != frame->visible_rect().size()) { 122 // Cropping and or switching UV planes is needed. 123 UpdateI420Buffer(frame); 124 captured_frame.data = buffer_; 125 captured_frame.data_size = buffer_size_; 126 captured_frame.fourcc = cricket::FOURCC_I420; 127 } else { 128 captured_frame.fourcc = media::VideoFrame::I420 == frame->format() ? 129 cricket::FOURCC_I420 : cricket::FOURCC_YV12; 130 captured_frame.data = frame->data(0); 131 captured_frame.data_size = 132 media::VideoFrame::AllocationSize(frame->format(), frame->coded_size()); 133 } 134 135 // This signals to libJingle that a new VideoFrame is available. 136 // libJingle have no assumptions on what thread this signal come from. 137 SignalFrameCaptured(this, &captured_frame); 138} 139 140void WebRtcVideoCapturerAdapter::UpdateI420Buffer( 141 const scoped_refptr<media::VideoFrame>& src) { 142 const int src_width = src->coded_size().width(); 143 const int src_height = src->coded_size().height(); 144 const int dst_width = src->visible_rect().width(); 145 const int dst_height = src->visible_rect().height(); 146 DCHECK(src_width >= dst_width && src_height >= dst_height); 147 148 const int horiz_crop = src->visible_rect().x(); 149 const int vert_crop = src->visible_rect().y(); 150 151 const uint8* src_y = src->data(media::VideoFrame::kYPlane) + 152 (src_width * vert_crop + horiz_crop); 153 const int center = (src_width + 1) / 2; 154 const uint8* src_u = src->data(media::VideoFrame::kUPlane) + 155 (center * vert_crop + horiz_crop) / 2; 156 const uint8* src_v = src->data(media::VideoFrame::kVPlane) + 157 (center * vert_crop + horiz_crop) / 2; 158 159 const size_t dst_size = 160 media::VideoFrame::AllocationSize(src->format(), 161 src->visible_rect().size()); 162 163 if (dst_size != buffer_size_) { 164 base::AlignedFree(buffer_); 165 buffer_ = reinterpret_cast<uint8*>( 166 base::AlignedAlloc(dst_size + media::VideoFrame::kFrameSizePadding, 167 media::VideoFrame::kFrameAddressAlignment)); 168 buffer_size_ = dst_size; 169 } 170 171 uint8* dst_y = buffer_; 172 const int dst_stride_y = dst_width; 173 uint8* dst_u = dst_y + dst_width * dst_height; 174 const int dst_halfwidth = (dst_width + 1) / 2; 175 const int dst_halfheight = (dst_height + 1) / 2; 176 uint8* dst_v = dst_u + dst_halfwidth * dst_halfheight; 177 178 libyuv::I420Copy(src_y, 179 src->stride(media::VideoFrame::kYPlane), 180 src_u, 181 src->stride(media::VideoFrame::kUPlane), 182 src_v, 183 src->stride(media::VideoFrame::kVPlane), 184 dst_y, 185 dst_stride_y, 186 dst_u, 187 dst_halfwidth, 188 dst_v, 189 dst_halfwidth, 190 dst_width, 191 dst_height); 192} 193 194} // namespace content 195