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.
5 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.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"
15 WebRtcVideoCapturerAdapter::WebRtcVideoCapturerAdapter(bool is_screencast)
16 : is_screencast_(is_screencast),
20 thread_checker_.DetachFromThread();
23 WebRtcVideoCapturerAdapter::~WebRtcVideoCapturerAdapter() {
24 DVLOG(3) << " WebRtcVideoCapturerAdapter::dtor";
25 base::AlignedFree(buffer_);
28 cricket::CaptureState WebRtcVideoCapturerAdapter::Start(
29 const cricket::VideoFormat& capture_format) {
30 DCHECK(thread_checker_.CalledOnValidThread());
32 DVLOG(3) << " WebRtcVideoCapturerAdapter::Start w = " << capture_format.width
33 << " h = " << capture_format.height;
36 return cricket::CS_RUNNING;
39 void WebRtcVideoCapturerAdapter::Stop() {
40 DCHECK(thread_checker_.CalledOnValidThread());
41 DVLOG(3) << " WebRtcVideoCapturerAdapter::Stop ";
44 SetCaptureFormat(NULL);
45 SignalStateChange(this, cricket::CS_STOPPED);
48 bool WebRtcVideoCapturerAdapter::IsRunning() {
49 DCHECK(thread_checker_.CalledOnValidThread());
53 bool WebRtcVideoCapturerAdapter::GetPreferredFourccs(
54 std::vector<uint32>* fourccs) {
55 DCHECK(thread_checker_.CalledOnValidThread());
58 fourccs->push_back(cricket::FOURCC_I420);
62 bool WebRtcVideoCapturerAdapter::IsScreencast() const {
63 return is_screencast_;
66 bool WebRtcVideoCapturerAdapter::GetBestCaptureFormat(
67 const cricket::VideoFormat& desired,
68 cricket::VideoFormat* best_format) {
69 DCHECK(thread_checker_.CalledOnValidThread());
70 DVLOG(3) << " GetBestCaptureFormat:: "
71 << " w = " << desired.width
72 << " h = " << desired.height;
74 // Capability enumeration is done in MediaStreamVideoSource. The adapter can
75 // just use what is provided.
76 // Use the desired format as the best format.
77 best_format->width = desired.width;
78 best_format->height = desired.height;
79 best_format->fourcc = cricket::FOURCC_I420;
80 best_format->interval = desired.interval;
84 void WebRtcVideoCapturerAdapter::OnFrameCaptured(
85 const scoped_refptr<media::VideoFrame>& frame) {
86 DCHECK(thread_checker_.CalledOnValidThread());
87 DCHECK(media::VideoFrame::I420 == frame->format() ||
88 media::VideoFrame::YV12 == frame->format());
89 if (first_frame_timestamp_ == media::kNoTimestamp())
90 first_frame_timestamp_ = frame->timestamp();
92 cricket::CapturedFrame captured_frame;
93 captured_frame.width = frame->visible_rect().width();
94 captured_frame.height = frame->visible_rect().height();
95 // cricket::CapturedFrame time is in nanoseconds.
96 captured_frame.elapsed_time =
97 (frame->timestamp() - first_frame_timestamp_).InMicroseconds() *
98 base::Time::kNanosecondsPerMicrosecond;
99 captured_frame.time_stamp = frame->timestamp().InMicroseconds() *
100 base::Time::kNanosecondsPerMicrosecond;
101 captured_frame.pixel_height = 1;
102 captured_frame.pixel_width = 1;
105 // Libjingle expects contiguous layout of image planes as input.
106 // The only format where that is true in Chrome is I420 where the
107 // coded_size == visible_rect().size().
108 if (frame->format() != media::VideoFrame::I420 ||
109 frame->coded_size() != frame->visible_rect().size()) {
110 // Cropping and or switching UV planes is needed.
111 UpdateI420Buffer(frame);
112 captured_frame.data = buffer_;
113 captured_frame.data_size = buffer_size_;
114 captured_frame.fourcc = cricket::FOURCC_I420;
116 captured_frame.fourcc = media::VideoFrame::I420 == frame->format() ?
117 cricket::FOURCC_I420 : cricket::FOURCC_YV12;
118 captured_frame.data = frame->data(0);
119 captured_frame.data_size =
120 media::VideoFrame::AllocationSize(frame->format(), frame->coded_size());
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, &captured_frame);
128 void WebRtcVideoCapturerAdapter::UpdateI420Buffer(
129 const scoped_refptr<media::VideoFrame>& src) {
130 DCHECK(thread_checker_.CalledOnValidThread());
131 const int src_width = src->coded_size().width();
132 const int src_height = src->coded_size().height();
133 const int dst_width = src->visible_rect().width();
134 const int dst_height = src->visible_rect().height();
135 DCHECK(src_width >= dst_width && src_height >= dst_height);
137 const int horiz_crop = src->visible_rect().x();
138 const int vert_crop = src->visible_rect().y();
140 const uint8* src_y = src->data(media::VideoFrame::kYPlane) +
141 (src_width * vert_crop + horiz_crop);
142 const int center = (src_width + 1) / 2;
143 const uint8* src_u = src->data(media::VideoFrame::kUPlane) +
144 (center * vert_crop + horiz_crop) / 2;
145 const uint8* src_v = src->data(media::VideoFrame::kVPlane) +
146 (center * vert_crop + horiz_crop) / 2;
148 const size_t dst_size =
149 media::VideoFrame::AllocationSize(src->format(),
150 src->visible_rect().size());
152 if (dst_size != buffer_size_) {
153 base::AlignedFree(buffer_);
154 buffer_ = reinterpret_cast<uint8*>(
155 base::AlignedAlloc(dst_size + media::VideoFrame::kFrameSizePadding,
156 media::VideoFrame::kFrameAddressAlignment));
157 buffer_size_ = dst_size;
160 uint8* dst_y = buffer_;
161 const int dst_stride_y = dst_width;
162 uint8* dst_u = dst_y + dst_width * dst_height;
163 const int dst_halfwidth = (dst_width + 1) / 2;
164 const int dst_halfheight = (dst_height + 1) / 2;
165 uint8* dst_v = dst_u + dst_halfwidth * dst_halfheight;
167 libyuv::I420Copy(src_y,
168 src->stride(media::VideoFrame::kYPlane),
170 src->stride(media::VideoFrame::kUPlane),
172 src->stride(media::VideoFrame::kVPlane),
183 } // namespace content