Blink roll 25b6bd3a7a131ffe68d809546ad1a20707915cdc:3a503f41ae42e5b79cfcd2ff10e65afde...
[chromium-blink-merge.git] / media / base / video_frame.cc
blobabea883446669be3e88c1b27bf6c5a4a22d5a277
1 // Copyright (c) 2012 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 "media/base/video_frame.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/logging.h"
12 #include "base/memory/aligned_memory.h"
13 #include "base/strings/string_piece.h"
14 #include "gpu/command_buffer/common/mailbox_holder.h"
15 #include "media/base/limits.h"
16 #include "media/base/video_util.h"
17 #include "ui/gfx/point.h"
19 #if !defined(MEDIA_FOR_CAST_IOS)
20 #include "third_party/skia/include/core/SkBitmap.h"
21 #endif
23 namespace media {
25 static bool IsPowerOfTwo(size_t x) {
26 return x != 0 && (x & (x - 1)) == 0;
29 static inline size_t RoundUp(size_t value, size_t alignment) {
30 DCHECK(IsPowerOfTwo(alignment));
31 return ((value + (alignment - 1)) & ~(alignment - 1));
34 static inline size_t RoundDown(size_t value, size_t alignment) {
35 DCHECK(IsPowerOfTwo(alignment));
36 return value & ~(alignment - 1);
39 // Returns the pixel size per element for given |plane| and |format|. E.g. 2x2
40 // for the U-plane in I420.
41 static gfx::Size SampleSize(VideoFrame::Format format, size_t plane) {
42 DCHECK(VideoFrame::IsValidPlane(plane, format));
44 switch (plane) {
45 case VideoFrame::kYPlane:
46 case VideoFrame::kAPlane:
47 return gfx::Size(1, 1);
49 case VideoFrame::kUPlane: // and VideoFrame::kUVPlane:
50 case VideoFrame::kVPlane:
51 switch (format) {
52 case VideoFrame::YV24:
53 return gfx::Size(1, 1);
55 case VideoFrame::YV16:
56 return gfx::Size(2, 1);
58 case VideoFrame::YV12:
59 case VideoFrame::YV12J:
60 case VideoFrame::I420:
61 case VideoFrame::YV12A:
62 case VideoFrame::NV12:
63 return gfx::Size(2, 2);
65 case VideoFrame::UNKNOWN:
66 #if defined(VIDEO_HOLE)
67 case VideoFrame::HOLE:
68 #endif // defined(VIDEO_HOLE)
69 case VideoFrame::NATIVE_TEXTURE:
70 break;
73 NOTREACHED();
74 return gfx::Size();
77 // Return the alignment for the whole frame, calculated as the max of the
78 // alignment for each individual plane.
79 static gfx::Size CommonAlignment(VideoFrame::Format format) {
80 int max_sample_width = 0;
81 int max_sample_height = 0;
82 for (size_t plane = 0; plane < VideoFrame::NumPlanes(format); ++plane) {
83 const gfx::Size sample_size = SampleSize(format, plane);
84 max_sample_width = std::max(max_sample_width, sample_size.width());
85 max_sample_height = std::max(max_sample_height, sample_size.height());
87 return gfx::Size(max_sample_width, max_sample_height);
90 // Returns the number of bytes per element for given |plane| and |format|. E.g.
91 // 2 for the UV plane in NV12.
92 static int BytesPerElement(VideoFrame::Format format, size_t plane) {
93 DCHECK(VideoFrame::IsValidPlane(plane, format));
94 return (format == VideoFrame::NV12 && plane == VideoFrame::kUVPlane) ? 2 : 1;
97 // Rounds up |coded_size| if necessary for |format|.
98 static gfx::Size AdjustCodedSize(VideoFrame::Format format,
99 const gfx::Size& coded_size) {
100 const gfx::Size alignment = CommonAlignment(format);
101 return gfx::Size(RoundUp(coded_size.width(), alignment.width()),
102 RoundUp(coded_size.height(), alignment.height()));
105 // static
106 scoped_refptr<VideoFrame> VideoFrame::CreateFrame(
107 VideoFrame::Format format,
108 const gfx::Size& coded_size,
109 const gfx::Rect& visible_rect,
110 const gfx::Size& natural_size,
111 base::TimeDelta timestamp) {
112 DCHECK(format != VideoFrame::UNKNOWN &&
113 format != VideoFrame::NV12 &&
114 format != VideoFrame::NATIVE_TEXTURE);
115 #if defined(VIDEO_HOLE)
116 DCHECK(format != VideoFrame::HOLE);
117 #endif // defined(VIDEO_HOLE)
119 // Since we're creating a new YUV frame (and allocating memory for it
120 // ourselves), we can pad the requested |coded_size| if necessary if the
121 // request does not line up on sample boundaries.
122 const gfx::Size new_coded_size = AdjustCodedSize(format, coded_size);
123 DCHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size));
125 scoped_refptr<VideoFrame> frame(
126 new VideoFrame(format,
127 new_coded_size,
128 visible_rect,
129 natural_size,
130 scoped_ptr<gpu::MailboxHolder>(),
131 timestamp,
132 false));
133 frame->AllocateYUV();
134 return frame;
137 // static
138 std::string VideoFrame::FormatToString(VideoFrame::Format format) {
139 switch (format) {
140 case VideoFrame::UNKNOWN:
141 return "UNKNOWN";
142 case VideoFrame::YV12:
143 return "YV12";
144 case VideoFrame::YV16:
145 return "YV16";
146 case VideoFrame::I420:
147 return "I420";
148 case VideoFrame::NATIVE_TEXTURE:
149 return "NATIVE_TEXTURE";
150 #if defined(VIDEO_HOLE)
151 case VideoFrame::HOLE:
152 return "HOLE";
153 #endif // defined(VIDEO_HOLE)
154 case VideoFrame::YV12A:
155 return "YV12A";
156 case VideoFrame::YV12J:
157 return "YV12J";
158 case VideoFrame::NV12:
159 return "NV12";
160 case VideoFrame::YV24:
161 return "YV24";
163 NOTREACHED() << "Invalid videoframe format provided: " << format;
164 return "";
167 // static
168 bool VideoFrame::IsValidConfig(VideoFrame::Format format,
169 const gfx::Size& coded_size,
170 const gfx::Rect& visible_rect,
171 const gfx::Size& natural_size) {
172 // Check maximum limits for all formats.
173 if (coded_size.GetArea() > limits::kMaxCanvas ||
174 coded_size.width() > limits::kMaxDimension ||
175 coded_size.height() > limits::kMaxDimension ||
176 visible_rect.x() < 0 || visible_rect.y() < 0 ||
177 visible_rect.right() > coded_size.width() ||
178 visible_rect.bottom() > coded_size.height() ||
179 natural_size.GetArea() > limits::kMaxCanvas ||
180 natural_size.width() > limits::kMaxDimension ||
181 natural_size.height() > limits::kMaxDimension)
182 return false;
184 // Check format-specific width/height requirements.
185 switch (format) {
186 case VideoFrame::UNKNOWN:
187 return (coded_size.IsEmpty() && visible_rect.IsEmpty() &&
188 natural_size.IsEmpty());
190 // NATIVE_TEXTURE and HOLE have no software-allocated buffers and are
191 // allowed to skip the below check.
192 case VideoFrame::NATIVE_TEXTURE:
193 #if defined(VIDEO_HOLE)
194 case VideoFrame::HOLE:
195 #endif // defined(VIDEO_HOLE)
196 return true;
198 case VideoFrame::YV24:
199 case VideoFrame::YV12:
200 case VideoFrame::YV12J:
201 case VideoFrame::I420:
202 case VideoFrame::YV12A:
203 case VideoFrame::NV12:
204 case VideoFrame::YV16:
205 // Check that software-allocated buffer formats are aligned correctly and
206 // not empty.
207 const gfx::Size alignment = CommonAlignment(format);
208 return RoundUp(visible_rect.right(), alignment.width()) <=
209 static_cast<size_t>(coded_size.width()) &&
210 RoundUp(visible_rect.bottom(), alignment.height()) <=
211 static_cast<size_t>(coded_size.height()) &&
212 !coded_size.IsEmpty() && !visible_rect.IsEmpty() &&
213 !natural_size.IsEmpty();
216 NOTREACHED();
217 return false;
220 // static
221 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
222 scoped_ptr<gpu::MailboxHolder> mailbox_holder,
223 const ReleaseMailboxCB& mailbox_holder_release_cb,
224 const gfx::Size& coded_size,
225 const gfx::Rect& visible_rect,
226 const gfx::Size& natural_size,
227 base::TimeDelta timestamp,
228 const ReadPixelsCB& read_pixels_cb) {
229 scoped_refptr<VideoFrame> frame(new VideoFrame(NATIVE_TEXTURE,
230 coded_size,
231 visible_rect,
232 natural_size,
233 mailbox_holder.Pass(),
234 timestamp,
235 false));
236 frame->mailbox_holder_release_cb_ = mailbox_holder_release_cb;
237 frame->read_pixels_cb_ = read_pixels_cb;
239 return frame;
242 #if !defined(MEDIA_FOR_CAST_IOS)
243 void VideoFrame::ReadPixelsFromNativeTexture(const SkBitmap& pixels) {
244 DCHECK_EQ(format_, NATIVE_TEXTURE);
245 if (!read_pixels_cb_.is_null())
246 read_pixels_cb_.Run(pixels);
248 #endif
250 // static
251 scoped_refptr<VideoFrame> VideoFrame::WrapExternalPackedMemory(
252 Format format,
253 const gfx::Size& coded_size,
254 const gfx::Rect& visible_rect,
255 const gfx::Size& natural_size,
256 uint8* data,
257 size_t data_size,
258 base::SharedMemoryHandle handle,
259 base::TimeDelta timestamp,
260 const base::Closure& no_longer_needed_cb) {
261 const gfx::Size new_coded_size = AdjustCodedSize(format, coded_size);
263 if (!IsValidConfig(format, new_coded_size, visible_rect, natural_size))
264 return NULL;
265 if (data_size < AllocationSize(format, new_coded_size))
266 return NULL;
268 switch (format) {
269 case VideoFrame::I420: {
270 scoped_refptr<VideoFrame> frame(
271 new VideoFrame(format,
272 new_coded_size,
273 visible_rect,
274 natural_size,
275 scoped_ptr<gpu::MailboxHolder>(),
276 timestamp,
277 false));
278 frame->shared_memory_handle_ = handle;
279 frame->strides_[kYPlane] = new_coded_size.width();
280 frame->strides_[kUPlane] = new_coded_size.width() / 2;
281 frame->strides_[kVPlane] = new_coded_size.width() / 2;
282 frame->data_[kYPlane] = data;
283 frame->data_[kUPlane] = data + new_coded_size.GetArea();
284 frame->data_[kVPlane] = data + (new_coded_size.GetArea() * 5 / 4);
285 frame->no_longer_needed_cb_ = no_longer_needed_cb;
286 return frame;
288 default:
289 NOTIMPLEMENTED();
290 return NULL;
294 #if defined(OS_POSIX)
295 // static
296 scoped_refptr<VideoFrame> VideoFrame::WrapExternalDmabufs(
297 Format format,
298 const gfx::Size& coded_size,
299 const gfx::Rect& visible_rect,
300 const gfx::Size& natural_size,
301 const std::vector<int> dmabuf_fds,
302 base::TimeDelta timestamp,
303 const base::Closure& no_longer_needed_cb) {
304 if (!IsValidConfig(format, coded_size, visible_rect, natural_size))
305 return NULL;
307 if (dmabuf_fds.size() != NumPlanes(format)) {
308 LOG(FATAL) << "Not enough dmabuf fds provided!";
309 return NULL;
312 scoped_refptr<VideoFrame> frame(
313 new VideoFrame(format,
314 coded_size,
315 visible_rect,
316 natural_size,
317 scoped_ptr<gpu::MailboxHolder>(),
318 timestamp,
319 false));
321 for (size_t i = 0; i < dmabuf_fds.size(); ++i) {
322 int duped_fd = HANDLE_EINTR(dup(dmabuf_fds[i]));
323 if (duped_fd == -1) {
324 // The already-duped in previous iterations fds will be closed when
325 // the partially-created frame drops out of scope here.
326 DLOG(ERROR) << "Failed duplicating a dmabuf fd";
327 return NULL;
330 frame->dmabuf_fds_[i].reset(duped_fd);
331 // Data is accessible only via fds.
332 frame->data_[i] = NULL;
333 frame->strides_[i] = 0;
336 frame->no_longer_needed_cb_ = no_longer_needed_cb;
337 return frame;
339 #endif
341 #if defined(OS_MACOSX)
342 // static
343 scoped_refptr<VideoFrame> VideoFrame::WrapCVPixelBuffer(
344 CVPixelBufferRef cv_pixel_buffer,
345 base::TimeDelta timestamp) {
346 DCHECK(cv_pixel_buffer);
347 DCHECK(CFGetTypeID(cv_pixel_buffer) == CVPixelBufferGetTypeID());
349 const OSType cv_format = CVPixelBufferGetPixelFormatType(cv_pixel_buffer);
350 Format format;
351 // There are very few compatible CV pixel formats, so just check each.
352 if (cv_format == kCVPixelFormatType_420YpCbCr8Planar) {
353 format = Format::I420;
354 } else if (cv_format == kCVPixelFormatType_444YpCbCr8) {
355 format = Format::YV24;
356 } else if (cv_format == '420v') {
357 // TODO(jfroy): Use kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange when the
358 // minimum OS X and iOS SDKs permits it.
359 format = Format::NV12;
360 } else {
361 DLOG(ERROR) << "CVPixelBuffer format not supported: " << cv_format;
362 return NULL;
365 const gfx::Size coded_size(CVImageBufferGetEncodedSize(cv_pixel_buffer));
366 const gfx::Rect visible_rect(CVImageBufferGetCleanRect(cv_pixel_buffer));
367 const gfx::Size natural_size(CVImageBufferGetDisplaySize(cv_pixel_buffer));
369 if (!IsValidConfig(format, coded_size, visible_rect, natural_size))
370 return NULL;
372 scoped_refptr<VideoFrame> frame(
373 new VideoFrame(format,
374 coded_size,
375 visible_rect,
376 natural_size,
377 scoped_ptr<gpu::MailboxHolder>(),
378 timestamp,
379 false));
381 frame->cv_pixel_buffer_.reset(cv_pixel_buffer, base::scoped_policy::RETAIN);
382 return frame;
384 #endif
386 // static
387 scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvData(
388 Format format,
389 const gfx::Size& coded_size,
390 const gfx::Rect& visible_rect,
391 const gfx::Size& natural_size,
392 int32 y_stride,
393 int32 u_stride,
394 int32 v_stride,
395 uint8* y_data,
396 uint8* u_data,
397 uint8* v_data,
398 base::TimeDelta timestamp,
399 const base::Closure& no_longer_needed_cb) {
400 const gfx::Size new_coded_size = AdjustCodedSize(format, coded_size);
401 CHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size));
403 scoped_refptr<VideoFrame> frame(
404 new VideoFrame(format,
405 new_coded_size,
406 visible_rect,
407 natural_size,
408 scoped_ptr<gpu::MailboxHolder>(),
409 timestamp,
410 false));
411 frame->strides_[kYPlane] = y_stride;
412 frame->strides_[kUPlane] = u_stride;
413 frame->strides_[kVPlane] = v_stride;
414 frame->data_[kYPlane] = y_data;
415 frame->data_[kUPlane] = u_data;
416 frame->data_[kVPlane] = v_data;
417 frame->no_longer_needed_cb_ = no_longer_needed_cb;
418 return frame;
421 // static
422 scoped_refptr<VideoFrame> VideoFrame::WrapVideoFrame(
423 const scoped_refptr<VideoFrame>& frame,
424 const gfx::Rect& visible_rect,
425 const gfx::Size& natural_size,
426 const base::Closure& no_longer_needed_cb) {
427 // NATIVE_TEXTURE frames need mailbox info propagated, and there's no support
428 // for that here yet, see http://crbug/362521.
429 CHECK_NE(frame->format(), NATIVE_TEXTURE);
431 DCHECK(frame->visible_rect().Contains(visible_rect));
432 scoped_refptr<VideoFrame> wrapped_frame(
433 new VideoFrame(frame->format(),
434 frame->coded_size(),
435 visible_rect,
436 natural_size,
437 scoped_ptr<gpu::MailboxHolder>(),
438 frame->timestamp(),
439 frame->end_of_stream()));
441 for (size_t i = 0; i < NumPlanes(frame->format()); ++i) {
442 wrapped_frame->strides_[i] = frame->stride(i);
443 wrapped_frame->data_[i] = frame->data(i);
446 wrapped_frame->no_longer_needed_cb_ = no_longer_needed_cb;
447 return wrapped_frame;
450 // static
451 scoped_refptr<VideoFrame> VideoFrame::CreateEOSFrame() {
452 return new VideoFrame(VideoFrame::UNKNOWN,
453 gfx::Size(),
454 gfx::Rect(),
455 gfx::Size(),
456 scoped_ptr<gpu::MailboxHolder>(),
457 kNoTimestamp(),
458 true);
461 // static
462 scoped_refptr<VideoFrame> VideoFrame::CreateColorFrame(
463 const gfx::Size& size,
464 uint8 y, uint8 u, uint8 v,
465 base::TimeDelta timestamp) {
466 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
467 VideoFrame::YV12, size, gfx::Rect(size), size, timestamp);
468 FillYUV(frame.get(), y, u, v);
469 return frame;
472 // static
473 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(const gfx::Size& size) {
474 const uint8 kBlackY = 0x00;
475 const uint8 kBlackUV = 0x80;
476 const base::TimeDelta kZero;
477 return CreateColorFrame(size, kBlackY, kBlackUV, kBlackUV, kZero);
480 // static
481 scoped_refptr<VideoFrame> VideoFrame::CreateTransparentFrame(
482 const gfx::Size& size) {
483 const uint8 kBlackY = 0x00;
484 const uint8 kBlackUV = 0x00;
485 const uint8 kTransparentA = 0x00;
486 const base::TimeDelta kZero;
487 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
488 VideoFrame::YV12A, size, gfx::Rect(size), size, kZero);
489 FillYUVA(frame.get(), kBlackY, kBlackUV, kBlackUV, kTransparentA);
490 return frame;
493 #if defined(VIDEO_HOLE)
494 // This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not
495 // maintained by the general compositor team. Please contact the following
496 // people instead:
498 // wonsik@chromium.org
499 // ycheo@chromium.org
501 // static
502 scoped_refptr<VideoFrame> VideoFrame::CreateHoleFrame(
503 const gfx::Size& size) {
504 DCHECK(IsValidConfig(VideoFrame::HOLE, size, gfx::Rect(size), size));
505 scoped_refptr<VideoFrame> frame(
506 new VideoFrame(VideoFrame::HOLE,
507 size,
508 gfx::Rect(size),
509 size,
510 scoped_ptr<gpu::MailboxHolder>(),
511 base::TimeDelta(),
512 false));
513 return frame;
515 #endif // defined(VIDEO_HOLE)
517 // static
518 size_t VideoFrame::NumPlanes(Format format) {
519 switch (format) {
520 case VideoFrame::NATIVE_TEXTURE:
521 #if defined(VIDEO_HOLE)
522 case VideoFrame::HOLE:
523 #endif // defined(VIDEO_HOLE)
524 return 0;
525 case VideoFrame::NV12:
526 return 2;
527 case VideoFrame::YV12:
528 case VideoFrame::YV16:
529 case VideoFrame::I420:
530 case VideoFrame::YV12J:
531 case VideoFrame::YV24:
532 return 3;
533 case VideoFrame::YV12A:
534 return 4;
535 case VideoFrame::UNKNOWN:
536 break;
538 NOTREACHED() << "Unsupported video frame format: " << format;
539 return 0;
543 // static
544 size_t VideoFrame::AllocationSize(Format format, const gfx::Size& coded_size) {
545 size_t total = 0;
546 for (size_t i = 0; i < NumPlanes(format); ++i)
547 total += PlaneAllocationSize(format, i, coded_size);
548 return total;
551 // static
552 gfx::Size VideoFrame::PlaneSize(Format format,
553 size_t plane,
554 const gfx::Size& coded_size) {
555 DCHECK(IsValidPlane(plane, format));
557 // Align to multiple-of-two size overall. This ensures that non-subsampled
558 // planes can be addressed by pixel with the same scaling as the subsampled
559 // planes.
560 const int width = RoundUp(coded_size.width(), 2);
561 const int height = RoundUp(coded_size.height(), 2);
563 const gfx::Size subsample = SampleSize(format, plane);
564 DCHECK(width % subsample.width() == 0);
565 DCHECK(height % subsample.height() == 0);
566 return gfx::Size(BytesPerElement(format, plane) * width / subsample.width(),
567 height / subsample.height());
570 size_t VideoFrame::PlaneAllocationSize(Format format,
571 size_t plane,
572 const gfx::Size& coded_size) {
573 // VideoFrame formats are (so far) all YUV and 1 byte per sample.
574 return PlaneSize(format, plane, coded_size).GetArea();
577 // static
578 int VideoFrame::PlaneHorizontalBitsPerPixel(Format format, size_t plane) {
579 DCHECK(IsValidPlane(plane, format));
580 const int bits_per_element = 8 * BytesPerElement(format, plane);
581 const int pixels_per_element = SampleSize(format, plane).GetArea();
582 DCHECK(bits_per_element % pixels_per_element == 0);
583 return bits_per_element / pixels_per_element;
586 // Release data allocated by AllocateYUV().
587 static void ReleaseData(uint8* data) {
588 DCHECK(data);
589 base::AlignedFree(data);
592 void VideoFrame::AllocateYUV() {
593 DCHECK(format_ == YV12 || format_ == YV16 || format_ == YV12A ||
594 format_ == I420 || format_ == YV12J || format_ == YV24);
595 COMPILE_ASSERT(0 == kYPlane, y_plane_data_must_be_index_0);
597 size_t data_size = 0;
598 size_t offset[kMaxPlanes];
599 for (size_t plane = 0; plane < VideoFrame::NumPlanes(format_); ++plane) {
600 // The *2 in alignment for height is because some formats (e.g. h264) allow
601 // interlaced coding, and then the size needs to be a multiple of two
602 // macroblocks (vertically). See
603 // libavcodec/utils.c:avcodec_align_dimensions2().
604 const size_t height = RoundUp(rows(plane), kFrameSizeAlignment * 2);
605 strides_[plane] = RoundUp(row_bytes(plane), kFrameSizeAlignment);
606 offset[plane] = data_size;
607 data_size += height * strides_[plane];
610 // The extra line of UV being allocated is because h264 chroma MC
611 // overreads by one line in some cases, see libavcodec/utils.c:
612 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
613 // put_h264_chroma_mc4_ssse3().
614 DCHECK(IsValidPlane(kUPlane, format_));
615 data_size += strides_[kUPlane] + kFrameSizePadding;
617 // FFmpeg expects the initialize allocation to be zero-initialized. Failure
618 // to do so can lead to unitialized value usage. See http://crbug.com/390941
619 uint8* data = reinterpret_cast<uint8*>(
620 base::AlignedAlloc(data_size, kFrameAddressAlignment));
621 memset(data, 0, data_size);
623 for (size_t plane = 0; plane < VideoFrame::NumPlanes(format_); ++plane)
624 data_[plane] = data + offset[plane];
626 no_longer_needed_cb_ = base::Bind(&ReleaseData, data);
629 VideoFrame::VideoFrame(VideoFrame::Format format,
630 const gfx::Size& coded_size,
631 const gfx::Rect& visible_rect,
632 const gfx::Size& natural_size,
633 scoped_ptr<gpu::MailboxHolder> mailbox_holder,
634 base::TimeDelta timestamp,
635 bool end_of_stream)
636 : format_(format),
637 coded_size_(coded_size),
638 visible_rect_(visible_rect),
639 natural_size_(natural_size),
640 mailbox_holder_(mailbox_holder.Pass()),
641 shared_memory_handle_(base::SharedMemory::NULLHandle()),
642 timestamp_(timestamp),
643 release_sync_point_(0),
644 end_of_stream_(end_of_stream) {
645 DCHECK(IsValidConfig(format_, coded_size_, visible_rect_, natural_size_));
647 memset(&strides_, 0, sizeof(strides_));
648 memset(&data_, 0, sizeof(data_));
651 VideoFrame::~VideoFrame() {
652 if (!mailbox_holder_release_cb_.is_null()) {
653 uint32 release_sync_point;
655 // To ensure that changes to |release_sync_point_| are visible on this
656 // thread (imply a memory barrier).
657 base::AutoLock locker(release_sync_point_lock_);
658 release_sync_point = release_sync_point_;
660 base::ResetAndReturn(&mailbox_holder_release_cb_).Run(release_sync_point);
662 if (!no_longer_needed_cb_.is_null())
663 base::ResetAndReturn(&no_longer_needed_cb_).Run();
666 // static
667 bool VideoFrame::IsValidPlane(size_t plane, VideoFrame::Format format) {
668 return (plane < NumPlanes(format));
671 int VideoFrame::stride(size_t plane) const {
672 DCHECK(IsValidPlane(plane, format_));
673 return strides_[plane];
676 // static
677 size_t VideoFrame::RowBytes(size_t plane,
678 VideoFrame::Format format,
679 int width) {
680 DCHECK(IsValidPlane(plane, format));
681 return BytesPerElement(format, plane) * Columns(plane, format, width);
684 int VideoFrame::row_bytes(size_t plane) const {
685 return RowBytes(plane, format_, coded_size_.width());
688 // static
689 size_t VideoFrame::Rows(size_t plane, VideoFrame::Format format, int height) {
690 DCHECK(IsValidPlane(plane, format));
691 const int sample_height = SampleSize(format, plane).height();
692 return RoundUp(height, sample_height) / sample_height;
695 // static
696 size_t VideoFrame::Columns(size_t plane, Format format, int width) {
697 DCHECK(IsValidPlane(plane, format));
698 const int sample_width = SampleSize(format, plane).width();
699 return RoundUp(width, sample_width) / sample_width;
702 int VideoFrame::rows(size_t plane) const {
703 return Rows(plane, format_, coded_size_.height());
706 const uint8* VideoFrame::data(size_t plane) const {
707 DCHECK(IsValidPlane(plane, format_));
708 return data_[plane];
711 uint8* VideoFrame::data(size_t plane) {
712 DCHECK(IsValidPlane(plane, format_));
713 return data_[plane];
716 const uint8* VideoFrame::visible_data(size_t plane) const {
717 DCHECK(IsValidPlane(plane, format_));
719 // Calculate an offset that is properly aligned for all planes.
720 const gfx::Size alignment = CommonAlignment(format_);
721 const gfx::Point offset(RoundDown(visible_rect_.x(), alignment.width()),
722 RoundDown(visible_rect_.y(), alignment.height()));
724 const gfx::Size subsample = SampleSize(format_, plane);
725 DCHECK(offset.x() % subsample.width() == 0);
726 DCHECK(offset.y() % subsample.height() == 0);
727 return data(plane) +
728 stride(plane) * (offset.y() / subsample.height()) + // Row offset.
729 BytesPerElement(format_, plane) * // Column offset.
730 (offset.x() / subsample.width());
733 uint8* VideoFrame::visible_data(size_t plane) {
734 return const_cast<uint8*>(
735 static_cast<const VideoFrame*>(this)->visible_data(plane));
738 const gpu::MailboxHolder* VideoFrame::mailbox_holder() const {
739 DCHECK_EQ(format_, NATIVE_TEXTURE);
740 return mailbox_holder_.get();
743 base::SharedMemoryHandle VideoFrame::shared_memory_handle() const {
744 return shared_memory_handle_;
747 void VideoFrame::UpdateReleaseSyncPoint(SyncPointClient* client) {
748 DCHECK_EQ(format_, NATIVE_TEXTURE);
749 base::AutoLock locker(release_sync_point_lock_);
750 // Must wait on the previous sync point before inserting a new sync point so
751 // that |mailbox_holder_release_cb_| guarantees the previous sync point
752 // occurred when it waits on |release_sync_point_|.
753 if (release_sync_point_)
754 client->WaitSyncPoint(release_sync_point_);
755 release_sync_point_ = client->InsertSyncPoint();
758 #if defined(OS_POSIX)
759 int VideoFrame::dmabuf_fd(size_t plane) const {
760 return dmabuf_fds_[plane].get();
762 #endif
764 #if defined(OS_MACOSX)
765 CVPixelBufferRef VideoFrame::cv_pixel_buffer() const {
766 return cv_pixel_buffer_.get();
768 #endif
770 void VideoFrame::HashFrameForTesting(base::MD5Context* context) {
771 for (size_t plane = 0; plane < NumPlanes(format_); ++plane) {
772 for (int row = 0; row < rows(plane); ++row) {
773 base::MD5Update(context, base::StringPiece(
774 reinterpret_cast<char*>(data(plane) + stride(plane) * row),
775 row_bytes(plane)));
780 } // namespace media