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 "ui/gfx/geometry/point.h"
21 static bool IsPowerOfTwo(size_t x
) {
22 return x
!= 0 && (x
& (x
- 1)) == 0;
25 static inline size_t RoundUp(size_t value
, size_t alignment
) {
26 DCHECK(IsPowerOfTwo(alignment
));
27 return ((value
+ (alignment
- 1)) & ~(alignment
- 1));
30 static inline size_t RoundDown(size_t value
, size_t alignment
) {
31 DCHECK(IsPowerOfTwo(alignment
));
32 return value
& ~(alignment
- 1);
35 // Returns the pixel size per element for given |plane| and |format|. E.g. 2x2
36 // for the U-plane in I420.
37 static gfx::Size
SampleSize(VideoFrame::Format format
, size_t plane
) {
38 DCHECK(VideoFrame::IsValidPlane(plane
, format
));
41 case VideoFrame::kYPlane
:
42 case VideoFrame::kAPlane
:
43 return gfx::Size(1, 1);
45 case VideoFrame::kUPlane
: // and VideoFrame::kUVPlane:
46 case VideoFrame::kVPlane
:
48 case VideoFrame::YV24
:
49 return gfx::Size(1, 1);
51 case VideoFrame::YV16
:
52 return gfx::Size(2, 1);
54 case VideoFrame::YV12
:
55 case VideoFrame::YV12J
:
56 case VideoFrame::YV12HD
:
57 case VideoFrame::I420
:
58 case VideoFrame::YV12A
:
59 case VideoFrame::NV12
:
60 return gfx::Size(2, 2);
62 case VideoFrame::UNKNOWN
:
63 #if defined(VIDEO_HOLE)
64 case VideoFrame::HOLE
:
65 #endif // defined(VIDEO_HOLE)
66 case VideoFrame::NATIVE_TEXTURE
:
67 case VideoFrame::ARGB
:
75 // Return the alignment for the whole frame, calculated as the max of the
76 // alignment for each individual plane.
77 static gfx::Size
CommonAlignment(VideoFrame::Format format
) {
78 int max_sample_width
= 0;
79 int max_sample_height
= 0;
80 for (size_t plane
= 0; plane
< VideoFrame::NumPlanes(format
); ++plane
) {
81 const gfx::Size sample_size
= SampleSize(format
, plane
);
82 max_sample_width
= std::max(max_sample_width
, sample_size
.width());
83 max_sample_height
= std::max(max_sample_height
, sample_size
.height());
85 return gfx::Size(max_sample_width
, max_sample_height
);
88 // Returns the number of bytes per element for given |plane| and |format|. E.g.
89 // 2 for the UV plane in NV12.
90 static int BytesPerElement(VideoFrame::Format format
, size_t plane
) {
91 DCHECK(VideoFrame::IsValidPlane(plane
, format
));
92 if (format
== VideoFrame::ARGB
)
95 if (format
== VideoFrame::NV12
&& plane
== VideoFrame::kUVPlane
)
101 // Rounds up |coded_size| if necessary for |format|.
102 static gfx::Size
AdjustCodedSize(VideoFrame::Format format
,
103 const gfx::Size
& coded_size
) {
104 const gfx::Size alignment
= CommonAlignment(format
);
105 return gfx::Size(RoundUp(coded_size
.width(), alignment
.width()),
106 RoundUp(coded_size
.height(), alignment
.height()));
110 scoped_refptr
<VideoFrame
> VideoFrame::CreateFrame(
111 VideoFrame::Format format
,
112 const gfx::Size
& coded_size
,
113 const gfx::Rect
& visible_rect
,
114 const gfx::Size
& natural_size
,
115 base::TimeDelta timestamp
) {
117 case VideoFrame::YV12
:
118 case VideoFrame::YV16
:
119 case VideoFrame::I420
:
120 case VideoFrame::YV12A
:
121 case VideoFrame::YV12J
:
122 case VideoFrame::YV24
:
123 case VideoFrame::YV12HD
:
126 case VideoFrame::UNKNOWN
:
127 case VideoFrame::NV12
:
128 case VideoFrame::NATIVE_TEXTURE
:
129 #if defined(VIDEO_HOLE)
130 case VideoFrame::HOLE
:
131 #endif // defined(VIDEO_HOLE)
132 case VideoFrame::ARGB
:
137 // Since we're creating a new YUV frame (and allocating memory for it
138 // ourselves), we can pad the requested |coded_size| if necessary if the
139 // request does not line up on sample boundaries.
140 const gfx::Size new_coded_size
= AdjustCodedSize(format
, coded_size
);
141 DCHECK(IsValidConfig(format
, new_coded_size
, visible_rect
, natural_size
));
143 scoped_refptr
<VideoFrame
> frame(
144 new VideoFrame(format
,
148 scoped_ptr
<gpu::MailboxHolder
>(),
151 frame
->AllocateYUV();
156 std::string
VideoFrame::FormatToString(VideoFrame::Format format
) {
158 case VideoFrame::UNKNOWN
:
160 case VideoFrame::YV12
:
162 case VideoFrame::YV16
:
164 case VideoFrame::I420
:
166 case VideoFrame::NATIVE_TEXTURE
:
167 return "NATIVE_TEXTURE";
168 #if defined(VIDEO_HOLE)
169 case VideoFrame::HOLE
:
171 #endif // defined(VIDEO_HOLE)
172 case VideoFrame::YV12A
:
174 case VideoFrame::YV12J
:
176 case VideoFrame::NV12
:
178 case VideoFrame::YV24
:
180 case VideoFrame::ARGB
:
182 case VideoFrame::YV12HD
:
185 NOTREACHED() << "Invalid videoframe format provided: " << format
;
190 bool VideoFrame::IsValidConfig(VideoFrame::Format format
,
191 const gfx::Size
& coded_size
,
192 const gfx::Rect
& visible_rect
,
193 const gfx::Size
& natural_size
) {
194 // Check maximum limits for all formats.
195 if (coded_size
.GetArea() > limits::kMaxCanvas
||
196 coded_size
.width() > limits::kMaxDimension
||
197 coded_size
.height() > limits::kMaxDimension
||
198 visible_rect
.x() < 0 || visible_rect
.y() < 0 ||
199 visible_rect
.right() > coded_size
.width() ||
200 visible_rect
.bottom() > coded_size
.height() ||
201 natural_size
.GetArea() > limits::kMaxCanvas
||
202 natural_size
.width() > limits::kMaxDimension
||
203 natural_size
.height() > limits::kMaxDimension
)
206 // Check format-specific width/height requirements.
208 case VideoFrame::UNKNOWN
:
209 return (coded_size
.IsEmpty() && visible_rect
.IsEmpty() &&
210 natural_size
.IsEmpty());
212 // NATIVE_TEXTURE and HOLE have no software-allocated buffers and are
213 // allowed to skip the below check.
214 case VideoFrame::NATIVE_TEXTURE
:
215 #if defined(VIDEO_HOLE)
216 case VideoFrame::HOLE
:
217 #endif // defined(VIDEO_HOLE)
220 case VideoFrame::YV24
:
221 case VideoFrame::YV12
:
222 case VideoFrame::YV12J
:
223 case VideoFrame::I420
:
224 case VideoFrame::YV12A
:
225 case VideoFrame::NV12
:
226 case VideoFrame::YV12HD
:
227 case VideoFrame::YV16
:
228 case VideoFrame::ARGB
:
229 // Check that software-allocated buffer formats are aligned correctly and
231 const gfx::Size alignment
= CommonAlignment(format
);
232 return RoundUp(visible_rect
.right(), alignment
.width()) <=
233 static_cast<size_t>(coded_size
.width()) &&
234 RoundUp(visible_rect
.bottom(), alignment
.height()) <=
235 static_cast<size_t>(coded_size
.height()) &&
236 !coded_size
.IsEmpty() && !visible_rect
.IsEmpty() &&
237 !natural_size
.IsEmpty();
245 scoped_refptr
<VideoFrame
> VideoFrame::WrapNativeTexture(
246 scoped_ptr
<gpu::MailboxHolder
> mailbox_holder
,
247 const ReleaseMailboxCB
& mailbox_holder_release_cb
,
248 const gfx::Size
& coded_size
,
249 const gfx::Rect
& visible_rect
,
250 const gfx::Size
& natural_size
,
251 base::TimeDelta timestamp
,
252 bool allow_overlay
) {
253 scoped_refptr
<VideoFrame
> frame(new VideoFrame(NATIVE_TEXTURE
,
257 mailbox_holder
.Pass(),
260 frame
->mailbox_holder_release_cb_
= mailbox_holder_release_cb
;
261 frame
->allow_overlay_
= allow_overlay
;
267 scoped_refptr
<VideoFrame
> VideoFrame::WrapExternalPackedMemory(
269 const gfx::Size
& coded_size
,
270 const gfx::Rect
& visible_rect
,
271 const gfx::Size
& natural_size
,
274 base::SharedMemoryHandle handle
,
276 base::TimeDelta timestamp
,
277 const base::Closure
& no_longer_needed_cb
) {
278 const gfx::Size new_coded_size
= AdjustCodedSize(format
, coded_size
);
280 if (!IsValidConfig(format
, new_coded_size
, visible_rect
, natural_size
))
282 if (data_size
< AllocationSize(format
, new_coded_size
))
286 case VideoFrame::I420
: {
287 scoped_refptr
<VideoFrame
> frame(
288 new VideoFrame(format
,
292 scoped_ptr
<gpu::MailboxHolder
>(),
295 frame
->shared_memory_handle_
= handle
;
296 frame
->shared_memory_offset_
= data_offset
;
297 frame
->strides_
[kYPlane
] = new_coded_size
.width();
298 frame
->strides_
[kUPlane
] = new_coded_size
.width() / 2;
299 frame
->strides_
[kVPlane
] = new_coded_size
.width() / 2;
300 frame
->data_
[kYPlane
] = data
;
301 frame
->data_
[kUPlane
] = data
+ new_coded_size
.GetArea();
302 frame
->data_
[kVPlane
] = data
+ (new_coded_size
.GetArea() * 5 / 4);
303 frame
->no_longer_needed_cb_
= no_longer_needed_cb
;
313 scoped_refptr
<VideoFrame
> VideoFrame::WrapExternalYuvData(
315 const gfx::Size
& coded_size
,
316 const gfx::Rect
& visible_rect
,
317 const gfx::Size
& natural_size
,
324 base::TimeDelta timestamp
,
325 const base::Closure
& no_longer_needed_cb
) {
326 const gfx::Size new_coded_size
= AdjustCodedSize(format
, coded_size
);
327 CHECK(IsValidConfig(format
, new_coded_size
, visible_rect
, natural_size
));
329 scoped_refptr
<VideoFrame
> frame(
330 new VideoFrame(format
,
334 scoped_ptr
<gpu::MailboxHolder
>(),
337 frame
->strides_
[kYPlane
] = y_stride
;
338 frame
->strides_
[kUPlane
] = u_stride
;
339 frame
->strides_
[kVPlane
] = v_stride
;
340 frame
->data_
[kYPlane
] = y_data
;
341 frame
->data_
[kUPlane
] = u_data
;
342 frame
->data_
[kVPlane
] = v_data
;
343 frame
->no_longer_needed_cb_
= no_longer_needed_cb
;
347 #if defined(OS_POSIX)
349 scoped_refptr
<VideoFrame
> VideoFrame::WrapExternalDmabufs(
351 const gfx::Size
& coded_size
,
352 const gfx::Rect
& visible_rect
,
353 const gfx::Size
& natural_size
,
354 const std::vector
<int> dmabuf_fds
,
355 base::TimeDelta timestamp
,
356 const base::Closure
& no_longer_needed_cb
) {
357 if (!IsValidConfig(format
, coded_size
, visible_rect
, natural_size
))
360 // TODO(posciak): This is not exactly correct, it's possible for one
361 // buffer to contain more than one plane.
362 if (dmabuf_fds
.size() != NumPlanes(format
)) {
363 LOG(FATAL
) << "Not enough dmabuf fds provided!";
367 scoped_refptr
<VideoFrame
> frame(
368 new VideoFrame(format
,
372 scoped_ptr
<gpu::MailboxHolder
>(),
376 for (size_t i
= 0; i
< dmabuf_fds
.size(); ++i
) {
377 int duped_fd
= HANDLE_EINTR(dup(dmabuf_fds
[i
]));
378 if (duped_fd
== -1) {
379 // The already-duped in previous iterations fds will be closed when
380 // the partially-created frame drops out of scope here.
381 DLOG(ERROR
) << "Failed duplicating a dmabuf fd";
385 frame
->dmabuf_fds_
[i
].reset(duped_fd
);
386 // Data is accessible only via fds.
387 frame
->data_
[i
] = NULL
;
388 frame
->strides_
[i
] = 0;
391 frame
->no_longer_needed_cb_
= no_longer_needed_cb
;
396 #if defined(OS_MACOSX)
398 scoped_refptr
<VideoFrame
> VideoFrame::WrapCVPixelBuffer(
399 CVPixelBufferRef cv_pixel_buffer
,
400 base::TimeDelta timestamp
) {
401 DCHECK(cv_pixel_buffer
);
402 DCHECK(CFGetTypeID(cv_pixel_buffer
) == CVPixelBufferGetTypeID());
404 const OSType cv_format
= CVPixelBufferGetPixelFormatType(cv_pixel_buffer
);
406 // There are very few compatible CV pixel formats, so just check each.
407 if (cv_format
== kCVPixelFormatType_420YpCbCr8Planar
) {
408 format
= Format::I420
;
409 } else if (cv_format
== kCVPixelFormatType_444YpCbCr8
) {
410 format
= Format::YV24
;
411 } else if (cv_format
== '420v') {
412 // TODO(jfroy): Use kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange when the
413 // minimum OS X and iOS SDKs permits it.
414 format
= Format::NV12
;
416 DLOG(ERROR
) << "CVPixelBuffer format not supported: " << cv_format
;
420 const gfx::Size
coded_size(CVImageBufferGetEncodedSize(cv_pixel_buffer
));
421 const gfx::Rect
visible_rect(CVImageBufferGetCleanRect(cv_pixel_buffer
));
422 const gfx::Size
natural_size(CVImageBufferGetDisplaySize(cv_pixel_buffer
));
424 if (!IsValidConfig(format
, coded_size
, visible_rect
, natural_size
))
427 scoped_refptr
<VideoFrame
> frame(
428 new VideoFrame(format
,
432 scoped_ptr
<gpu::MailboxHolder
>(),
436 frame
->cv_pixel_buffer_
.reset(cv_pixel_buffer
, base::scoped_policy::RETAIN
);
442 scoped_refptr
<VideoFrame
> VideoFrame::WrapVideoFrame(
443 const scoped_refptr
<VideoFrame
>& frame
,
444 const gfx::Rect
& visible_rect
,
445 const gfx::Size
& natural_size
,
446 const base::Closure
& no_longer_needed_cb
) {
447 // NATIVE_TEXTURE frames need mailbox info propagated, and there's no support
448 // for that here yet, see http://crbug/362521.
449 CHECK_NE(frame
->format(), NATIVE_TEXTURE
);
451 DCHECK(frame
->visible_rect().Contains(visible_rect
));
452 scoped_refptr
<VideoFrame
> wrapped_frame(
453 new VideoFrame(frame
->format(),
457 scoped_ptr
<gpu::MailboxHolder
>(),
459 frame
->end_of_stream()));
461 for (size_t i
= 0; i
< NumPlanes(frame
->format()); ++i
) {
462 wrapped_frame
->strides_
[i
] = frame
->stride(i
);
463 wrapped_frame
->data_
[i
] = frame
->data(i
);
466 wrapped_frame
->no_longer_needed_cb_
= no_longer_needed_cb
;
467 return wrapped_frame
;
471 scoped_refptr
<VideoFrame
> VideoFrame::CreateEOSFrame() {
472 return new VideoFrame(VideoFrame::UNKNOWN
,
476 scoped_ptr
<gpu::MailboxHolder
>(),
482 scoped_refptr
<VideoFrame
> VideoFrame::CreateColorFrame(
483 const gfx::Size
& size
,
484 uint8 y
, uint8 u
, uint8 v
,
485 base::TimeDelta timestamp
) {
486 scoped_refptr
<VideoFrame
> frame
= VideoFrame::CreateFrame(
487 VideoFrame::YV12
, size
, gfx::Rect(size
), size
, timestamp
);
488 FillYUV(frame
.get(), y
, u
, v
);
493 scoped_refptr
<VideoFrame
> VideoFrame::CreateBlackFrame(const gfx::Size
& size
) {
494 const uint8 kBlackY
= 0x00;
495 const uint8 kBlackUV
= 0x80;
496 const base::TimeDelta kZero
;
497 return CreateColorFrame(size
, kBlackY
, kBlackUV
, kBlackUV
, kZero
);
501 scoped_refptr
<VideoFrame
> VideoFrame::CreateTransparentFrame(
502 const gfx::Size
& size
) {
503 const uint8 kBlackY
= 0x00;
504 const uint8 kBlackUV
= 0x00;
505 const uint8 kTransparentA
= 0x00;
506 const base::TimeDelta kZero
;
507 scoped_refptr
<VideoFrame
> frame
= VideoFrame::CreateFrame(
508 VideoFrame::YV12A
, size
, gfx::Rect(size
), size
, kZero
);
509 FillYUVA(frame
.get(), kBlackY
, kBlackUV
, kBlackUV
, kTransparentA
);
513 #if defined(VIDEO_HOLE)
514 // This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not
515 // maintained by the general compositor team. Please contact the following
518 // wonsik@chromium.org
519 // ycheo@chromium.org
522 scoped_refptr
<VideoFrame
> VideoFrame::CreateHoleFrame(
523 const gfx::Size
& size
) {
524 DCHECK(IsValidConfig(VideoFrame::HOLE
, size
, gfx::Rect(size
), size
));
525 scoped_refptr
<VideoFrame
> frame(
526 new VideoFrame(VideoFrame::HOLE
,
530 scoped_ptr
<gpu::MailboxHolder
>(),
535 #endif // defined(VIDEO_HOLE)
538 size_t VideoFrame::NumPlanes(Format format
) {
540 case VideoFrame::NATIVE_TEXTURE
:
541 #if defined(VIDEO_HOLE)
542 case VideoFrame::HOLE
:
543 #endif // defined(VIDEO_HOLE)
545 case VideoFrame::ARGB
:
547 case VideoFrame::NV12
:
549 case VideoFrame::YV12
:
550 case VideoFrame::YV16
:
551 case VideoFrame::I420
:
552 case VideoFrame::YV12J
:
553 case VideoFrame::YV12HD
:
554 case VideoFrame::YV24
:
556 case VideoFrame::YV12A
:
558 case VideoFrame::UNKNOWN
:
561 NOTREACHED() << "Unsupported video frame format: " << format
;
567 size_t VideoFrame::AllocationSize(Format format
, const gfx::Size
& coded_size
) {
569 for (size_t i
= 0; i
< NumPlanes(format
); ++i
)
570 total
+= PlaneAllocationSize(format
, i
, coded_size
);
575 gfx::Size
VideoFrame::PlaneSize(Format format
,
577 const gfx::Size
& coded_size
) {
578 DCHECK(IsValidPlane(plane
, format
));
580 int width
= coded_size
.width();
581 int height
= coded_size
.height();
582 if (format
!= VideoFrame::ARGB
) {
583 // Align to multiple-of-two size overall. This ensures that non-subsampled
584 // planes can be addressed by pixel with the same scaling as the subsampled
586 width
= RoundUp(width
, 2);
587 height
= RoundUp(height
, 2);
590 const gfx::Size subsample
= SampleSize(format
, plane
);
591 DCHECK(width
% subsample
.width() == 0);
592 DCHECK(height
% subsample
.height() == 0);
593 return gfx::Size(BytesPerElement(format
, plane
) * width
/ subsample
.width(),
594 height
/ subsample
.height());
597 size_t VideoFrame::PlaneAllocationSize(Format format
,
599 const gfx::Size
& coded_size
) {
600 return PlaneSize(format
, plane
, coded_size
).GetArea();
604 int VideoFrame::PlaneHorizontalBitsPerPixel(Format format
, size_t plane
) {
605 DCHECK(IsValidPlane(plane
, format
));
606 const int bits_per_element
= 8 * BytesPerElement(format
, plane
);
607 const int horiz_pixels_per_element
= SampleSize(format
, plane
).width();
608 DCHECK_EQ(bits_per_element
% horiz_pixels_per_element
, 0);
609 return bits_per_element
/ horiz_pixels_per_element
;
613 int VideoFrame::PlaneBitsPerPixel(Format format
, size_t plane
) {
614 DCHECK(IsValidPlane(plane
, format
));
615 return PlaneHorizontalBitsPerPixel(format
, plane
) /
616 SampleSize(format
, plane
).height();
619 // Release data allocated by AllocateYUV().
620 static void ReleaseData(uint8
* data
) {
622 base::AlignedFree(data
);
625 void VideoFrame::AllocateYUV() {
626 DCHECK(format_
== YV12
|| format_
== YV16
|| format_
== YV12A
||
627 format_
== I420
|| format_
== YV12J
|| format_
== YV24
||
629 static_assert(0 == kYPlane
, "y plane data must be index 0");
631 size_t data_size
= 0;
632 size_t offset
[kMaxPlanes
];
633 for (size_t plane
= 0; plane
< VideoFrame::NumPlanes(format_
); ++plane
) {
634 // The *2 in alignment for height is because some formats (e.g. h264) allow
635 // interlaced coding, and then the size needs to be a multiple of two
636 // macroblocks (vertically). See
637 // libavcodec/utils.c:avcodec_align_dimensions2().
638 const size_t height
= RoundUp(rows(plane
), kFrameSizeAlignment
* 2);
639 strides_
[plane
] = RoundUp(row_bytes(plane
), kFrameSizeAlignment
);
640 offset
[plane
] = data_size
;
641 data_size
+= height
* strides_
[plane
];
644 // The extra line of UV being allocated is because h264 chroma MC
645 // overreads by one line in some cases, see libavcodec/utils.c:
646 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
647 // put_h264_chroma_mc4_ssse3().
648 DCHECK(IsValidPlane(kUPlane
, format_
));
649 data_size
+= strides_
[kUPlane
] + kFrameSizePadding
;
651 // FFmpeg expects the initialize allocation to be zero-initialized. Failure
652 // to do so can lead to unitialized value usage. See http://crbug.com/390941
653 uint8
* data
= reinterpret_cast<uint8
*>(
654 base::AlignedAlloc(data_size
, kFrameAddressAlignment
));
655 memset(data
, 0, data_size
);
657 for (size_t plane
= 0; plane
< VideoFrame::NumPlanes(format_
); ++plane
)
658 data_
[plane
] = data
+ offset
[plane
];
660 no_longer_needed_cb_
= base::Bind(&ReleaseData
, data
);
663 VideoFrame::VideoFrame(VideoFrame::Format format
,
664 const gfx::Size
& coded_size
,
665 const gfx::Rect
& visible_rect
,
666 const gfx::Size
& natural_size
,
667 scoped_ptr
<gpu::MailboxHolder
> mailbox_holder
,
668 base::TimeDelta timestamp
,
671 coded_size_(coded_size
),
672 visible_rect_(visible_rect
),
673 natural_size_(natural_size
),
674 mailbox_holder_(mailbox_holder
.Pass()),
675 shared_memory_handle_(base::SharedMemory::NULLHandle()),
676 shared_memory_offset_(0),
677 timestamp_(timestamp
),
678 release_sync_point_(0),
679 end_of_stream_(end_of_stream
),
680 allow_overlay_(false) {
681 DCHECK(IsValidConfig(format_
, coded_size_
, visible_rect_
, natural_size_
));
683 memset(&strides_
, 0, sizeof(strides_
));
684 memset(&data_
, 0, sizeof(data_
));
687 VideoFrame::~VideoFrame() {
688 if (!mailbox_holder_release_cb_
.is_null()) {
689 uint32 release_sync_point
;
691 // To ensure that changes to |release_sync_point_| are visible on this
692 // thread (imply a memory barrier).
693 base::AutoLock
locker(release_sync_point_lock_
);
694 release_sync_point
= release_sync_point_
;
696 base::ResetAndReturn(&mailbox_holder_release_cb_
).Run(release_sync_point
);
698 if (!no_longer_needed_cb_
.is_null())
699 base::ResetAndReturn(&no_longer_needed_cb_
).Run();
703 bool VideoFrame::IsValidPlane(size_t plane
, VideoFrame::Format format
) {
704 return (plane
< NumPlanes(format
));
707 int VideoFrame::stride(size_t plane
) const {
708 DCHECK(IsValidPlane(plane
, format_
));
709 return strides_
[plane
];
713 size_t VideoFrame::RowBytes(size_t plane
,
714 VideoFrame::Format format
,
716 DCHECK(IsValidPlane(plane
, format
));
717 return BytesPerElement(format
, plane
) * Columns(plane
, format
, width
);
720 int VideoFrame::row_bytes(size_t plane
) const {
721 return RowBytes(plane
, format_
, coded_size_
.width());
725 size_t VideoFrame::Rows(size_t plane
, VideoFrame::Format format
, int height
) {
726 DCHECK(IsValidPlane(plane
, format
));
727 const int sample_height
= SampleSize(format
, plane
).height();
728 return RoundUp(height
, sample_height
) / sample_height
;
732 size_t VideoFrame::Columns(size_t plane
, Format format
, int width
) {
733 DCHECK(IsValidPlane(plane
, format
));
734 const int sample_width
= SampleSize(format
, plane
).width();
735 return RoundUp(width
, sample_width
) / sample_width
;
738 int VideoFrame::rows(size_t plane
) const {
739 return Rows(plane
, format_
, coded_size_
.height());
742 const uint8
* VideoFrame::data(size_t plane
) const {
743 DCHECK(IsValidPlane(plane
, format_
));
747 uint8
* VideoFrame::data(size_t plane
) {
748 DCHECK(IsValidPlane(plane
, format_
));
752 const uint8
* VideoFrame::visible_data(size_t plane
) const {
753 DCHECK(IsValidPlane(plane
, format_
));
755 // Calculate an offset that is properly aligned for all planes.
756 const gfx::Size alignment
= CommonAlignment(format_
);
757 const gfx::Point
offset(RoundDown(visible_rect_
.x(), alignment
.width()),
758 RoundDown(visible_rect_
.y(), alignment
.height()));
760 const gfx::Size subsample
= SampleSize(format_
, plane
);
761 DCHECK(offset
.x() % subsample
.width() == 0);
762 DCHECK(offset
.y() % subsample
.height() == 0);
764 stride(plane
) * (offset
.y() / subsample
.height()) + // Row offset.
765 BytesPerElement(format_
, plane
) * // Column offset.
766 (offset
.x() / subsample
.width());
769 uint8
* VideoFrame::visible_data(size_t plane
) {
770 return const_cast<uint8
*>(
771 static_cast<const VideoFrame
*>(this)->visible_data(plane
));
774 const gpu::MailboxHolder
* VideoFrame::mailbox_holder() const {
775 DCHECK_EQ(format_
, NATIVE_TEXTURE
);
776 return mailbox_holder_
.get();
779 base::SharedMemoryHandle
VideoFrame::shared_memory_handle() const {
780 return shared_memory_handle_
;
783 size_t VideoFrame::shared_memory_offset() const {
784 return shared_memory_offset_
;
787 void VideoFrame::UpdateReleaseSyncPoint(SyncPointClient
* client
) {
788 DCHECK_EQ(format_
, NATIVE_TEXTURE
);
789 base::AutoLock
locker(release_sync_point_lock_
);
790 // Must wait on the previous sync point before inserting a new sync point so
791 // that |mailbox_holder_release_cb_| guarantees the previous sync point
792 // occurred when it waits on |release_sync_point_|.
793 if (release_sync_point_
)
794 client
->WaitSyncPoint(release_sync_point_
);
795 release_sync_point_
= client
->InsertSyncPoint();
798 #if defined(OS_POSIX)
799 int VideoFrame::dmabuf_fd(size_t plane
) const {
800 return dmabuf_fds_
[plane
].get();
804 #if defined(OS_MACOSX)
805 CVPixelBufferRef
VideoFrame::cv_pixel_buffer() const {
806 return cv_pixel_buffer_
.get();
810 void VideoFrame::HashFrameForTesting(base::MD5Context
* context
) {
811 for (size_t plane
= 0; plane
< NumPlanes(format_
); ++plane
) {
812 for (int row
= 0; row
< rows(plane
); ++row
) {
813 base::MD5Update(context
, base::StringPiece(
814 reinterpret_cast<char*>(data(plane
) + stride(plane
) * row
),