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 "media/base/limits.h"
15 #include "media/base/video_util.h"
16 #include "ui/gfx/geometry/point.h"
20 static bool IsPowerOfTwo(size_t x
) {
21 return x
!= 0 && (x
& (x
- 1)) == 0;
24 static inline size_t RoundUp(size_t value
, size_t alignment
) {
25 DCHECK(IsPowerOfTwo(alignment
));
26 return ((value
+ (alignment
- 1)) & ~(alignment
- 1));
29 static inline size_t RoundDown(size_t value
, size_t alignment
) {
30 DCHECK(IsPowerOfTwo(alignment
));
31 return value
& ~(alignment
- 1);
34 // Returns the pixel size per element for given |plane| and |format|. E.g. 2x2
35 // for the U-plane in I420.
36 static gfx::Size
SampleSize(VideoFrame::Format format
, size_t plane
) {
37 DCHECK(VideoFrame::IsValidPlane(plane
, format
));
40 case VideoFrame::kYPlane
:
41 case VideoFrame::kAPlane
:
42 return gfx::Size(1, 1);
44 case VideoFrame::kUPlane
: // and VideoFrame::kUVPlane:
45 case VideoFrame::kVPlane
:
47 case VideoFrame::YV24
:
48 return gfx::Size(1, 1);
50 case VideoFrame::YV16
:
51 return gfx::Size(2, 1);
53 case VideoFrame::YV12
:
54 case VideoFrame::I420
:
55 case VideoFrame::YV12A
:
56 case VideoFrame::NV12
:
57 return gfx::Size(2, 2);
59 case VideoFrame::UNKNOWN
:
60 #if defined(VIDEO_HOLE)
61 case VideoFrame::HOLE
:
62 #endif // defined(VIDEO_HOLE)
63 case VideoFrame::NATIVE_TEXTURE
:
64 case VideoFrame::ARGB
:
72 // Return the alignment for the whole frame, calculated as the max of the
73 // alignment for each individual plane.
74 static gfx::Size
CommonAlignment(VideoFrame::Format format
) {
75 int max_sample_width
= 0;
76 int max_sample_height
= 0;
77 for (size_t plane
= 0; plane
< VideoFrame::NumPlanes(format
); ++plane
) {
78 const gfx::Size sample_size
= SampleSize(format
, plane
);
79 max_sample_width
= std::max(max_sample_width
, sample_size
.width());
80 max_sample_height
= std::max(max_sample_height
, sample_size
.height());
82 return gfx::Size(max_sample_width
, max_sample_height
);
85 // Returns the number of bytes per element for given |plane| and |format|. E.g.
86 // 2 for the UV plane in NV12.
87 static int BytesPerElement(VideoFrame::Format format
, size_t plane
) {
88 DCHECK(VideoFrame::IsValidPlane(plane
, format
));
89 if (format
== VideoFrame::ARGB
)
92 if (format
== VideoFrame::NV12
&& plane
== VideoFrame::kUVPlane
)
98 // Rounds up |coded_size| if necessary for |format|.
99 static gfx::Size
AdjustCodedSize(VideoFrame::Format format
,
100 const gfx::Size
& coded_size
) {
101 const gfx::Size alignment
= CommonAlignment(format
);
102 return gfx::Size(RoundUp(coded_size
.width(), alignment
.width()),
103 RoundUp(coded_size
.height(), alignment
.height()));
107 scoped_refptr
<VideoFrame
> VideoFrame::CreateFrame(
108 VideoFrame::Format format
,
109 const gfx::Size
& coded_size
,
110 const gfx::Rect
& visible_rect
,
111 const gfx::Size
& natural_size
,
112 base::TimeDelta timestamp
) {
114 case VideoFrame::YV12
:
115 case VideoFrame::YV16
:
116 case VideoFrame::I420
:
117 case VideoFrame::YV12A
:
118 case VideoFrame::YV24
:
121 case VideoFrame::UNKNOWN
:
122 case VideoFrame::NV12
:
123 case VideoFrame::NATIVE_TEXTURE
:
124 #if defined(VIDEO_HOLE)
125 case VideoFrame::HOLE
:
126 #endif // defined(VIDEO_HOLE)
127 case VideoFrame::ARGB
:
132 // Since we're creating a new YUV frame (and allocating memory for it
133 // ourselves), we can pad the requested |coded_size| if necessary if the
134 // request does not line up on sample boundaries.
135 const gfx::Size new_coded_size
= AdjustCodedSize(format
, coded_size
);
136 DCHECK(IsValidConfig(format
, new_coded_size
, visible_rect
, natural_size
));
138 gpu::MailboxHolder mailboxes
[kMaxPlanes
];
139 scoped_refptr
<VideoFrame
> frame(
140 new VideoFrame(format
, new_coded_size
, visible_rect
, natural_size
,
141 mailboxes
, TEXTURE_RGBA
, timestamp
, false));
142 frame
->AllocateYUV();
147 std::string
VideoFrame::FormatToString(VideoFrame::Format format
) {
149 case VideoFrame::UNKNOWN
:
151 case VideoFrame::YV12
:
153 case VideoFrame::YV16
:
155 case VideoFrame::I420
:
157 case VideoFrame::NATIVE_TEXTURE
:
158 return "NATIVE_TEXTURE";
159 #if defined(VIDEO_HOLE)
160 case VideoFrame::HOLE
:
162 #endif // defined(VIDEO_HOLE)
163 case VideoFrame::YV12A
:
165 case VideoFrame::NV12
:
167 case VideoFrame::YV24
:
169 case VideoFrame::ARGB
:
172 NOTREACHED() << "Invalid videoframe format provided: " << format
;
177 bool VideoFrame::IsValidConfig(VideoFrame::Format format
,
178 const gfx::Size
& coded_size
,
179 const gfx::Rect
& visible_rect
,
180 const gfx::Size
& natural_size
) {
181 // Check maximum limits for all formats.
182 if (coded_size
.GetArea() > limits::kMaxCanvas
||
183 coded_size
.width() > limits::kMaxDimension
||
184 coded_size
.height() > limits::kMaxDimension
||
185 visible_rect
.x() < 0 || visible_rect
.y() < 0 ||
186 visible_rect
.right() > coded_size
.width() ||
187 visible_rect
.bottom() > coded_size
.height() ||
188 natural_size
.GetArea() > limits::kMaxCanvas
||
189 natural_size
.width() > limits::kMaxDimension
||
190 natural_size
.height() > limits::kMaxDimension
)
193 // Check format-specific width/height requirements.
195 case VideoFrame::UNKNOWN
:
196 return (coded_size
.IsEmpty() && visible_rect
.IsEmpty() &&
197 natural_size
.IsEmpty());
199 // NATIVE_TEXTURE and HOLE have no software-allocated buffers and are
200 // allowed to skip the below check.
201 case VideoFrame::NATIVE_TEXTURE
:
202 #if defined(VIDEO_HOLE)
203 case VideoFrame::HOLE
:
204 #endif // defined(VIDEO_HOLE)
207 case VideoFrame::YV24
:
208 case VideoFrame::YV12
:
209 case VideoFrame::I420
:
210 case VideoFrame::YV12A
:
211 case VideoFrame::NV12
:
212 case VideoFrame::YV16
:
213 case VideoFrame::ARGB
:
214 // Check that software-allocated buffer formats are aligned correctly and
216 const gfx::Size alignment
= CommonAlignment(format
);
217 return RoundUp(visible_rect
.right(), alignment
.width()) <=
218 static_cast<size_t>(coded_size
.width()) &&
219 RoundUp(visible_rect
.bottom(), alignment
.height()) <=
220 static_cast<size_t>(coded_size
.height()) &&
221 !coded_size
.IsEmpty() && !visible_rect
.IsEmpty() &&
222 !natural_size
.IsEmpty();
230 scoped_refptr
<VideoFrame
> VideoFrame::WrapNativeTexture(
231 const gpu::MailboxHolder
& mailbox_holder
,
232 const ReleaseMailboxCB
& mailbox_holder_release_cb
,
233 const gfx::Size
& coded_size
,
234 const gfx::Rect
& visible_rect
,
235 const gfx::Size
& natural_size
,
236 base::TimeDelta timestamp
,
239 gpu::MailboxHolder mailbox_holders
[kMaxPlanes
];
240 mailbox_holders
[kARGBPlane
] = mailbox_holder
;
241 TextureFormat texture_format
= has_alpha
? TEXTURE_RGBA
: TEXTURE_RGB
;
242 scoped_refptr
<VideoFrame
> frame(
243 new VideoFrame(NATIVE_TEXTURE
, coded_size
, visible_rect
, natural_size
,
244 mailbox_holders
, texture_format
, timestamp
, false));
245 frame
->mailbox_holders_release_cb_
= mailbox_holder_release_cb
;
246 frame
->allow_overlay_
= allow_overlay
;
251 scoped_refptr
<VideoFrame
> VideoFrame::WrapYUV420NativeTextures(
252 const gpu::MailboxHolder
& y_mailbox_holder
,
253 const gpu::MailboxHolder
& u_mailbox_holder
,
254 const gpu::MailboxHolder
& v_mailbox_holder
,
255 const ReleaseMailboxCB
& mailbox_holder_release_cb
,
256 const gfx::Size
& coded_size
,
257 const gfx::Rect
& visible_rect
,
258 const gfx::Size
& natural_size
,
259 base::TimeDelta timestamp
,
260 bool allow_overlay
) {
261 gpu::MailboxHolder mailbox_holders
[kMaxPlanes
];
262 mailbox_holders
[kYPlane
] = y_mailbox_holder
;
263 mailbox_holders
[kUPlane
] = u_mailbox_holder
;
264 mailbox_holders
[kVPlane
] = v_mailbox_holder
;
265 scoped_refptr
<VideoFrame
> frame(
266 new VideoFrame(NATIVE_TEXTURE
, coded_size
, visible_rect
, natural_size
,
267 mailbox_holders
, TEXTURE_YUV_420
, timestamp
, false));
268 frame
->mailbox_holders_release_cb_
= mailbox_holder_release_cb
;
269 frame
->allow_overlay_
= allow_overlay
;
274 scoped_refptr
<VideoFrame
> VideoFrame::WrapExternalPackedMemory(
276 const gfx::Size
& coded_size
,
277 const gfx::Rect
& visible_rect
,
278 const gfx::Size
& natural_size
,
281 base::SharedMemoryHandle handle
,
283 base::TimeDelta timestamp
) {
284 const gfx::Size new_coded_size
= AdjustCodedSize(format
, coded_size
);
286 if (!IsValidConfig(format
, new_coded_size
, visible_rect
, natural_size
))
288 if (data_size
< AllocationSize(format
, new_coded_size
))
292 case VideoFrame::I420
: {
293 gpu::MailboxHolder mailbox_holders
[kMaxPlanes
];
294 scoped_refptr
<VideoFrame
> frame(
295 new VideoFrame(format
, new_coded_size
, visible_rect
, natural_size
,
296 mailbox_holders
, TEXTURE_RGBA
, timestamp
, false));
297 frame
->shared_memory_handle_
= handle
;
298 frame
->shared_memory_offset_
= data_offset
;
299 frame
->strides_
[kYPlane
] = new_coded_size
.width();
300 frame
->strides_
[kUPlane
] = new_coded_size
.width() / 2;
301 frame
->strides_
[kVPlane
] = new_coded_size
.width() / 2;
302 frame
->data_
[kYPlane
] = data
;
303 frame
->data_
[kUPlane
] = data
+ new_coded_size
.GetArea();
304 frame
->data_
[kVPlane
] = data
+ (new_coded_size
.GetArea() * 5 / 4);
314 scoped_refptr
<VideoFrame
> VideoFrame::WrapExternalYuvData(
316 const gfx::Size
& coded_size
,
317 const gfx::Rect
& visible_rect
,
318 const gfx::Size
& natural_size
,
325 base::TimeDelta timestamp
) {
326 const gfx::Size new_coded_size
= AdjustCodedSize(format
, coded_size
);
327 CHECK(IsValidConfig(format
, new_coded_size
, visible_rect
, natural_size
));
329 gpu::MailboxHolder mailbox_holders
[kMaxPlanes
];
330 scoped_refptr
<VideoFrame
> frame(
331 new VideoFrame(format
, new_coded_size
, visible_rect
, natural_size
,
332 mailbox_holders
, TEXTURE_RGBA
, timestamp
, false));
333 frame
->strides_
[kYPlane
] = y_stride
;
334 frame
->strides_
[kUPlane
] = u_stride
;
335 frame
->strides_
[kVPlane
] = v_stride
;
336 frame
->data_
[kYPlane
] = y_data
;
337 frame
->data_
[kUPlane
] = u_data
;
338 frame
->data_
[kVPlane
] = v_data
;
342 #if defined(OS_POSIX)
344 scoped_refptr
<VideoFrame
> VideoFrame::WrapExternalDmabufs(
346 const gfx::Size
& coded_size
,
347 const gfx::Rect
& visible_rect
,
348 const gfx::Size
& natural_size
,
349 const std::vector
<int> dmabuf_fds
,
350 base::TimeDelta timestamp
) {
351 if (!IsValidConfig(format
, coded_size
, visible_rect
, natural_size
))
354 // TODO(posciak): This is not exactly correct, it's possible for one
355 // buffer to contain more than one plane.
356 if (dmabuf_fds
.size() != NumPlanes(format
)) {
357 LOG(FATAL
) << "Not enough dmabuf fds provided!";
361 gpu::MailboxHolder mailbox_holders
[kMaxPlanes
];
362 scoped_refptr
<VideoFrame
> frame(
363 new VideoFrame(format
, coded_size
, visible_rect
, natural_size
,
364 mailbox_holders
, TEXTURE_RGBA
, timestamp
, false));
366 for (size_t i
= 0; i
< dmabuf_fds
.size(); ++i
) {
367 int duped_fd
= HANDLE_EINTR(dup(dmabuf_fds
[i
]));
368 if (duped_fd
== -1) {
369 // The already-duped in previous iterations fds will be closed when
370 // the partially-created frame drops out of scope here.
371 DLOG(ERROR
) << "Failed duplicating a dmabuf fd";
375 frame
->dmabuf_fds_
[i
].reset(duped_fd
);
376 // Data is accessible only via fds.
377 frame
->data_
[i
] = NULL
;
378 frame
->strides_
[i
] = 0;
385 #if defined(OS_MACOSX)
387 scoped_refptr
<VideoFrame
> VideoFrame::WrapCVPixelBuffer(
388 CVPixelBufferRef cv_pixel_buffer
,
389 base::TimeDelta timestamp
) {
390 DCHECK(cv_pixel_buffer
);
391 DCHECK(CFGetTypeID(cv_pixel_buffer
) == CVPixelBufferGetTypeID());
393 const OSType cv_format
= CVPixelBufferGetPixelFormatType(cv_pixel_buffer
);
395 // There are very few compatible CV pixel formats, so just check each.
396 if (cv_format
== kCVPixelFormatType_420YpCbCr8Planar
) {
397 format
= Format::I420
;
398 } else if (cv_format
== kCVPixelFormatType_444YpCbCr8
) {
399 format
= Format::YV24
;
400 } else if (cv_format
== '420v') {
401 // TODO(jfroy): Use kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange when the
402 // minimum OS X and iOS SDKs permits it.
403 format
= Format::NV12
;
405 DLOG(ERROR
) << "CVPixelBuffer format not supported: " << cv_format
;
409 const gfx::Size
coded_size(CVImageBufferGetEncodedSize(cv_pixel_buffer
));
410 const gfx::Rect
visible_rect(CVImageBufferGetCleanRect(cv_pixel_buffer
));
411 const gfx::Size
natural_size(CVImageBufferGetDisplaySize(cv_pixel_buffer
));
413 if (!IsValidConfig(format
, coded_size
, visible_rect
, natural_size
))
416 gpu::MailboxHolder mailbox_holders
[kMaxPlanes
];
417 scoped_refptr
<VideoFrame
> frame(
418 new VideoFrame(format
, coded_size
, visible_rect
, natural_size
,
419 mailbox_holders
, TEXTURE_RGBA
, timestamp
, false));
421 frame
->cv_pixel_buffer_
.reset(cv_pixel_buffer
, base::scoped_policy::RETAIN
);
427 scoped_refptr
<VideoFrame
> VideoFrame::WrapVideoFrame(
428 const scoped_refptr
<VideoFrame
>& frame
,
429 const gfx::Rect
& visible_rect
,
430 const gfx::Size
& natural_size
) {
431 // NATIVE_TEXTURE frames need mailbox info propagated, and there's no support
432 // for that here yet, see http://crbug/362521.
433 CHECK_NE(frame
->format(), NATIVE_TEXTURE
);
435 DCHECK(frame
->visible_rect().Contains(visible_rect
));
436 gpu::MailboxHolder mailbox_holders
[kMaxPlanes
];
437 scoped_refptr
<VideoFrame
> wrapped_frame(
438 new VideoFrame(frame
->format(), frame
->coded_size(), visible_rect
,
439 natural_size
, mailbox_holders
, TEXTURE_RGBA
,
440 frame
->timestamp(), frame
->end_of_stream()));
442 for (size_t i
= 0; i
< NumPlanes(frame
->format()); ++i
) {
443 wrapped_frame
->strides_
[i
] = frame
->stride(i
);
444 wrapped_frame
->data_
[i
] = frame
->data(i
);
447 return wrapped_frame
;
451 scoped_refptr
<VideoFrame
> VideoFrame::CreateEOSFrame() {
452 gpu::MailboxHolder mailbox_holders
[kMaxPlanes
];
453 return new VideoFrame(VideoFrame::UNKNOWN
, gfx::Size(), gfx::Rect(),
454 gfx::Size(), mailbox_holders
, TEXTURE_RGBA
,
455 kNoTimestamp(), true);
459 scoped_refptr
<VideoFrame
> VideoFrame::CreateColorFrame(
460 const gfx::Size
& size
,
461 uint8 y
, uint8 u
, uint8 v
,
462 base::TimeDelta timestamp
) {
463 scoped_refptr
<VideoFrame
> frame
= VideoFrame::CreateFrame(
464 VideoFrame::YV12
, size
, gfx::Rect(size
), size
, timestamp
);
465 FillYUV(frame
.get(), y
, u
, v
);
470 scoped_refptr
<VideoFrame
> VideoFrame::CreateBlackFrame(const gfx::Size
& size
) {
471 const uint8 kBlackY
= 0x00;
472 const uint8 kBlackUV
= 0x80;
473 const base::TimeDelta kZero
;
474 return CreateColorFrame(size
, kBlackY
, kBlackUV
, kBlackUV
, kZero
);
478 scoped_refptr
<VideoFrame
> VideoFrame::CreateTransparentFrame(
479 const gfx::Size
& size
) {
480 const uint8 kBlackY
= 0x00;
481 const uint8 kBlackUV
= 0x00;
482 const uint8 kTransparentA
= 0x00;
483 const base::TimeDelta kZero
;
484 scoped_refptr
<VideoFrame
> frame
= VideoFrame::CreateFrame(
485 VideoFrame::YV12A
, size
, gfx::Rect(size
), size
, kZero
);
486 FillYUVA(frame
.get(), kBlackY
, kBlackUV
, kBlackUV
, kTransparentA
);
490 #if defined(VIDEO_HOLE)
491 // This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not
492 // maintained by the general compositor team. Please contact the following
495 // wonsik@chromium.org
496 // ycheo@chromium.org
499 scoped_refptr
<VideoFrame
> VideoFrame::CreateHoleFrame(
500 const gfx::Size
& size
) {
501 DCHECK(IsValidConfig(VideoFrame::HOLE
, size
, gfx::Rect(size
), size
));
502 gpu::MailboxHolder mailboxes
[kMaxPlanes
];
503 scoped_refptr
<VideoFrame
> frame(
504 new VideoFrame(VideoFrame::HOLE
, size
, gfx::Rect(size
), size
, mailboxes
,
505 TEXTURE_RGBA
, base::TimeDelta(), false));
508 #endif // defined(VIDEO_HOLE)
511 size_t VideoFrame::NumPlanes(Format format
) {
513 case VideoFrame::NATIVE_TEXTURE
:
514 #if defined(VIDEO_HOLE)
515 case VideoFrame::HOLE
:
516 #endif // defined(VIDEO_HOLE)
518 case VideoFrame::ARGB
:
520 case VideoFrame::NV12
:
522 case VideoFrame::YV12
:
523 case VideoFrame::YV16
:
524 case VideoFrame::I420
:
525 case VideoFrame::YV24
:
527 case VideoFrame::YV12A
:
529 case VideoFrame::UNKNOWN
:
532 NOTREACHED() << "Unsupported video frame format: " << format
;
537 size_t VideoFrame::NumTextures(TextureFormat texture_format
) {
538 switch (texture_format
) {
542 case TEXTURE_YUV_420
:
551 size_t VideoFrame::AllocationSize(Format format
, const gfx::Size
& coded_size
) {
553 for (size_t i
= 0; i
< NumPlanes(format
); ++i
)
554 total
+= PlaneAllocationSize(format
, i
, coded_size
);
559 gfx::Size
VideoFrame::PlaneSize(Format format
,
561 const gfx::Size
& coded_size
) {
562 DCHECK(IsValidPlane(plane
, format
));
564 int width
= coded_size
.width();
565 int height
= coded_size
.height();
566 if (format
!= VideoFrame::ARGB
) {
567 // Align to multiple-of-two size overall. This ensures that non-subsampled
568 // planes can be addressed by pixel with the same scaling as the subsampled
570 width
= RoundUp(width
, 2);
571 height
= RoundUp(height
, 2);
574 const gfx::Size subsample
= SampleSize(format
, plane
);
575 DCHECK(width
% subsample
.width() == 0);
576 DCHECK(height
% subsample
.height() == 0);
577 return gfx::Size(BytesPerElement(format
, plane
) * width
/ subsample
.width(),
578 height
/ subsample
.height());
581 size_t VideoFrame::PlaneAllocationSize(Format format
,
583 const gfx::Size
& coded_size
) {
584 return PlaneSize(format
, plane
, coded_size
).GetArea();
588 int VideoFrame::PlaneHorizontalBitsPerPixel(Format format
, size_t plane
) {
589 DCHECK(IsValidPlane(plane
, format
));
590 const int bits_per_element
= 8 * BytesPerElement(format
, plane
);
591 const int horiz_pixels_per_element
= SampleSize(format
, plane
).width();
592 DCHECK_EQ(bits_per_element
% horiz_pixels_per_element
, 0);
593 return bits_per_element
/ horiz_pixels_per_element
;
597 int VideoFrame::PlaneBitsPerPixel(Format format
, size_t plane
) {
598 DCHECK(IsValidPlane(plane
, format
));
599 return PlaneHorizontalBitsPerPixel(format
, plane
) /
600 SampleSize(format
, plane
).height();
603 // Release data allocated by AllocateYUV().
604 static void ReleaseData(uint8
* data
) {
606 base::AlignedFree(data
);
609 void VideoFrame::AllocateYUV() {
610 DCHECK(format_
== YV12
|| format_
== YV16
|| format_
== YV12A
||
611 format_
== I420
|| format_
== YV24
);
612 static_assert(0 == kYPlane
, "y plane data must be index 0");
614 size_t data_size
= 0;
615 size_t offset
[kMaxPlanes
];
616 for (size_t plane
= 0; plane
< VideoFrame::NumPlanes(format_
); ++plane
) {
617 // The *2 in alignment for height is because some formats (e.g. h264) allow
618 // interlaced coding, and then the size needs to be a multiple of two
619 // macroblocks (vertically). See
620 // libavcodec/utils.c:avcodec_align_dimensions2().
621 const size_t height
= RoundUp(rows(plane
), kFrameSizeAlignment
* 2);
622 strides_
[plane
] = RoundUp(row_bytes(plane
), kFrameSizeAlignment
);
623 offset
[plane
] = data_size
;
624 data_size
+= height
* strides_
[plane
];
627 // The extra line of UV being allocated is because h264 chroma MC
628 // overreads by one line in some cases, see libavcodec/utils.c:
629 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
630 // put_h264_chroma_mc4_ssse3().
631 DCHECK(IsValidPlane(kUPlane
, format_
));
632 data_size
+= strides_
[kUPlane
] + kFrameSizePadding
;
634 // FFmpeg expects the initialize allocation to be zero-initialized. Failure
635 // to do so can lead to unitialized value usage. See http://crbug.com/390941
636 uint8
* data
= reinterpret_cast<uint8
*>(
637 base::AlignedAlloc(data_size
, kFrameAddressAlignment
));
638 memset(data
, 0, data_size
);
640 for (size_t plane
= 0; plane
< VideoFrame::NumPlanes(format_
); ++plane
)
641 data_
[plane
] = data
+ offset
[plane
];
643 AddDestructionObserver(base::Bind(&ReleaseData
, data
));
646 VideoFrame::VideoFrame(VideoFrame::Format format
,
647 const gfx::Size
& coded_size
,
648 const gfx::Rect
& visible_rect
,
649 const gfx::Size
& natural_size
,
650 const gpu::MailboxHolder(&mailbox_holders
)[kMaxPlanes
],
651 VideoFrame::TextureFormat texture_format
,
652 base::TimeDelta timestamp
,
655 texture_format_(texture_format
),
656 coded_size_(coded_size
),
657 visible_rect_(visible_rect
),
658 natural_size_(natural_size
),
659 shared_memory_handle_(base::SharedMemory::NULLHandle()),
660 shared_memory_offset_(0),
661 timestamp_(timestamp
),
662 release_sync_point_(0),
663 end_of_stream_(end_of_stream
),
664 allow_overlay_(false) {
665 DCHECK(IsValidConfig(format_
, coded_size_
, visible_rect_
, natural_size_
));
666 memcpy(&mailbox_holders_
, mailbox_holders
, sizeof(mailbox_holders_
));
667 memset(&strides_
, 0, sizeof(strides_
));
668 memset(&data_
, 0, sizeof(data_
));
671 VideoFrame::~VideoFrame() {
672 if (!mailbox_holders_release_cb_
.is_null()) {
673 uint32 release_sync_point
;
675 // To ensure that changes to |release_sync_point_| are visible on this
676 // thread (imply a memory barrier).
677 base::AutoLock
locker(release_sync_point_lock_
);
678 release_sync_point
= release_sync_point_
;
680 base::ResetAndReturn(&mailbox_holders_release_cb_
).Run(release_sync_point
);
683 for (auto& callback
: done_callbacks_
)
684 base::ResetAndReturn(&callback
).Run();
688 bool VideoFrame::IsValidPlane(size_t plane
, VideoFrame::Format format
) {
689 return (plane
< NumPlanes(format
));
692 int VideoFrame::stride(size_t plane
) const {
693 DCHECK(IsValidPlane(plane
, format_
));
694 return strides_
[plane
];
698 size_t VideoFrame::RowBytes(size_t plane
,
699 VideoFrame::Format format
,
701 DCHECK(IsValidPlane(plane
, format
));
702 return BytesPerElement(format
, plane
) * Columns(plane
, format
, width
);
705 int VideoFrame::row_bytes(size_t plane
) const {
706 return RowBytes(plane
, format_
, coded_size_
.width());
710 size_t VideoFrame::Rows(size_t plane
, VideoFrame::Format format
, int height
) {
711 DCHECK(IsValidPlane(plane
, format
));
712 const int sample_height
= SampleSize(format
, plane
).height();
713 return RoundUp(height
, sample_height
) / sample_height
;
717 size_t VideoFrame::Columns(size_t plane
, Format format
, int width
) {
718 DCHECK(IsValidPlane(plane
, format
));
719 const int sample_width
= SampleSize(format
, plane
).width();
720 return RoundUp(width
, sample_width
) / sample_width
;
723 int VideoFrame::rows(size_t plane
) const {
724 return Rows(plane
, format_
, coded_size_
.height());
727 const uint8
* VideoFrame::data(size_t plane
) const {
728 DCHECK(IsValidPlane(plane
, format_
));
732 uint8
* VideoFrame::data(size_t plane
) {
733 DCHECK(IsValidPlane(plane
, format_
));
737 const uint8
* VideoFrame::visible_data(size_t plane
) const {
738 DCHECK(IsValidPlane(plane
, format_
));
740 // Calculate an offset that is properly aligned for all planes.
741 const gfx::Size alignment
= CommonAlignment(format_
);
742 const gfx::Point
offset(RoundDown(visible_rect_
.x(), alignment
.width()),
743 RoundDown(visible_rect_
.y(), alignment
.height()));
745 const gfx::Size subsample
= SampleSize(format_
, plane
);
746 DCHECK(offset
.x() % subsample
.width() == 0);
747 DCHECK(offset
.y() % subsample
.height() == 0);
749 stride(plane
) * (offset
.y() / subsample
.height()) + // Row offset.
750 BytesPerElement(format_
, plane
) * // Column offset.
751 (offset
.x() / subsample
.width());
754 uint8
* VideoFrame::visible_data(size_t plane
) {
755 return const_cast<uint8
*>(
756 static_cast<const VideoFrame
*>(this)->visible_data(plane
));
759 const gpu::MailboxHolder
& VideoFrame::mailbox_holder(size_t texture
) const {
760 DCHECK_EQ(format_
, NATIVE_TEXTURE
);
761 DCHECK_LT(texture
, NumTextures(texture_format_
));
762 return mailbox_holders_
[texture
];
765 base::SharedMemoryHandle
VideoFrame::shared_memory_handle() const {
766 return shared_memory_handle_
;
769 size_t VideoFrame::shared_memory_offset() const {
770 return shared_memory_offset_
;
773 void VideoFrame::AddDestructionObserver(const base::Closure
& callback
) {
774 DCHECK(!callback
.is_null());
775 done_callbacks_
.push_back(callback
);
778 void VideoFrame::UpdateReleaseSyncPoint(SyncPointClient
* client
) {
779 DCHECK_EQ(format_
, NATIVE_TEXTURE
);
780 base::AutoLock
locker(release_sync_point_lock_
);
781 // Must wait on the previous sync point before inserting a new sync point so
782 // that |mailbox_holders_release_cb_| guarantees the previous sync point
783 // occurred when it waits on |release_sync_point_|.
784 if (release_sync_point_
)
785 client
->WaitSyncPoint(release_sync_point_
);
786 release_sync_point_
= client
->InsertSyncPoint();
789 #if defined(OS_POSIX)
790 int VideoFrame::dmabuf_fd(size_t plane
) const {
791 return dmabuf_fds_
[plane
].get();
795 #if defined(OS_MACOSX)
796 CVPixelBufferRef
VideoFrame::cv_pixel_buffer() const {
797 return cv_pixel_buffer_
.get();
801 void VideoFrame::HashFrameForTesting(base::MD5Context
* context
) {
802 for (size_t plane
= 0; plane
< NumPlanes(format_
); ++plane
) {
803 for (int row
= 0; row
< rows(plane
); ++row
) {
804 base::MD5Update(context
, base::StringPiece(
805 reinterpret_cast<char*>(data(plane
) + stride(plane
) * row
),