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

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: perkj@s comments 2 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 "media/base/video_frame_pool.h"
12 #include "third_party/libjingle/source/talk/media/base/videoframe.h"
tommi (sloooow) - chröme 2014/10/16 22:33:05 can you remind me tomorrow to ask you about this?
13 #include "third_party/libjingle/source/talk/media/base/videoframefactory.h"
14 #include "third_party/libjingle/source/talk/media/webrtc/webrtcvideoframe.h"
15 #include "third_party/libyuv/include/libyuv/convert_from.h"
11 #include "third_party/libyuv/include/libyuv/scale.h" 16 #include "third_party/libyuv/include/libyuv/scale.h"
12 17
13 namespace content { 18 namespace content {
19 namespace {
20
21 // Empty method used for keeping a reference to the original media::VideoFrame.
22 // The reference to |frame| is kept in the closure that calls this method.
23 void ReleaseOriginalFrame(const scoped_refptr<media::VideoFrame>& frame) {
24 }
25
26 // Thin map between an existing media::VideoFrame and cricket::VideoFrame to
27 // avoid premature deep copies.
28 // This implementation is only safe to use in a const context and should never
29 // be written to.
30 class VideoFrameWrapper : public cricket::VideoFrame {
31 public:
32 VideoFrameWrapper(const scoped_refptr<media::VideoFrame>& frame,
33 int64 elapsed_time)
34 : frame_(media::VideoFrame::WrapVideoFrame(
35 frame,
36 frame->visible_rect(),
37 frame->natural_size(),
38 base::Bind(&ReleaseOriginalFrame, frame))),
39 elapsed_time_(elapsed_time) {}
40
41 virtual VideoFrame* Copy() const override {
42 DCHECK(thread_checker_.CalledOnValidThread());
43 return new VideoFrameWrapper(frame_, elapsed_time_);
44 }
45
46 virtual size_t GetWidth() const override {
47 DCHECK(thread_checker_.CalledOnValidThread());
48 return static_cast<size_t>(frame_->visible_rect().width());
49 }
50
51 virtual size_t GetHeight() const override {
52 DCHECK(thread_checker_.CalledOnValidThread());
53 return static_cast<size_t>(frame_->visible_rect().height());
54 }
55
56 virtual const uint8* GetYPlane() const override {
57 DCHECK(thread_checker_.CalledOnValidThread());
58 return frame_->visible_data(media::VideoFrame::kYPlane);
59 }
60
61 virtual const uint8* GetUPlane() const override {
62 DCHECK(thread_checker_.CalledOnValidThread());
63 return frame_->visible_data(media::VideoFrame::kUPlane);
64 }
65
66 virtual const uint8* GetVPlane() const override {
67 DCHECK(thread_checker_.CalledOnValidThread());
68 return frame_->visible_data(media::VideoFrame::kVPlane);
69 }
70
71 virtual uint8* GetYPlane() override {
72 DCHECK(thread_checker_.CalledOnValidThread());
73 return frame_->visible_data(media::VideoFrame::kYPlane);
74 }
75
76 virtual uint8* GetUPlane() override {
77 DCHECK(thread_checker_.CalledOnValidThread());
78 return frame_->visible_data(media::VideoFrame::kUPlane);
79 }
80
81 virtual uint8* GetVPlane() override {
82 DCHECK(thread_checker_.CalledOnValidThread());
83 return frame_->visible_data(media::VideoFrame::kVPlane);
84 }
85
86 virtual int32 GetYPitch() const override {
87 DCHECK(thread_checker_.CalledOnValidThread());
88 return frame_->stride(media::VideoFrame::kYPlane);
89 }
90
91 virtual int32 GetUPitch() const override {
92 DCHECK(thread_checker_.CalledOnValidThread());
93 return frame_->stride(media::VideoFrame::kUPlane);
94 }
95
96 virtual int32 GetVPitch() const override {
97 DCHECK(thread_checker_.CalledOnValidThread());
98 return frame_->stride(media::VideoFrame::kVPlane);
99 }
100
101 virtual void* GetNativeHandle() const override {
102 DCHECK(thread_checker_.CalledOnValidThread());
103 return NULL;
104 }
105
106 virtual size_t GetPixelWidth() const override {
107 DCHECK(thread_checker_.CalledOnValidThread());
108 return 1;
109 }
110 virtual size_t GetPixelHeight() const override {
111 DCHECK(thread_checker_.CalledOnValidThread());
112 return 1;
113 }
114
115 virtual int64 GetElapsedTime() const override {
116 DCHECK(thread_checker_.CalledOnValidThread());
117 return elapsed_time_;
118 }
119
120 virtual int64 GetTimeStamp() const override {
121 DCHECK(thread_checker_.CalledOnValidThread());
122 return frame_->timestamp().InMicroseconds() *
123 base::Time::kNanosecondsPerMicrosecond;
124 }
125
126 virtual void SetElapsedTime(int64 elapsed_time) override {
127 DCHECK(thread_checker_.CalledOnValidThread());
128 elapsed_time_ = elapsed_time;
129 }
130
131 virtual void SetTimeStamp(int64 time_stamp) override {
132 DCHECK(thread_checker_.CalledOnValidThread());
133 // Round to closest microsecond.
134 frame_->set_timestamp(base::TimeDelta::FromMicroseconds(
135 (time_stamp + base::Time::kNanosecondsPerMicrosecond / 2) /
136 base::Time::kNanosecondsPerMicrosecond));
137 }
138
139 virtual int GetRotation() const override {
140 DCHECK(thread_checker_.CalledOnValidThread());
141 return 0;
142 }
143
144 // TODO(magjed): Refactor into base class.
145 virtual size_t ConvertToRgbBuffer(uint32 to_fourcc,
146 uint8* buffer,
147 size_t size,
148 int stride_rgb) const override {
149 DCHECK(thread_checker_.CalledOnValidThread());
150 const size_t needed = std::abs(stride_rgb) * GetHeight();
151 if (size < needed) {
152 DLOG(WARNING) << "RGB buffer is not large enough";
153 return needed;
154 }
155
156 if (libyuv::ConvertFromI420(GetYPlane(),
157 GetYPitch(),
158 GetUPlane(),
159 GetUPitch(),
160 GetVPlane(),
161 GetVPitch(),
162 buffer,
163 stride_rgb,
164 static_cast<int>(GetWidth()),
165 static_cast<int>(GetHeight()),
166 to_fourcc)) {
167 DLOG(ERROR) << "RGB type not supported: " << to_fourcc;
168 return 0; // 0 indicates error
169 }
170 return needed;
171 }
172
173 // The rest of the public methods are NOTIMPLEMENTED.
174 virtual bool InitToBlack(int w,
175 int h,
176 size_t pixel_width,
177 size_t pixel_height,
178 int64 elapsed_time,
179 int64 time_stamp) override {
180 NOTIMPLEMENTED();
181 return false;
182 }
183
184 virtual bool Reset(uint32 fourcc,
185 int w,
186 int h,
187 int dw,
188 int dh,
189 uint8* sample,
190 size_t sample_size,
191 size_t pixel_width,
192 size_t pixel_height,
193 int64 elapsed_time,
194 int64 time_stamp,
195 int rotation) override {
196 NOTIMPLEMENTED();
197 return false;
198 }
199
200 virtual bool MakeExclusive() override {
201 NOTIMPLEMENTED();
202 return false;
203 }
204
205 virtual size_t CopyToBuffer(uint8* buffer, size_t size) const override {
206 NOTIMPLEMENTED();
207 return 0;
208 }
209
210 protected:
211 // TODO(magjed): Refactor as a static method in WebRtcVideoFrame.
212 virtual VideoFrame* CreateEmptyFrame(int w,
213 int h,
214 size_t pixel_width,
215 size_t pixel_height,
216 int64 elapsed_time,
217 int64 time_stamp) const override {
218 DCHECK(thread_checker_.CalledOnValidThread());
219 VideoFrame* frame = new cricket::WebRtcVideoFrame();
220 frame->InitToBlack(
221 w, h, pixel_width, pixel_height, elapsed_time, time_stamp);
222 return frame;
223 }
224
225 private:
226 scoped_refptr<media::VideoFrame> frame_;
227 int64 elapsed_time_;
228 base::ThreadChecker thread_checker_;
229 };
230
231 } // anonymous namespace
232
233 // A cricket::VideoFrameFactory for media::VideoFrame. The purpose of this
234 // class is to avoid a premature frame copy. A media::VideoFrame is injected
235 // with SetFrame, and converted into a cricket::VideoFrame with
236 // CreateAliasedFrame. SetFrame should be called before CreateAliasedFrame
237 // for every frame.
238 class WebRtcVideoCapturerAdapter::MediaVideoFrameFactory
239 : public cricket::VideoFrameFactory {
240 public:
241 void SetFrame(const scoped_refptr<media::VideoFrame>& frame,
242 int64_t elapsed_time) {
243 DCHECK(frame.get());
244 // Create a CapturedFrame that only contains header information, not the
245 // actual pixel data.
246 captured_frame_.width = frame->natural_size().width();
247 captured_frame_.height = frame->natural_size().height();
248 captured_frame_.elapsed_time = elapsed_time;
249 captured_frame_.time_stamp = frame->timestamp().InMicroseconds() *
250 base::Time::kNanosecondsPerMicrosecond;
251 captured_frame_.pixel_height = 1;
252 captured_frame_.pixel_width = 1;
253 captured_frame_.rotation = 0;
254 captured_frame_.data = NULL;
255 captured_frame_.data_size = cricket::CapturedFrame::kUnknownDataSize;
256 captured_frame_.fourcc = static_cast<uint32>(cricket::FOURCC_ANY);
257
258 frame_ = frame;
259 }
260
261 void ReleaseFrame() { frame_ = NULL; }
262
263 const cricket::CapturedFrame* GetCapturedFrame() const {
264 return &captured_frame_;
265 }
266
267 virtual cricket::VideoFrame* CreateAliasedFrame(
268 const cricket::CapturedFrame* captured_frame,
269 int dst_width,
270 int dst_height) const override {
271 // Check that captured_frame is actually our frame.
272 DCHECK(captured_frame == &captured_frame_);
273 DCHECK(frame_.get());
274
275 scoped_refptr<media::VideoFrame> video_frame = frame_;
276 // Check if scaling is needed.
277 if (dst_width != frame_->visible_rect().width() ||
278 dst_height != frame_->visible_rect().height()) {
279 video_frame =
280 scaled_frame_pool_.CreateFrame(media::VideoFrame::I420,
281 gfx::Size(dst_width, dst_height),
282 gfx::Rect(0, 0, dst_width, dst_height),
283 gfx::Size(dst_width, dst_height),
284 frame_->timestamp());
285 libyuv::I420Scale(frame_->visible_data(media::VideoFrame::kYPlane),
286 frame_->stride(media::VideoFrame::kYPlane),
287 frame_->visible_data(media::VideoFrame::kUPlane),
288 frame_->stride(media::VideoFrame::kUPlane),
289 frame_->visible_data(media::VideoFrame::kVPlane),
290 frame_->stride(media::VideoFrame::kVPlane),
291 frame_->visible_rect().width(),
292 frame_->visible_rect().height(),
293 video_frame->data(media::VideoFrame::kYPlane),
294 video_frame->stride(media::VideoFrame::kYPlane),
295 video_frame->data(media::VideoFrame::kUPlane),
296 video_frame->stride(media::VideoFrame::kUPlane),
297 video_frame->data(media::VideoFrame::kVPlane),
298 video_frame->stride(media::VideoFrame::kVPlane),
299 dst_width,
300 dst_height,
301 libyuv::kFilterBilinear);
302 }
303
304 // Create a shallow cricket::VideoFrame wrapper around the
305 // media::VideoFrame. The caller has ownership of the returned frame.
306 return new VideoFrameWrapper(video_frame, captured_frame_.elapsed_time);
307 }
308
309 private:
310 scoped_refptr<media::VideoFrame> frame_;
311 cricket::CapturedFrame captured_frame_;
312 // This is used only if scaling is needed.
313 mutable media::VideoFramePool scaled_frame_pool_;
314 };
14 315
15 WebRtcVideoCapturerAdapter::WebRtcVideoCapturerAdapter(bool is_screencast) 316 WebRtcVideoCapturerAdapter::WebRtcVideoCapturerAdapter(bool is_screencast)
16 : is_screencast_(is_screencast), 317 : is_screencast_(is_screencast),
17 running_(false), 318 running_(false),
18 buffer_(NULL), 319 first_frame_timestamp_(media::kNoTimestamp()),
19 buffer_size_(0) { 320 frame_factory_(new MediaVideoFrameFactory) {
20 thread_checker_.DetachFromThread(); 321 thread_checker_.DetachFromThread();
322 // The base class takes ownership of the frame factory.
323 set_frame_factory(frame_factory_);
21 } 324 }
22 325
23 WebRtcVideoCapturerAdapter::~WebRtcVideoCapturerAdapter() { 326 WebRtcVideoCapturerAdapter::~WebRtcVideoCapturerAdapter() {
24 DVLOG(3) << " WebRtcVideoCapturerAdapter::dtor"; 327 DVLOG(3) << " WebRtcVideoCapturerAdapter::dtor";
25 base::AlignedFree(buffer_);
26 } 328 }
27 329
28 cricket::CaptureState WebRtcVideoCapturerAdapter::Start( 330 cricket::CaptureState WebRtcVideoCapturerAdapter::Start(
29 const cricket::VideoFormat& capture_format) { 331 const cricket::VideoFormat& capture_format) {
30 DCHECK(thread_checker_.CalledOnValidThread()); 332 DCHECK(thread_checker_.CalledOnValidThread());
31 DCHECK(!running_); 333 DCHECK(!running_);
32 DVLOG(3) << " WebRtcVideoCapturerAdapter::Start w = " << capture_format.width 334 DVLOG(3) << " WebRtcVideoCapturerAdapter::Start w = " << capture_format.width
33 << " h = " << capture_format.height; 335 << " h = " << capture_format.height;
34 336
35 running_ = true; 337 running_ = true;
(...skipping 10 matching lines...) Expand all
46 } 348 }
47 349
48 bool WebRtcVideoCapturerAdapter::IsRunning() { 350 bool WebRtcVideoCapturerAdapter::IsRunning() {
49 DCHECK(thread_checker_.CalledOnValidThread()); 351 DCHECK(thread_checker_.CalledOnValidThread());
50 return running_; 352 return running_;
51 } 353 }
52 354
53 bool WebRtcVideoCapturerAdapter::GetPreferredFourccs( 355 bool WebRtcVideoCapturerAdapter::GetPreferredFourccs(
54 std::vector<uint32>* fourccs) { 356 std::vector<uint32>* fourccs) {
55 DCHECK(thread_checker_.CalledOnValidThread()); 357 DCHECK(thread_checker_.CalledOnValidThread());
56 if (!fourccs) 358 DCHECK(!fourccs || fourccs->empty());
57 return false; 359 if (fourccs)
58 fourccs->push_back(cricket::FOURCC_I420); 360 fourccs->push_back(cricket::FOURCC_I420);
59 return true; 361 return fourccs != NULL;
60 } 362 }
61 363
62 bool WebRtcVideoCapturerAdapter::IsScreencast() const { 364 bool WebRtcVideoCapturerAdapter::IsScreencast() const {
63 return is_screencast_; 365 return is_screencast_;
64 } 366 }
65 367
66 bool WebRtcVideoCapturerAdapter::GetBestCaptureFormat( 368 bool WebRtcVideoCapturerAdapter::GetBestCaptureFormat(
67 const cricket::VideoFormat& desired, 369 const cricket::VideoFormat& desired,
68 cricket::VideoFormat* best_format) { 370 cricket::VideoFormat* best_format) {
69 DCHECK(thread_checker_.CalledOnValidThread()); 371 DCHECK(thread_checker_.CalledOnValidThread());
(...skipping 20 matching lines...) Expand all
90 // Some types of sources support textures as output. Since connecting 392 // Some types of sources support textures as output. Since connecting
91 // sources and sinks do not check the format, we need to just ignore 393 // sources and sinks do not check the format, we need to just ignore
92 // formats that we can not handle. 394 // formats that we can not handle.
93 NOTREACHED(); 395 NOTREACHED();
94 return; 396 return;
95 } 397 }
96 398
97 if (first_frame_timestamp_ == media::kNoTimestamp()) 399 if (first_frame_timestamp_ == media::kNoTimestamp())
98 first_frame_timestamp_ = frame->timestamp(); 400 first_frame_timestamp_ = frame->timestamp();
99 401
100 cricket::CapturedFrame captured_frame; 402 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() * 403 (frame->timestamp() - first_frame_timestamp_).InMicroseconds() *
106 base::Time::kNanosecondsPerMicrosecond; 404 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 405
112 // TODO(perkj): 406 // Inject the frame via the VideoFrameFractory.
113 // Libjingle expects contiguous layout of image planes as input. 407 DCHECK(frame_factory_ == frame_factory());
114 // The only format where that is true in Chrome is I420 where the 408 frame_factory_->SetFrame(frame, elapsed_time);
115 // coded_size == natural_size().
116 if (frame->format() != media::VideoFrame::I420 ||
117 frame->coded_size() != frame->natural_size()) {
118 // Cropping / Scaling and or switching UV planes is needed.
119 UpdateI420Buffer(frame);
120 captured_frame.data = buffer_;
121 captured_frame.data_size = buffer_size_;
122 captured_frame.fourcc = cricket::FOURCC_I420;
123 } else {
124 captured_frame.fourcc = media::VideoFrame::I420 == frame->format() ?
125 cricket::FOURCC_I420 : cricket::FOURCC_YV12;
126 captured_frame.data = frame->data(0);
127 captured_frame.data_size =
128 media::VideoFrame::AllocationSize(frame->format(), frame->coded_size());
129 }
130 409
131 // This signals to libJingle that a new VideoFrame is available. 410 // This signals to libJingle that a new VideoFrame is available.
132 // libJingle have no assumptions on what thread this signal come from. 411 SignalFrameCaptured(this, frame_factory_->GetCapturedFrame());
133 SignalFrameCaptured(this, &captured_frame);
134 }
135 412
136 void WebRtcVideoCapturerAdapter::UpdateI420Buffer( 413 frame_factory_->ReleaseFrame(); // Release the frame ASAP.
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,
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 } 414 }
192 415
193 } // namespace content 416 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698