Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / media / webrtc / webrtc_video_capturer_adapter.cc
blob024c2b1ea6585360bfd9c2ce016e731ff302ad24
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"
7 #include "base/bind.h"
8 #include "base/memory/aligned_memory.h"
9 #include "base/trace_event/trace_event.h"
10 #include "media/base/video_frame.h"
11 #include "media/base/video_frame_pool.h"
12 #include "third_party/libjingle/source/talk/media/base/videoframefactory.h"
13 #include "third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.h"
14 #include "third_party/libyuv/include/libyuv/convert_from.h"
15 #include "third_party/libyuv/include/libyuv/scale.h"
16 #include "third_party/webrtc/common_video/interface/video_frame_buffer.h"
17 #include "third_party/webrtc/common_video/rotation.h"
19 namespace content {
20 namespace {
22 // Empty method used for keeping a reference to the original media::VideoFrame.
23 // The reference to |frame| is kept in the closure that calls this method.
24 void ReleaseOriginalFrame(const scoped_refptr<media::VideoFrame>& frame) {
27 int WebRtcToMediaPlaneType(webrtc::PlaneType type) {
28 switch (type) {
29 case webrtc::kYPlane:
30 return media::VideoFrame::kYPlane;
31 case webrtc::kUPlane:
32 return media::VideoFrame::kUPlane;
33 case webrtc::kVPlane:
34 return media::VideoFrame::kVPlane;
35 default:
36 NOTREACHED();
37 return media::VideoFrame::kMaxPlanes;
41 // Thin adapter from media::VideoFrame to webrtc::VideoFrameBuffer. This
42 // implementation is read-only and will return null if trying to get a
43 // non-const pointer to the pixel data. This object will be accessed from
44 // different threads, but that's safe since it's read-only.
45 class VideoFrameWrapper : public webrtc::VideoFrameBuffer {
46 public:
47 VideoFrameWrapper(const scoped_refptr<media::VideoFrame>& frame)
48 : frame_(frame) {}
50 private:
51 int width() const override { return frame_->visible_rect().width(); }
53 int height() const override { return frame_->visible_rect().height(); }
55 const uint8_t* data(webrtc::PlaneType type) const override {
56 return frame_->visible_data(WebRtcToMediaPlaneType(type));
59 uint8_t* data(webrtc::PlaneType type) override {
60 NOTREACHED();
61 return nullptr;
64 int stride(webrtc::PlaneType type) const override {
65 return frame_->stride(WebRtcToMediaPlaneType(type));
68 rtc::scoped_refptr<webrtc::NativeHandle> native_handle() const override {
69 return nullptr;
72 ~VideoFrameWrapper() override {}
73 friend class rtc::RefCountedObject<VideoFrameWrapper>;
75 scoped_refptr<media::VideoFrame> frame_;
78 } // anonymous namespace
80 // A cricket::VideoFrameFactory for media::VideoFrame. The purpose of this
81 // class is to avoid a premature frame copy. A media::VideoFrame is injected
82 // with SetFrame, and converted into a cricket::VideoFrame with
83 // CreateAliasedFrame. SetFrame should be called before CreateAliasedFrame
84 // for every frame.
85 class WebRtcVideoCapturerAdapter::MediaVideoFrameFactory
86 : public cricket::VideoFrameFactory {
87 public:
88 void SetFrame(const scoped_refptr<media::VideoFrame>& frame,
89 int64_t elapsed_time) {
90 DCHECK(frame.get());
91 // Create a CapturedFrame that only contains header information, not the
92 // actual pixel data.
93 captured_frame_.width = frame->natural_size().width();
94 captured_frame_.height = frame->natural_size().height();
95 captured_frame_.elapsed_time = elapsed_time;
96 captured_frame_.time_stamp = frame->timestamp().InMicroseconds() *
97 base::Time::kNanosecondsPerMicrosecond;
98 captured_frame_.pixel_height = 1;
99 captured_frame_.pixel_width = 1;
100 captured_frame_.rotation = webrtc::kVideoRotation_0;
101 captured_frame_.data = NULL;
102 captured_frame_.data_size = cricket::CapturedFrame::kUnknownDataSize;
103 captured_frame_.fourcc = static_cast<uint32>(cricket::FOURCC_ANY);
105 frame_ = frame;
108 void ReleaseFrame() { frame_ = NULL; }
110 const cricket::CapturedFrame* GetCapturedFrame() const {
111 return &captured_frame_;
114 cricket::VideoFrame* CreateAliasedFrame(
115 const cricket::CapturedFrame* input_frame,
116 int cropped_input_width,
117 int cropped_input_height,
118 int output_width,
119 int output_height) const override {
120 // Check that captured_frame is actually our frame.
121 DCHECK(input_frame == &captured_frame_);
122 DCHECK(frame_.get());
124 // Create a centered cropped visible rect that preservers aspect ratio for
125 // cropped natural size.
126 gfx::Rect visible_rect = frame_->visible_rect();
127 visible_rect.ClampToCenteredSize(gfx::Size(
128 visible_rect.width() * cropped_input_width / input_frame->width,
129 visible_rect.height() * cropped_input_height / input_frame->height));
131 const gfx::Size output_size(output_width, output_height);
132 scoped_refptr<media::VideoFrame> video_frame =
133 media::VideoFrame::WrapVideoFrame(
134 frame_, visible_rect, output_size,
135 base::Bind(&ReleaseOriginalFrame, frame_));
137 const int64_t timestamp_ns = frame_->timestamp().InMicroseconds() *
138 base::Time::kNanosecondsPerMicrosecond;
140 // If no scaling is needed, return a wrapped version of |frame_| directly.
141 if (video_frame->natural_size() == video_frame->visible_rect().size()) {
142 return new cricket::WebRtcVideoFrame(
143 new rtc::RefCountedObject<VideoFrameWrapper>(video_frame),
144 captured_frame_.elapsed_time, timestamp_ns);
147 // We need to scale the frame before we hand it over to cricket.
148 scoped_refptr<media::VideoFrame> scaled_frame =
149 scaled_frame_pool_.CreateFrame(media::VideoFrame::I420, output_size,
150 gfx::Rect(output_size), output_size,
151 frame_->timestamp());
152 libyuv::I420Scale(video_frame->visible_data(media::VideoFrame::kYPlane),
153 video_frame->stride(media::VideoFrame::kYPlane),
154 video_frame->visible_data(media::VideoFrame::kUPlane),
155 video_frame->stride(media::VideoFrame::kUPlane),
156 video_frame->visible_data(media::VideoFrame::kVPlane),
157 video_frame->stride(media::VideoFrame::kVPlane),
158 video_frame->visible_rect().width(),
159 video_frame->visible_rect().height(),
160 scaled_frame->data(media::VideoFrame::kYPlane),
161 scaled_frame->stride(media::VideoFrame::kYPlane),
162 scaled_frame->data(media::VideoFrame::kUPlane),
163 scaled_frame->stride(media::VideoFrame::kUPlane),
164 scaled_frame->data(media::VideoFrame::kVPlane),
165 scaled_frame->stride(media::VideoFrame::kVPlane),
166 output_width, output_height, libyuv::kFilterBilinear);
167 return new cricket::WebRtcVideoFrame(
168 new rtc::RefCountedObject<VideoFrameWrapper>(scaled_frame),
169 captured_frame_.elapsed_time, timestamp_ns);
172 cricket::VideoFrame* CreateAliasedFrame(
173 const cricket::CapturedFrame* input_frame,
174 int output_width,
175 int output_height) const override {
176 return CreateAliasedFrame(input_frame, input_frame->width,
177 input_frame->height, output_width, output_height);
180 private:
181 scoped_refptr<media::VideoFrame> frame_;
182 cricket::CapturedFrame captured_frame_;
183 // This is used only if scaling is needed.
184 mutable media::VideoFramePool scaled_frame_pool_;
187 WebRtcVideoCapturerAdapter::WebRtcVideoCapturerAdapter(bool is_screencast)
188 : is_screencast_(is_screencast),
189 running_(false),
190 first_frame_timestamp_(media::kNoTimestamp()),
191 frame_factory_(new MediaVideoFrameFactory) {
192 thread_checker_.DetachFromThread();
193 // The base class takes ownership of the frame factory.
194 set_frame_factory(frame_factory_);
197 WebRtcVideoCapturerAdapter::~WebRtcVideoCapturerAdapter() {
198 DVLOG(3) << " WebRtcVideoCapturerAdapter::dtor";
201 cricket::CaptureState WebRtcVideoCapturerAdapter::Start(
202 const cricket::VideoFormat& capture_format) {
203 DCHECK(thread_checker_.CalledOnValidThread());
204 DCHECK(!running_);
205 DVLOG(3) << " WebRtcVideoCapturerAdapter::Start w = " << capture_format.width
206 << " h = " << capture_format.height;
208 running_ = true;
209 return cricket::CS_RUNNING;
212 void WebRtcVideoCapturerAdapter::Stop() {
213 DCHECK(thread_checker_.CalledOnValidThread());
214 DVLOG(3) << " WebRtcVideoCapturerAdapter::Stop ";
215 DCHECK(running_);
216 running_ = false;
217 SetCaptureFormat(NULL);
218 SignalStateChange(this, cricket::CS_STOPPED);
221 bool WebRtcVideoCapturerAdapter::IsRunning() {
222 DCHECK(thread_checker_.CalledOnValidThread());
223 return running_;
226 bool WebRtcVideoCapturerAdapter::GetPreferredFourccs(
227 std::vector<uint32>* fourccs) {
228 DCHECK(thread_checker_.CalledOnValidThread());
229 DCHECK(!fourccs || fourccs->empty());
230 if (fourccs)
231 fourccs->push_back(cricket::FOURCC_I420);
232 return fourccs != NULL;
235 bool WebRtcVideoCapturerAdapter::IsScreencast() const {
236 return is_screencast_;
239 bool WebRtcVideoCapturerAdapter::GetBestCaptureFormat(
240 const cricket::VideoFormat& desired,
241 cricket::VideoFormat* best_format) {
242 DCHECK(thread_checker_.CalledOnValidThread());
243 DVLOG(3) << " GetBestCaptureFormat:: "
244 << " w = " << desired.width
245 << " h = " << desired.height;
247 // Capability enumeration is done in MediaStreamVideoSource. The adapter can
248 // just use what is provided.
249 // Use the desired format as the best format.
250 best_format->width = desired.width;
251 best_format->height = desired.height;
252 best_format->fourcc = cricket::FOURCC_I420;
253 best_format->interval = desired.interval;
254 return true;
257 void WebRtcVideoCapturerAdapter::OnFrameCaptured(
258 const scoped_refptr<media::VideoFrame>& frame) {
259 DCHECK(thread_checker_.CalledOnValidThread());
260 TRACE_EVENT0("video", "WebRtcVideoCapturerAdapter::OnFrameCaptured");
261 if (!(media::VideoFrame::I420 == frame->format() ||
262 media::VideoFrame::YV12 == frame->format())) {
263 // Some types of sources support textures as output. Since connecting
264 // sources and sinks do not check the format, we need to just ignore
265 // formats that we can not handle.
266 NOTREACHED();
267 return;
270 if (first_frame_timestamp_ == media::kNoTimestamp())
271 first_frame_timestamp_ = frame->timestamp();
273 const int64 elapsed_time =
274 (frame->timestamp() - first_frame_timestamp_).InMicroseconds() *
275 base::Time::kNanosecondsPerMicrosecond;
277 // Inject the frame via the VideoFrameFractory.
278 DCHECK(frame_factory_ == frame_factory());
279 frame_factory_->SetFrame(frame, elapsed_time);
281 // This signals to libJingle that a new VideoFrame is available.
282 SignalFrameCaptured(this, frame_factory_->GetCapturedFrame());
284 frame_factory_->ReleaseFrame(); // Release the frame ASAP.
287 } // namespace content