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"
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 "third_party/skia/include/core/SkBitmap.h"
21 static inline size_t RoundUp(size_t value
, size_t alignment
) {
22 // Check that |alignment| is a power of 2.
23 DCHECK((alignment
+ (alignment
- 1)) == (alignment
| (alignment
- 1)));
24 return ((value
+ (alignment
- 1)) & ~(alignment
- 1));
27 // Rounds up |coded_size| if necessary for |format|.
28 static gfx::Size
AdjustCodedSize(VideoFrame::Format format
,
29 const gfx::Size
& coded_size
) {
30 gfx::Size
new_coded_size(coded_size
);
32 case VideoFrame::YV12
:
33 case VideoFrame::YV12A
:
34 case VideoFrame::I420
:
35 case VideoFrame::YV12J
:
36 new_coded_size
.set_height(RoundUp(new_coded_size
.height(), 2));
38 case VideoFrame::YV16
:
39 new_coded_size
.set_width(RoundUp(new_coded_size
.width(), 2));
44 return new_coded_size
;
48 scoped_refptr
<VideoFrame
> VideoFrame::CreateFrame(
49 VideoFrame::Format format
,
50 const gfx::Size
& coded_size
,
51 const gfx::Rect
& visible_rect
,
52 const gfx::Size
& natural_size
,
53 base::TimeDelta timestamp
) {
54 DCHECK(format
!= VideoFrame::UNKNOWN
&&
55 format
!= VideoFrame::NV12
&&
56 format
!= VideoFrame::NATIVE_TEXTURE
);
57 #if defined(VIDEO_HOLE)
58 DCHECK(format
!= VideoFrame::HOLE
);
59 #endif // defined(VIDEO_HOLE)
61 // Since we're creating a new YUV frame (and allocating memory for it
62 // ourselves), we can pad the requested |coded_size| if necessary if the
63 // request does not line up on sample boundaries.
64 gfx::Size new_coded_size
= AdjustCodedSize(format
, coded_size
);
65 DCHECK(IsValidConfig(format
, new_coded_size
, visible_rect
, natural_size
));
67 scoped_refptr
<VideoFrame
> frame(
68 new VideoFrame(format
,
72 scoped_ptr
<gpu::MailboxHolder
>(),
80 std::string
VideoFrame::FormatToString(VideoFrame::Format format
) {
82 case VideoFrame::UNKNOWN
:
84 case VideoFrame::YV12
:
86 case VideoFrame::YV16
:
88 case VideoFrame::I420
:
90 case VideoFrame::NATIVE_TEXTURE
:
91 return "NATIVE_TEXTURE";
92 #if defined(VIDEO_HOLE)
93 case VideoFrame::HOLE
:
95 #endif // defined(VIDEO_HOLE)
96 case VideoFrame::YV12A
:
98 case VideoFrame::YV12J
:
100 case VideoFrame::NV12
:
102 case VideoFrame::YV24
:
105 NOTREACHED() << "Invalid videoframe format provided: " << format
;
110 bool VideoFrame::IsValidConfig(VideoFrame::Format format
,
111 const gfx::Size
& coded_size
,
112 const gfx::Rect
& visible_rect
,
113 const gfx::Size
& natural_size
) {
114 // Check maximum limits for all formats.
115 if (coded_size
.GetArea() > limits::kMaxCanvas
||
116 coded_size
.width() > limits::kMaxDimension
||
117 coded_size
.height() > limits::kMaxDimension
||
118 visible_rect
.x() < 0 || visible_rect
.y() < 0 ||
119 visible_rect
.right() > coded_size
.width() ||
120 visible_rect
.bottom() > coded_size
.height() ||
121 natural_size
.GetArea() > limits::kMaxCanvas
||
122 natural_size
.width() > limits::kMaxDimension
||
123 natural_size
.height() > limits::kMaxDimension
)
126 // Check format-specific width/height requirements.
128 case VideoFrame::UNKNOWN
:
129 return (coded_size
.IsEmpty() && visible_rect
.IsEmpty() &&
130 natural_size
.IsEmpty());
131 case VideoFrame::YV24
:
133 case VideoFrame::YV12
:
134 case VideoFrame::YV12J
:
135 case VideoFrame::I420
:
136 case VideoFrame::YV12A
:
137 case VideoFrame::NV12
:
138 // Subsampled YUV formats have width/height requirements.
139 if (static_cast<size_t>(coded_size
.height()) <
140 RoundUp(visible_rect
.bottom(), 2))
143 case VideoFrame::YV16
:
144 if (static_cast<size_t>(coded_size
.width()) <
145 RoundUp(visible_rect
.right(), 2))
148 case VideoFrame::NATIVE_TEXTURE
:
149 #if defined(VIDEO_HOLE)
150 case VideoFrame::HOLE
:
151 #endif // defined(VIDEO_HOLE)
152 // NATIVE_TEXTURE and HOLE have no software-allocated buffers and are
153 // allowed to skip the below check and be empty.
157 // Check that software-allocated buffer formats are not empty.
158 return (!coded_size
.IsEmpty() && !visible_rect
.IsEmpty() &&
159 !natural_size
.IsEmpty());
163 scoped_refptr
<VideoFrame
> VideoFrame::WrapNativeTexture(
164 scoped_ptr
<gpu::MailboxHolder
> mailbox_holder
,
165 const ReleaseMailboxCB
& mailbox_holder_release_cb
,
166 const gfx::Size
& coded_size
,
167 const gfx::Rect
& visible_rect
,
168 const gfx::Size
& natural_size
,
169 base::TimeDelta timestamp
,
170 const ReadPixelsCB
& read_pixels_cb
) {
171 scoped_refptr
<VideoFrame
> frame(new VideoFrame(NATIVE_TEXTURE
,
175 mailbox_holder
.Pass(),
178 frame
->mailbox_holder_release_cb_
= mailbox_holder_release_cb
;
179 frame
->read_pixels_cb_
= read_pixels_cb
;
184 void VideoFrame::ReadPixelsFromNativeTexture(const SkBitmap
& pixels
) {
185 DCHECK_EQ(format_
, NATIVE_TEXTURE
);
186 if (!read_pixels_cb_
.is_null())
187 read_pixels_cb_
.Run(pixels
);
191 scoped_refptr
<VideoFrame
> VideoFrame::WrapExternalPackedMemory(
193 const gfx::Size
& coded_size
,
194 const gfx::Rect
& visible_rect
,
195 const gfx::Size
& natural_size
,
198 base::SharedMemoryHandle handle
,
199 base::TimeDelta timestamp
,
200 const base::Closure
& no_longer_needed_cb
) {
201 gfx::Size new_coded_size
= AdjustCodedSize(format
, coded_size
);
203 if (!IsValidConfig(format
, new_coded_size
, visible_rect
, natural_size
))
205 if (data_size
< AllocationSize(format
, new_coded_size
))
209 case VideoFrame::I420
: {
210 scoped_refptr
<VideoFrame
> frame(
211 new VideoFrame(format
,
215 scoped_ptr
<gpu::MailboxHolder
>(),
218 frame
->shared_memory_handle_
= handle
;
219 frame
->strides_
[kYPlane
] = new_coded_size
.width();
220 frame
->strides_
[kUPlane
] = new_coded_size
.width() / 2;
221 frame
->strides_
[kVPlane
] = new_coded_size
.width() / 2;
222 frame
->data_
[kYPlane
] = data
;
223 frame
->data_
[kUPlane
] = data
+ new_coded_size
.GetArea();
224 frame
->data_
[kVPlane
] = data
+ (new_coded_size
.GetArea() * 5 / 4);
225 frame
->no_longer_needed_cb_
= no_longer_needed_cb
;
234 #if defined(OS_POSIX)
236 scoped_refptr
<VideoFrame
> VideoFrame::WrapExternalDmabufs(
238 const gfx::Size
& coded_size
,
239 const gfx::Rect
& visible_rect
,
240 const gfx::Size
& natural_size
,
241 const std::vector
<int> dmabuf_fds
,
242 base::TimeDelta timestamp
,
243 const base::Closure
& no_longer_needed_cb
) {
244 if (!IsValidConfig(format
, coded_size
, visible_rect
, natural_size
))
247 if (dmabuf_fds
.size() != NumPlanes(format
)) {
248 LOG(FATAL
) << "Not enough dmabuf fds provided!";
252 scoped_refptr
<VideoFrame
> frame(
253 new VideoFrame(format
,
257 scoped_ptr
<gpu::MailboxHolder
>(),
261 for (size_t i
= 0; i
< dmabuf_fds
.size(); ++i
) {
262 int duped_fd
= HANDLE_EINTR(dup(dmabuf_fds
[i
]));
263 if (duped_fd
== -1) {
264 // The already-duped in previous iterations fds will be closed when
265 // the partially-created frame drops out of scope here.
266 DLOG(ERROR
) << "Failed duplicating a dmabuf fd";
270 frame
->dmabuf_fds_
[i
].reset(duped_fd
);
271 // Data is accessible only via fds.
272 frame
->data_
[i
] = NULL
;
273 frame
->strides_
[i
] = 0;
276 frame
->no_longer_needed_cb_
= no_longer_needed_cb
;
281 #if defined(OS_MACOSX)
283 scoped_refptr
<VideoFrame
> VideoFrame::WrapCVPixelBuffer(
284 CVPixelBufferRef cv_pixel_buffer
,
285 base::TimeDelta timestamp
) {
286 DCHECK(cv_pixel_buffer
);
287 DCHECK(CFGetTypeID(cv_pixel_buffer
) == CVPixelBufferGetTypeID());
289 OSType cv_format
= CVPixelBufferGetPixelFormatType(cv_pixel_buffer
);
291 // There are very few compatible CV pixel formats, so just check each.
292 if (cv_format
== kCVPixelFormatType_420YpCbCr8Planar
) {
293 format
= Format::I420
;
294 } else if (cv_format
== kCVPixelFormatType_444YpCbCr8
) {
295 format
= Format::YV24
;
296 } else if (cv_format
== '420v') {
297 // TODO(jfroy): Use kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange when the
298 // minimum OS X and iOS SDKs permits it.
299 format
= Format::NV12
;
301 DLOG(ERROR
) << "CVPixelBuffer format not supported: " << cv_format
;
305 gfx::Size
coded_size(CVImageBufferGetEncodedSize(cv_pixel_buffer
));
306 gfx::Rect
visible_rect(CVImageBufferGetCleanRect(cv_pixel_buffer
));
307 gfx::Size
natural_size(CVImageBufferGetDisplaySize(cv_pixel_buffer
));
309 if (!IsValidConfig(format
, coded_size
, visible_rect
, natural_size
))
312 scoped_refptr
<VideoFrame
> frame(
313 new VideoFrame(format
,
317 scoped_ptr
<gpu::MailboxHolder
>(),
321 frame
->cv_pixel_buffer_
.reset(cv_pixel_buffer
, base::scoped_policy::RETAIN
);
327 scoped_refptr
<VideoFrame
> VideoFrame::WrapExternalYuvData(
329 const gfx::Size
& coded_size
,
330 const gfx::Rect
& visible_rect
,
331 const gfx::Size
& natural_size
,
338 base::TimeDelta timestamp
,
339 const base::Closure
& no_longer_needed_cb
) {
340 gfx::Size new_coded_size
= AdjustCodedSize(format
, coded_size
);
341 CHECK(IsValidConfig(format
, new_coded_size
, visible_rect
, natural_size
));
343 scoped_refptr
<VideoFrame
> frame(
344 new VideoFrame(format
,
348 scoped_ptr
<gpu::MailboxHolder
>(),
351 frame
->strides_
[kYPlane
] = y_stride
;
352 frame
->strides_
[kUPlane
] = u_stride
;
353 frame
->strides_
[kVPlane
] = v_stride
;
354 frame
->data_
[kYPlane
] = y_data
;
355 frame
->data_
[kUPlane
] = u_data
;
356 frame
->data_
[kVPlane
] = v_data
;
357 frame
->no_longer_needed_cb_
= no_longer_needed_cb
;
362 scoped_refptr
<VideoFrame
> VideoFrame::WrapVideoFrame(
363 const scoped_refptr
<VideoFrame
>& frame
,
364 const gfx::Rect
& visible_rect
,
365 const gfx::Size
& natural_size
,
366 const base::Closure
& no_longer_needed_cb
) {
367 // NATIVE_TEXTURE frames need mailbox info propagated, and there's no support
368 // for that here yet, see http://crbug/362521.
369 CHECK_NE(frame
->format(), NATIVE_TEXTURE
);
371 DCHECK(frame
->visible_rect().Contains(visible_rect
));
372 scoped_refptr
<VideoFrame
> wrapped_frame(
373 new VideoFrame(frame
->format(),
377 scoped_ptr
<gpu::MailboxHolder
>(),
379 frame
->end_of_stream()));
381 for (size_t i
= 0; i
< NumPlanes(frame
->format()); ++i
) {
382 wrapped_frame
->strides_
[i
] = frame
->stride(i
);
383 wrapped_frame
->data_
[i
] = frame
->data(i
);
386 wrapped_frame
->no_longer_needed_cb_
= no_longer_needed_cb
;
387 return wrapped_frame
;
391 scoped_refptr
<VideoFrame
> VideoFrame::CreateEOSFrame() {
392 return new VideoFrame(VideoFrame::UNKNOWN
,
396 scoped_ptr
<gpu::MailboxHolder
>(),
402 scoped_refptr
<VideoFrame
> VideoFrame::CreateColorFrame(
403 const gfx::Size
& size
,
404 uint8 y
, uint8 u
, uint8 v
,
405 base::TimeDelta timestamp
) {
406 scoped_refptr
<VideoFrame
> frame
= VideoFrame::CreateFrame(
407 VideoFrame::YV12
, size
, gfx::Rect(size
), size
, timestamp
);
408 FillYUV(frame
.get(), y
, u
, v
);
413 scoped_refptr
<VideoFrame
> VideoFrame::CreateBlackFrame(const gfx::Size
& size
) {
414 const uint8 kBlackY
= 0x00;
415 const uint8 kBlackUV
= 0x80;
416 const base::TimeDelta kZero
;
417 return CreateColorFrame(size
, kBlackY
, kBlackUV
, kBlackUV
, kZero
);
421 scoped_refptr
<VideoFrame
> VideoFrame::CreateTransparentFrame(
422 const gfx::Size
& size
) {
423 const uint8 kBlackY
= 0x00;
424 const uint8 kBlackUV
= 0x00;
425 const uint8 kTransparentA
= 0x00;
426 const base::TimeDelta kZero
;
427 scoped_refptr
<VideoFrame
> frame
= VideoFrame::CreateFrame(
428 VideoFrame::YV12A
, size
, gfx::Rect(size
), size
, kZero
);
429 FillYUVA(frame
.get(), kBlackY
, kBlackUV
, kBlackUV
, kTransparentA
);
433 #if defined(VIDEO_HOLE)
434 // This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not
435 // maintained by the general compositor team. Please contact the following
438 // wonsik@chromium.org
439 // ycheo@chromium.org
442 scoped_refptr
<VideoFrame
> VideoFrame::CreateHoleFrame(
443 const gfx::Size
& size
) {
444 DCHECK(IsValidConfig(VideoFrame::HOLE
, size
, gfx::Rect(size
), size
));
445 scoped_refptr
<VideoFrame
> frame(
446 new VideoFrame(VideoFrame::HOLE
,
450 scoped_ptr
<gpu::MailboxHolder
>(),
455 #endif // defined(VIDEO_HOLE)
458 size_t VideoFrame::NumPlanes(Format format
) {
460 case VideoFrame::NATIVE_TEXTURE
:
461 #if defined(VIDEO_HOLE)
462 case VideoFrame::HOLE
:
463 #endif // defined(VIDEO_HOLE)
465 case VideoFrame::NV12
:
467 case VideoFrame::YV12
:
468 case VideoFrame::YV16
:
469 case VideoFrame::I420
:
470 case VideoFrame::YV12J
:
471 case VideoFrame::YV24
:
473 case VideoFrame::YV12A
:
475 case VideoFrame::UNKNOWN
:
478 NOTREACHED() << "Unsupported video frame format: " << format
;
484 size_t VideoFrame::AllocationSize(Format format
, const gfx::Size
& coded_size
) {
486 for (size_t i
= 0; i
< NumPlanes(format
); ++i
)
487 total
+= PlaneAllocationSize(format
, i
, coded_size
);
492 gfx::Size
VideoFrame::PlaneSize(Format format
,
494 const gfx::Size
& coded_size
) {
495 // Align to multiple-of-two size overall. This ensures that non-subsampled
496 // planes can be addressed by pixel with the same scaling as the subsampled
498 const int width
= RoundUp(coded_size
.width(), 2);
499 const int height
= RoundUp(coded_size
.height(), 2);
501 case VideoFrame::YV24
:
503 case VideoFrame::kYPlane
:
504 case VideoFrame::kUPlane
:
505 case VideoFrame::kVPlane
:
506 return gfx::Size(width
, height
);
511 case VideoFrame::YV12
:
512 case VideoFrame::YV12J
:
513 case VideoFrame::I420
:
515 case VideoFrame::kYPlane
:
516 return gfx::Size(width
, height
);
517 case VideoFrame::kUPlane
:
518 case VideoFrame::kVPlane
:
519 return gfx::Size(width
/ 2, height
/ 2);
524 case VideoFrame::YV12A
:
526 case VideoFrame::kYPlane
:
527 case VideoFrame::kAPlane
:
528 return gfx::Size(width
, height
);
529 case VideoFrame::kUPlane
:
530 case VideoFrame::kVPlane
:
531 return gfx::Size(width
/ 2, height
/ 2);
536 case VideoFrame::YV16
:
538 case VideoFrame::kYPlane
:
539 return gfx::Size(width
, height
);
540 case VideoFrame::kUPlane
:
541 case VideoFrame::kVPlane
:
542 return gfx::Size(width
/ 2, height
);
547 case VideoFrame::NV12
:
549 case VideoFrame::kYPlane
:
550 return gfx::Size(width
, height
);
551 case VideoFrame::kUVPlane
:
552 return gfx::Size(width
, height
/ 2);
557 case VideoFrame::UNKNOWN
:
558 case VideoFrame::NATIVE_TEXTURE
:
559 #if defined(VIDEO_HOLE)
560 case VideoFrame::HOLE
:
561 #endif // defined(VIDEO_HOLE)
564 NOTREACHED() << "Unsupported video frame format/plane: "
565 << format
<< "/" << plane
;
569 size_t VideoFrame::PlaneAllocationSize(Format format
,
571 const gfx::Size
& coded_size
) {
572 // VideoFrame formats are (so far) all YUV and 1 byte per sample.
573 return PlaneSize(format
, plane
, coded_size
).GetArea();
577 int VideoFrame::PlaneHorizontalBitsPerPixel(Format format
, size_t plane
) {
579 case VideoFrame::YV24
:
589 case VideoFrame::YV12
:
590 case VideoFrame::YV16
:
591 case VideoFrame::I420
:
592 case VideoFrame::YV12J
:
603 case VideoFrame::YV12A
:
615 case VideoFrame::NV12
:
625 case VideoFrame::UNKNOWN
:
626 #if defined(VIDEO_HOLE)
627 case VideoFrame::HOLE
:
628 #endif // defined(VIDEO_HOLE)
629 case VideoFrame::NATIVE_TEXTURE
:
632 NOTREACHED() << "Unsupported video frame format/plane: "
633 << format
<< "/" << plane
;
637 // Release data allocated by AllocateYUV().
638 static void ReleaseData(uint8
* data
) {
640 base::AlignedFree(data
);
643 void VideoFrame::AllocateYUV() {
644 DCHECK(format_
== VideoFrame::YV12
|| format_
== VideoFrame::YV16
||
645 format_
== VideoFrame::YV12A
|| format_
== VideoFrame::I420
||
646 format_
== VideoFrame::YV12J
|| format_
== VideoFrame::YV24
);
647 // Align Y rows at least at 16 byte boundaries. The stride for both
648 // YV12 and YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for
649 // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in
650 // the case of YV12 the strides are identical for the same width surface, but
651 // the number of bytes allocated for YV12 is 1/2 the amount for U & V as
652 // YV16. We also round the height of the surface allocated to be an even
653 // number to avoid any potential of faulting by code that attempts to access
654 // the Y values of the final row, but assumes that the last row of U & V
655 // applies to a full two rows of Y. YV12A is the same as YV12, but with an
656 // additional alpha plane that has the same size and alignment as the Y plane.
657 size_t y_stride
= RoundUp(row_bytes(VideoFrame::kYPlane
),
658 kFrameSizeAlignment
);
659 size_t uv_stride
= RoundUp(row_bytes(VideoFrame::kUPlane
),
660 kFrameSizeAlignment
);
662 // The *2 here is because some formats (e.g. h264) allow interlaced coding,
663 // and then the size needs to be a multiple of two macroblocks (vertically).
664 // See libavcodec/utils.c:avcodec_align_dimensions2().
665 size_t y_height
= RoundUp(coded_size_
.height(), kFrameSizeAlignment
* 2);
667 (format_
== VideoFrame::YV12
|| format_
== VideoFrame::YV12A
||
668 format_
== VideoFrame::I420
)
671 size_t y_bytes
= y_height
* y_stride
;
672 size_t uv_bytes
= uv_height
* uv_stride
;
673 size_t a_bytes
= format_
== VideoFrame::YV12A
? y_bytes
: 0;
675 // The extra line of UV being allocated is because h264 chroma MC
676 // overreads by one line in some cases, see libavcodec/utils.c:
677 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
678 // put_h264_chroma_mc4_ssse3().
679 const size_t data_size
=
680 y_bytes
+ (uv_bytes
* 2 + uv_stride
) + a_bytes
+ kFrameSizePadding
;
681 uint8
* data
= reinterpret_cast<uint8
*>(
682 base::AlignedAlloc(data_size
, kFrameAddressAlignment
));
683 // FFmpeg expects the initialize allocation to be zero-initialized. Failure
684 // to do so can lead to unitialized value usage. See http://crbug.com/390941
685 memset(data
, 0, data_size
);
686 no_longer_needed_cb_
= base::Bind(&ReleaseData
, data
);
687 COMPILE_ASSERT(0 == VideoFrame::kYPlane
, y_plane_data_must_be_index_0
);
688 data_
[VideoFrame::kYPlane
] = data
;
689 data_
[VideoFrame::kUPlane
] = data
+ y_bytes
;
690 data_
[VideoFrame::kVPlane
] = data
+ y_bytes
+ uv_bytes
;
691 strides_
[VideoFrame::kYPlane
] = y_stride
;
692 strides_
[VideoFrame::kUPlane
] = uv_stride
;
693 strides_
[VideoFrame::kVPlane
] = uv_stride
;
694 if (format_
== YV12A
) {
695 data_
[VideoFrame::kAPlane
] = data
+ y_bytes
+ (2 * uv_bytes
);
696 strides_
[VideoFrame::kAPlane
] = y_stride
;
700 VideoFrame::VideoFrame(VideoFrame::Format format
,
701 const gfx::Size
& coded_size
,
702 const gfx::Rect
& visible_rect
,
703 const gfx::Size
& natural_size
,
704 scoped_ptr
<gpu::MailboxHolder
> mailbox_holder
,
705 base::TimeDelta timestamp
,
708 coded_size_(coded_size
),
709 visible_rect_(visible_rect
),
710 natural_size_(natural_size
),
711 mailbox_holder_(mailbox_holder
.Pass()),
712 shared_memory_handle_(base::SharedMemory::NULLHandle()),
713 timestamp_(timestamp
),
714 release_sync_point_(0),
715 end_of_stream_(end_of_stream
) {
716 DCHECK(IsValidConfig(format_
, coded_size_
, visible_rect_
, natural_size_
));
718 memset(&strides_
, 0, sizeof(strides_
));
719 memset(&data_
, 0, sizeof(data_
));
722 VideoFrame::~VideoFrame() {
723 if (!mailbox_holder_release_cb_
.is_null()) {
724 uint32 release_sync_point
;
726 // To ensure that changes to |release_sync_point_| are visible on this
727 // thread (imply a memory barrier).
728 base::AutoLock
locker(release_sync_point_lock_
);
729 release_sync_point
= release_sync_point_
;
731 base::ResetAndReturn(&mailbox_holder_release_cb_
).Run(release_sync_point
);
733 if (!no_longer_needed_cb_
.is_null())
734 base::ResetAndReturn(&no_longer_needed_cb_
).Run();
738 bool VideoFrame::IsValidPlane(size_t plane
, VideoFrame::Format format
) {
739 return (plane
< NumPlanes(format
));
742 int VideoFrame::stride(size_t plane
) const {
743 DCHECK(IsValidPlane(plane
, format_
));
744 return strides_
[plane
];
748 int VideoFrame::RowBytes(size_t plane
, VideoFrame::Format format
, int width
) {
749 DCHECK(IsValidPlane(plane
, format
));
751 case VideoFrame::YV24
:
761 case VideoFrame::YV12
:
762 case VideoFrame::YV16
:
763 case VideoFrame::I420
:
764 case VideoFrame::YV12J
:
770 return RoundUp(width
, 2) / 2;
775 case VideoFrame::YV12A
:
782 return RoundUp(width
, 2) / 2;
787 case VideoFrame::NV12
:
796 case VideoFrame::UNKNOWN
:
797 #if defined(VIDEO_HOLE)
798 case VideoFrame::HOLE
:
799 #endif // defined(VIDEO_HOLE)
800 case VideoFrame::NATIVE_TEXTURE
:
803 NOTREACHED() << "Unsupported video frame format/plane: " << format
<< "/"
808 int VideoFrame::row_bytes(size_t plane
) const {
809 return RowBytes(plane
, format_
, coded_size_
.width());
812 int VideoFrame::rows(size_t plane
) const {
813 DCHECK(IsValidPlane(plane
, format_
));
814 int height
= coded_size_
.height();
816 case VideoFrame::YV24
:
817 case VideoFrame::YV16
:
827 case VideoFrame::YV12
:
828 case VideoFrame::YV12J
:
829 case VideoFrame::I420
:
835 return RoundUp(height
, 2) / 2;
840 case VideoFrame::YV12A
:
847 return RoundUp(height
, 2) / 2;
852 case VideoFrame::NV12
:
857 return RoundUp(height
, 2) / 2;
862 case VideoFrame::UNKNOWN
:
863 #if defined(VIDEO_HOLE)
864 case VideoFrame::HOLE
:
865 #endif // defined(VIDEO_HOLE)
866 case VideoFrame::NATIVE_TEXTURE
:
869 NOTREACHED() << "Unsupported video frame format/plane: "
870 << format_
<< "/" << plane
;
874 uint8
* VideoFrame::data(size_t plane
) const {
875 DCHECK(IsValidPlane(plane
, format_
));
879 const gpu::MailboxHolder
* VideoFrame::mailbox_holder() const {
880 DCHECK_EQ(format_
, NATIVE_TEXTURE
);
881 return mailbox_holder_
.get();
884 base::SharedMemoryHandle
VideoFrame::shared_memory_handle() const {
885 return shared_memory_handle_
;
888 void VideoFrame::UpdateReleaseSyncPoint(SyncPointClient
* client
) {
889 DCHECK_EQ(format_
, NATIVE_TEXTURE
);
890 base::AutoLock
locker(release_sync_point_lock_
);
891 // Must wait on the previous sync point before inserting a new sync point so
892 // that |mailbox_holder_release_cb_| guarantees the previous sync point
893 // occurred when it waits on |release_sync_point_|.
894 if (release_sync_point_
)
895 client
->WaitSyncPoint(release_sync_point_
);
896 release_sync_point_
= client
->InsertSyncPoint();
899 #if defined(OS_POSIX)
900 int VideoFrame::dmabuf_fd(size_t plane
) const {
901 return dmabuf_fds_
[plane
].get();
905 #if defined(OS_MACOSX)
906 CVPixelBufferRef
VideoFrame::cv_pixel_buffer() const {
907 return cv_pixel_buffer_
.get();
911 void VideoFrame::HashFrameForTesting(base::MD5Context
* context
) {
912 for (int plane
= 0; plane
< kMaxPlanes
; ++plane
) {
913 if (!IsValidPlane(plane
, format_
))
915 for (int row
= 0; row
< rows(plane
); ++row
) {
916 base::MD5Update(context
, base::StringPiece(
917 reinterpret_cast<char*>(data(plane
) + stride(plane
) * row
),