Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(144)

Side by Side Diff: content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc

Issue 604743005: VideoCapture: Remove deep frame copy in the border to libJingle (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h" 5 #include "content/renderer/media/webrtc/webrtc_video_capturer_adapter.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
9 #include "base/memory/aligned_memory.h" 9 #include "base/memory/aligned_memory.h"
10 #include "media/base/video_frame.h" 10 #include "media/base/video_frame.h"
11 #include "third_party/libyuv/include/libyuv/scale.h" 11 #include "third_party/libjingle/source/talk/media/base/videoframe.h"
12 #include "third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.h"
13 #include "third_party/libyuv/include/libyuv/convert_from.h"
14
15 // Empty method used for keeping a reference to the original media::VideoFrame.
16 // The reference to |frame| is kept in the closure that calls this method.
17 void ReleaseOriginalFrame(const scoped_refptr<media::VideoFrame>& frame) {
18 }
19
20 // Thin map between an existing media::VideoFrame and cricket::VideoFrame to
21 // avoid premature deep copies.
22 // This implementation is only safe to use in a const context and should never
23 // be written to.
24 class VideoFrameWrapper : public cricket::VideoFrame {
tommi (sloooow) - chröme 2014/09/25 20:06:48 Assuming this is a single threaded class, can we a
magjed_chromium 2014/09/25 20:52:08 Yes, will fix.
25 public:
26 VideoFrameWrapper(const scoped_refptr<media::VideoFrame>& frame,
27 int64 elapsed_time)
28 : frame_(media::VideoFrame::WrapVideoFrame(
29 frame,
30 frame->visible_rect(),
31 frame->natural_size(),
32 base::Bind(&ReleaseOriginalFrame, frame))),
33 elapsed_time_(elapsed_time) {}
34
35 virtual VideoFrame* Copy() const OVERRIDE {
36 return new VideoFrameWrapper(frame_, elapsed_time_);
37 }
38
39 virtual size_t GetWidth() const OVERRIDE {
40 return static_cast<size_t>(frame_->visible_rect().width());
41 }
42
43 virtual size_t GetHeight() const OVERRIDE {
44 return static_cast<size_t>(frame_->visible_rect().height());
45 }
46
47 virtual const uint8* GetYPlane() const OVERRIDE {
48 return frame_->visible_data(media::VideoFrame::kYPlane);
49 }
50
51 virtual const uint8* GetUPlane() const OVERRIDE {
52 return frame_->visible_data(media::VideoFrame::kUPlane);
53 }
54
55 virtual const uint8* GetVPlane() const OVERRIDE {
56 return frame_->visible_data(media::VideoFrame::kVPlane);
57 }
58
59 virtual uint8* GetYPlane() OVERRIDE {
60 return frame_->visible_data(media::VideoFrame::kYPlane);
61 }
62
63 virtual uint8* GetUPlane() OVERRIDE {
64 return frame_->visible_data(media::VideoFrame::kUPlane);
65 }
66
67 virtual uint8* GetVPlane() OVERRIDE {
68 return frame_->visible_data(media::VideoFrame::kVPlane);
69 }
70
71 virtual int32 GetYPitch() const OVERRIDE {
72 return frame_->stride(media::VideoFrame::kYPlane);
73 }
74
75 virtual int32 GetUPitch() const OVERRIDE {
76 return frame_->stride(media::VideoFrame::kUPlane);
77 }
78
79 virtual int32 GetVPitch() const OVERRIDE {
80 return frame_->stride(media::VideoFrame::kVPlane);
81 }
82
83 virtual void* GetNativeHandle() const OVERRIDE { return NULL; }
84 virtual size_t GetPixelWidth() const OVERRIDE { return 1; }
85 virtual size_t GetPixelHeight() const OVERRIDE { return 1; }
86
87 virtual int64 GetElapsedTime() const OVERRIDE { return elapsed_time_; }
88
89 virtual int64 GetTimeStamp() const OVERRIDE {
90 return frame_->timestamp().InMicroseconds() *
91 base::Time::kNanosecondsPerMicrosecond;
92 }
93
94 virtual void SetElapsedTime(int64 elapsed_time) OVERRIDE {
95 elapsed_time_ = elapsed_time;
96 }
97
98 virtual void SetTimeStamp(int64 time_stamp) OVERRIDE {
99 // Round to closest microsecond.
100 frame_->set_timestamp(base::TimeDelta::FromMicroseconds(
101 (time_stamp + base::Time::kNanosecondsPerMicrosecond / 2) /
102 base::Time::kNanosecondsPerMicrosecond));
103 }
104
105 virtual int GetRotation() const OVERRIDE { return 0; }
106
107 // TODO(magjed): Refactor into base class
108 virtual size_t ConvertToRgbBuffer(uint32 to_fourcc,
109 uint8* buffer,
110 size_t size,
111 int stride_rgb) const OVERRIDE {
112 const size_t needed = std::abs(stride_rgb) * GetHeight();
113 if (size < needed) {
114 DLOG(WARNING) << "RGB buffer is not large enough";
115 return needed;
116 }
117
118 if (libyuv::ConvertFromI420(GetYPlane(),
119 GetYPitch(),
120 GetUPlane(),
121 GetUPitch(),
122 GetVPlane(),
123 GetVPitch(),
124 buffer,
125 stride_rgb,
126 static_cast<int>(GetWidth()),
127 static_cast<int>(GetHeight()),
128 to_fourcc)) {
129 DLOG(ERROR) << "RGB type not supported: " << to_fourcc;
130 return 0; // 0 indicates error
131 }
132 return needed;
133 }
134
135 // The rest of the public methods are NOTIMPLEMENTED.
136 virtual bool InitToBlack(int w,
137 int h,
138 size_t pixel_width,
139 size_t pixel_height,
140 int64 elapsed_time,
141 int64 time_stamp) OVERRIDE {
142 NOTIMPLEMENTED();
143 return false;
144 }
145
146 virtual bool Reset(uint32 fourcc,
147 int w,
148 int h,
149 int dw,
150 int dh,
151 uint8* sample,
152 size_t sample_size,
153 size_t pixel_width,
154 size_t pixel_height,
155 int64 elapsed_time,
156 int64 time_stamp,
157 int rotation) OVERRIDE {
158 NOTIMPLEMENTED();
159 return false;
160 }
161
162 virtual bool MakeExclusive() OVERRIDE {
163 NOTIMPLEMENTED();
164 return false;
165 }
166
167 virtual size_t CopyToBuffer(uint8* buffer, size_t size) const OVERRIDE {
168 NOTIMPLEMENTED();
169 return 0;
170 }
171
172 protected:
173 // TODO(magjed): Refactor as a static method in WebRtcVideoFrame
174 virtual VideoFrame* CreateEmptyFrame(int w,
175 int h,
176 size_t pixel_width,
177 size_t pixel_height,
178 int64 elapsed_time,
179 int64 time_stamp) const OVERRIDE {
180 VideoFrame* frame = new cricket::WebRtcVideoFrame();
181 frame->InitToBlack(
182 w, h, pixel_width, pixel_height, elapsed_time, time_stamp);
183 return frame;
184 }
185
186 private:
187 scoped_refptr<media::VideoFrame> frame_;
188 int64 elapsed_time_;
189 };
190
191 class DummyFactory : public cricket::VideoFrameFactory {
tommi (sloooow) - chröme 2014/09/25 20:06:48 can you add documentation for what context this cl
magjed_chromium 2014/09/25 20:52:08 The context for VideoFrameWrapper and DummyFactory
192 public:
193 DummyFactory(const scoped_refptr<media::VideoFrame>& frame,
194 int64_t elapsed_time)
195 : frame_(frame), elapsed_time_(elapsed_time) {}
196
197 virtual cricket::VideoFrame* CreateAliasedFrame(const cricket::CapturedFrame*,
198 int,
199 int) const OVERRIDE {
200 // Create a shallow cricket::VideoFrame wrapper around the
201 // media::VideoFrame. The caller has ownership over the returned frame.
202 return new VideoFrameWrapper(frame_, elapsed_time_);
203 }
204
205 private:
206 const scoped_refptr<media::VideoFrame>& frame_;
tommi (sloooow) - chröme 2014/09/25 20:06:48 is the reference intentional? I'd think it'd be s
magjed_chromium 2014/09/25 20:52:08 Ops, that is not intentional. Will fix.
207 const int64_t elapsed_time_;
208 };
12 209
13 namespace content { 210 namespace content {
14 211
15 WebRtcVideoCapturerAdapter::WebRtcVideoCapturerAdapter(bool is_screencast) 212 WebRtcVideoCapturerAdapter::WebRtcVideoCapturerAdapter(bool is_screencast)
16 : is_screencast_(is_screencast), 213 : is_screencast_(is_screencast), running_(false) {
17 running_(false),
18 buffer_(NULL),
19 buffer_size_(0) {
20 thread_checker_.DetachFromThread(); 214 thread_checker_.DetachFromThread();
21 } 215 }
22 216
23 WebRtcVideoCapturerAdapter::~WebRtcVideoCapturerAdapter() { 217 WebRtcVideoCapturerAdapter::~WebRtcVideoCapturerAdapter() {
24 DVLOG(3) << " WebRtcVideoCapturerAdapter::dtor"; 218 DVLOG(3) << " WebRtcVideoCapturerAdapter::dtor";
25 base::AlignedFree(buffer_);
26 } 219 }
27 220
28 cricket::CaptureState WebRtcVideoCapturerAdapter::Start( 221 cricket::CaptureState WebRtcVideoCapturerAdapter::Start(
29 const cricket::VideoFormat& capture_format) { 222 const cricket::VideoFormat& capture_format) {
30 DCHECK(thread_checker_.CalledOnValidThread()); 223 DCHECK(thread_checker_.CalledOnValidThread());
31 DCHECK(!running_); 224 DCHECK(!running_);
32 DVLOG(3) << " WebRtcVideoCapturerAdapter::Start w = " << capture_format.width 225 DVLOG(3) << " WebRtcVideoCapturerAdapter::Start w = " << capture_format.width
33 << " h = " << capture_format.height; 226 << " h = " << capture_format.height;
34 227
35 running_ = true; 228 running_ = true;
(...skipping 10 matching lines...) Expand all
46 } 239 }
47 240
48 bool WebRtcVideoCapturerAdapter::IsRunning() { 241 bool WebRtcVideoCapturerAdapter::IsRunning() {
49 DCHECK(thread_checker_.CalledOnValidThread()); 242 DCHECK(thread_checker_.CalledOnValidThread());
50 return running_; 243 return running_;
51 } 244 }
52 245
53 bool WebRtcVideoCapturerAdapter::GetPreferredFourccs( 246 bool WebRtcVideoCapturerAdapter::GetPreferredFourccs(
54 std::vector<uint32>* fourccs) { 247 std::vector<uint32>* fourccs) {
55 DCHECK(thread_checker_.CalledOnValidThread()); 248 DCHECK(thread_checker_.CalledOnValidThread());
56 if (!fourccs) 249 if (fourccs)
tommi (sloooow) - chröme 2014/09/25 20:06:48 Does it make sense to call this function with a NU
magjed_chromium 2014/09/25 20:52:08 We only have one real call to this function in Chr
57 return false; 250 fourccs->push_back(cricket::FOURCC_I420);
58 fourccs->push_back(cricket::FOURCC_I420); 251 return fourccs;
tommi (sloooow) - chröme 2014/09/25 20:06:48 hm... does this compile? :) I'm guessing you'd wa
magjed_chromium 2014/09/25 20:52:08 Yes, sorry about that. It compiled locally.
59 return true;
60 } 252 }
61 253
62 bool WebRtcVideoCapturerAdapter::IsScreencast() const { 254 bool WebRtcVideoCapturerAdapter::IsScreencast() const {
63 return is_screencast_; 255 return is_screencast_;
64 } 256 }
65 257
66 bool WebRtcVideoCapturerAdapter::GetBestCaptureFormat( 258 bool WebRtcVideoCapturerAdapter::GetBestCaptureFormat(
67 const cricket::VideoFormat& desired, 259 const cricket::VideoFormat& desired,
68 cricket::VideoFormat* best_format) { 260 cricket::VideoFormat* best_format) {
69 DCHECK(thread_checker_.CalledOnValidThread()); 261 DCHECK(thread_checker_.CalledOnValidThread());
(...skipping 20 matching lines...) Expand all
90 // Some types of sources support textures as output. Since connecting 282 // Some types of sources support textures as output. Since connecting
91 // sources and sinks do not check the format, we need to just ignore 283 // sources and sinks do not check the format, we need to just ignore
92 // formats that we can not handle. 284 // formats that we can not handle.
93 NOTREACHED(); 285 NOTREACHED();
94 return; 286 return;
95 } 287 }
96 288
97 if (first_frame_timestamp_ == media::kNoTimestamp()) 289 if (first_frame_timestamp_ == media::kNoTimestamp())
98 first_frame_timestamp_ = frame->timestamp(); 290 first_frame_timestamp_ = frame->timestamp();
99 291
100 cricket::CapturedFrame captured_frame; 292 const int64 elapsed_time =
101 captured_frame.width = frame->natural_size().width();
102 captured_frame.height = frame->natural_size().height();
103 // cricket::CapturedFrame time is in nanoseconds.
104 captured_frame.elapsed_time =
105 (frame->timestamp() - first_frame_timestamp_).InMicroseconds() * 293 (frame->timestamp() - first_frame_timestamp_).InMicroseconds() *
106 base::Time::kNanosecondsPerMicrosecond; 294 base::Time::kNanosecondsPerMicrosecond;
107 captured_frame.time_stamp = frame->timestamp().InMicroseconds() *
108 base::Time::kNanosecondsPerMicrosecond;
109 captured_frame.pixel_height = 1;
110 captured_frame.pixel_width = 1;
111 295
112 // TODO(perkj): 296 // Create a CapturedFrame that only contains header information, not the
113 // Libjingle expects contiguous layout of image planes as input. 297 // actual pixel data. The purpose of this charade is to satisfy the interface
114 // The only format where that is true in Chrome is I420 where the 298 // of cricket::VideoCapturer. We will inject the real cricket::VideoFrame with
115 // coded_size == natural_size(). 299 // a custom VideoFrameFactory instead.
116 if (frame->format() != media::VideoFrame::I420 || 300 cricket::CapturedFrame dummy_captured_frame;
117 frame->coded_size() != frame->natural_size()) { 301 dummy_captured_frame.width = frame->visible_rect().width();
118 // Cropping / Scaling and or switching UV planes is needed. 302 dummy_captured_frame.height = frame->visible_rect().height();
119 UpdateI420Buffer(frame); 303 dummy_captured_frame.elapsed_time = elapsed_time;
120 captured_frame.data = buffer_; 304 dummy_captured_frame.time_stamp = frame->timestamp().InMicroseconds() *
121 captured_frame.data_size = buffer_size_; 305 base::Time::kNanosecondsPerMicrosecond;
122 captured_frame.fourcc = cricket::FOURCC_I420; 306 dummy_captured_frame.pixel_height = 1;
123 } else { 307 dummy_captured_frame.pixel_width = 1;
124 captured_frame.fourcc = media::VideoFrame::I420 == frame->format() ? 308 dummy_captured_frame.rotation = 0;
125 cricket::FOURCC_I420 : cricket::FOURCC_YV12; 309 dummy_captured_frame.data = NULL;
126 captured_frame.data = frame->data(0); 310 dummy_captured_frame.data_size = cricket::CapturedFrame::kUnknownDataSize;
127 captured_frame.data_size = 311 dummy_captured_frame.fourcc = cricket::FOURCC_ANY;
128 media::VideoFrame::AllocationSize(frame->format(), frame->coded_size()); 312
129 } 313 // Inject the frame via the VideoFrameFractory.
314 set_frame_factory(new DummyFactory(frame, elapsed_time));
tommi (sloooow) - chröme 2014/09/25 20:06:48 does set_frame_factory accept a scoped_ptr? if not
magjed_chromium 2014/09/25 20:52:08 No, it does not accept a scoped_ptr. The definitio
130 315
131 // This signals to libJingle that a new VideoFrame is available. 316 // This signals to libJingle that a new VideoFrame is available.
132 // libJingle have no assumptions on what thread this signal come from. 317 // libJingle have no assumptions on what thread this signal come from.
133 SignalFrameCaptured(this, &captured_frame); 318 SignalFrameCaptured(this, &dummy_captured_frame);
134 }
135
136 void WebRtcVideoCapturerAdapter::UpdateI420Buffer(
137 const scoped_refptr<media::VideoFrame>& src) {
138 DCHECK(thread_checker_.CalledOnValidThread());
139 const int dst_width = src->natural_size().width();
140 const int dst_height = src->natural_size().height();
141 DCHECK(src->visible_rect().width() >= dst_width &&
142 src->visible_rect().height() >= dst_height);
143
144 const gfx::Rect& visible_rect = src->visible_rect();
145
146 const uint8* src_y = src->data(media::VideoFrame::kYPlane) +
147 visible_rect.y() * src->stride(media::VideoFrame::kYPlane) +
148 visible_rect.x();
149 const uint8* src_u = src->data(media::VideoFrame::kUPlane) +
150 visible_rect.y() / 2 * src->stride(media::VideoFrame::kUPlane) +
151 visible_rect.x() / 2;
152 const uint8* src_v = src->data(media::VideoFrame::kVPlane) +
153 visible_rect.y() / 2 * src->stride(media::VideoFrame::kVPlane) +
154 visible_rect.x() / 2;
155
156 const size_t dst_size =
157 media::VideoFrame::AllocationSize(src->format(), src->natural_size());
158
159 if (dst_size != buffer_size_) {
160 base::AlignedFree(buffer_);
161 buffer_ = reinterpret_cast<uint8*>(
162 base::AlignedAlloc(dst_size + media::VideoFrame::kFrameSizePadding,
163 media::VideoFrame::kFrameAddressAlignment));
164 buffer_size_ = dst_size;
165 }
166
167 uint8* dst_y = buffer_;
168 const int dst_stride_y = dst_width;
169 uint8* dst_u = dst_y + dst_width * dst_height;
170 const int dst_halfwidth = (dst_width + 1) / 2;
171 const int dst_halfheight = (dst_height + 1) / 2;
172 uint8* dst_v = dst_u + dst_halfwidth * dst_halfheight;
173
174 libyuv::I420Scale(src_y,
magjed_chromium 2014/09/25 19:21:23 Let the CoordinatedVideoAdapter take care of this
175 src->stride(media::VideoFrame::kYPlane),
176 src_u,
177 src->stride(media::VideoFrame::kUPlane),
178 src_v,
179 src->stride(media::VideoFrame::kVPlane),
180 visible_rect.width(),
181 visible_rect.height(),
182 dst_y,
183 dst_stride_y,
184 dst_u,
185 dst_halfwidth,
186 dst_v,
187 dst_halfwidth,
188 dst_width,
189 dst_height,
190 libyuv::kFilterBilinear);
191 } 319 }
192 320
193 } // namespace content 321 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698