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"
22 scoped_refptr
<VideoFrame
> VideoFrame::CreateFrame(
23 VideoFrame::Format format
,
24 const gfx::Size
& coded_size
,
25 const gfx::Rect
& visible_rect
,
26 const gfx::Size
& natural_size
,
27 base::TimeDelta timestamp
) {
28 DCHECK(IsValidConfig(format
, coded_size
, visible_rect
, natural_size
));
29 scoped_refptr
<VideoFrame
> frame(new VideoFrame(
30 format
, coded_size
, visible_rect
, natural_size
, timestamp
, false));
32 case VideoFrame::YV12
:
33 case VideoFrame::YV12A
:
34 case VideoFrame::YV16
:
35 case VideoFrame::I420
:
36 case VideoFrame::YV12J
:
40 LOG(FATAL
) << "Unsupported frame format: " << format
;
46 std::string
VideoFrame::FormatToString(VideoFrame::Format format
) {
48 case VideoFrame::UNKNOWN
:
50 case VideoFrame::YV12
:
52 case VideoFrame::YV16
:
54 case VideoFrame::I420
:
56 case VideoFrame::NATIVE_TEXTURE
:
57 return "NATIVE_TEXTURE";
58 #if defined(VIDEO_HOLE)
59 case VideoFrame::HOLE
:
61 #endif // defined(VIDEO_HOLE)
62 case VideoFrame::YV12A
:
64 case VideoFrame::YV12J
:
66 case VideoFrame::HISTOGRAM_MAX
:
67 return "HISTOGRAM_MAX";
69 NOTREACHED() << "Invalid videoframe format provided: " << format
;
74 bool VideoFrame::IsValidConfig(VideoFrame::Format format
,
75 const gfx::Size
& coded_size
,
76 const gfx::Rect
& visible_rect
,
77 const gfx::Size
& natural_size
) {
78 return (format
!= VideoFrame::UNKNOWN
&&
79 !coded_size
.IsEmpty() &&
80 coded_size
.GetArea() <= limits::kMaxCanvas
&&
81 coded_size
.width() <= limits::kMaxDimension
&&
82 coded_size
.height() <= limits::kMaxDimension
&&
83 !visible_rect
.IsEmpty() &&
84 visible_rect
.x() >= 0 && visible_rect
.y() >= 0 &&
85 visible_rect
.right() <= coded_size
.width() &&
86 visible_rect
.bottom() <= coded_size
.height() &&
87 !natural_size
.IsEmpty() &&
88 natural_size
.GetArea() <= limits::kMaxCanvas
&&
89 natural_size
.width() <= limits::kMaxDimension
&&
90 natural_size
.height() <= limits::kMaxDimension
);
94 scoped_refptr
<VideoFrame
> VideoFrame::WrapNativeTexture(
95 scoped_ptr
<gpu::MailboxHolder
> mailbox_holder
,
96 const ReleaseMailboxCB
& mailbox_holder_release_cb
,
97 const gfx::Size
& coded_size
,
98 const gfx::Rect
& visible_rect
,
99 const gfx::Size
& natural_size
,
100 base::TimeDelta timestamp
,
101 const ReadPixelsCB
& read_pixels_cb
) {
102 scoped_refptr
<VideoFrame
> frame(new VideoFrame(NATIVE_TEXTURE
,
108 frame
->mailbox_holder_
= mailbox_holder
.Pass();
109 frame
->mailbox_holder_release_cb_
= mailbox_holder_release_cb
;
110 frame
->read_pixels_cb_
= read_pixels_cb
;
115 void VideoFrame::ReadPixelsFromNativeTexture(const SkBitmap
& pixels
) {
116 DCHECK_EQ(format_
, NATIVE_TEXTURE
);
117 if (!read_pixels_cb_
.is_null())
118 read_pixels_cb_
.Run(pixels
);
122 scoped_refptr
<VideoFrame
> VideoFrame::WrapExternalPackedMemory(
124 const gfx::Size
& coded_size
,
125 const gfx::Rect
& visible_rect
,
126 const gfx::Size
& natural_size
,
129 base::SharedMemoryHandle handle
,
130 base::TimeDelta timestamp
,
131 const base::Closure
& no_longer_needed_cb
) {
132 if (data_size
< AllocationSize(format
, coded_size
))
137 scoped_refptr
<VideoFrame
> frame(new VideoFrame(
138 format
, coded_size
, visible_rect
, natural_size
, timestamp
, false));
139 frame
->shared_memory_handle_
= handle
;
140 frame
->strides_
[kYPlane
] = coded_size
.width();
141 frame
->strides_
[kUPlane
] = coded_size
.width() / 2;
142 frame
->strides_
[kVPlane
] = coded_size
.width() / 2;
143 frame
->data_
[kYPlane
] = data
;
144 frame
->data_
[kUPlane
] = data
+ coded_size
.GetArea();
145 frame
->data_
[kVPlane
] = data
+ (coded_size
.GetArea() * 5 / 4);
146 frame
->no_longer_needed_cb_
= no_longer_needed_cb
;
156 scoped_refptr
<VideoFrame
> VideoFrame::WrapExternalYuvData(
158 const gfx::Size
& coded_size
,
159 const gfx::Rect
& visible_rect
,
160 const gfx::Size
& natural_size
,
167 base::TimeDelta timestamp
,
168 const base::Closure
& no_longer_needed_cb
) {
169 DCHECK(format
== YV12
|| format
== YV16
|| format
== I420
) << format
;
170 scoped_refptr
<VideoFrame
> frame(new VideoFrame(
171 format
, coded_size
, visible_rect
, natural_size
, timestamp
, false));
172 frame
->strides_
[kYPlane
] = y_stride
;
173 frame
->strides_
[kUPlane
] = u_stride
;
174 frame
->strides_
[kVPlane
] = v_stride
;
175 frame
->data_
[kYPlane
] = y_data
;
176 frame
->data_
[kUPlane
] = u_data
;
177 frame
->data_
[kVPlane
] = v_data
;
178 frame
->no_longer_needed_cb_
= no_longer_needed_cb
;
183 scoped_refptr
<VideoFrame
> VideoFrame::WrapVideoFrame(
184 const scoped_refptr
<VideoFrame
>& frame
,
185 const base::Closure
& no_longer_needed_cb
) {
186 scoped_refptr
<VideoFrame
> wrapped_frame(new VideoFrame(
187 frame
->format(), frame
->coded_size(), frame
->visible_rect(),
188 frame
->natural_size(), frame
->GetTimestamp(), frame
->end_of_stream()));
190 for (size_t i
= 0; i
< NumPlanes(frame
->format()); ++i
) {
191 wrapped_frame
->strides_
[i
] = frame
->stride(i
);
192 wrapped_frame
->data_
[i
] = frame
->data(i
);
195 wrapped_frame
->no_longer_needed_cb_
= no_longer_needed_cb
;
196 return wrapped_frame
;
200 scoped_refptr
<VideoFrame
> VideoFrame::CreateEOSFrame() {
201 return new VideoFrame(VideoFrame::UNKNOWN
,
210 scoped_refptr
<VideoFrame
> VideoFrame::CreateColorFrame(
211 const gfx::Size
& size
,
212 uint8 y
, uint8 u
, uint8 v
,
213 base::TimeDelta timestamp
) {
214 DCHECK(IsValidConfig(VideoFrame::YV12
, size
, gfx::Rect(size
), size
));
215 scoped_refptr
<VideoFrame
> frame
= VideoFrame::CreateFrame(
216 VideoFrame::YV12
, size
, gfx::Rect(size
), size
, timestamp
);
217 FillYUV(frame
.get(), y
, u
, v
);
222 scoped_refptr
<VideoFrame
> VideoFrame::CreateBlackFrame(const gfx::Size
& size
) {
223 const uint8 kBlackY
= 0x00;
224 const uint8 kBlackUV
= 0x80;
225 const base::TimeDelta kZero
;
226 return CreateColorFrame(size
, kBlackY
, kBlackUV
, kBlackUV
, kZero
);
229 #if defined(VIDEO_HOLE)
230 // This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not
231 // maintained by the general compositor team. Please contact the following
234 // wonsik@chromium.org
235 // ycheo@chromium.org
238 scoped_refptr
<VideoFrame
> VideoFrame::CreateHoleFrame(
239 const gfx::Size
& size
) {
240 DCHECK(IsValidConfig(VideoFrame::HOLE
, size
, gfx::Rect(size
), size
));
241 scoped_refptr
<VideoFrame
> frame(new VideoFrame(
242 VideoFrame::HOLE
, size
, gfx::Rect(size
), size
, base::TimeDelta(), false));
245 #endif // defined(VIDEO_HOLE)
248 size_t VideoFrame::NumPlanes(Format format
) {
250 case VideoFrame::NATIVE_TEXTURE
:
251 #if defined(VIDEO_HOLE)
252 case VideoFrame::HOLE
:
253 #endif // defined(VIDEO_HOLE)
255 case VideoFrame::YV12
:
256 case VideoFrame::YV16
:
257 case VideoFrame::I420
:
258 case VideoFrame::YV12J
:
260 case VideoFrame::YV12A
:
262 case VideoFrame::UNKNOWN
:
263 case VideoFrame::HISTOGRAM_MAX
:
266 NOTREACHED() << "Unsupported video frame format: " << format
;
270 static inline size_t RoundUp(size_t value
, size_t alignment
) {
271 // Check that |alignment| is a power of 2.
272 DCHECK((alignment
+ (alignment
- 1)) == (alignment
| (alignment
- 1)));
273 return ((value
+ (alignment
- 1)) & ~(alignment
-1));
277 size_t VideoFrame::AllocationSize(Format format
, const gfx::Size
& coded_size
) {
279 for (size_t i
= 0; i
< NumPlanes(format
); ++i
)
280 total
+= PlaneAllocationSize(format
, i
, coded_size
);
285 size_t VideoFrame::PlaneAllocationSize(Format format
,
287 const gfx::Size
& coded_size
) {
289 RoundUp(coded_size
.width(), 2) * RoundUp(coded_size
.height(), 2);
291 case VideoFrame::YV12
:
292 case VideoFrame::YV12J
:
293 case VideoFrame::I420
: {
295 case VideoFrame::kYPlane
:
297 case VideoFrame::kUPlane
:
298 case VideoFrame::kVPlane
:
304 case VideoFrame::YV12A
: {
306 case VideoFrame::kYPlane
:
307 case VideoFrame::kAPlane
:
309 case VideoFrame::kUPlane
:
310 case VideoFrame::kVPlane
:
316 case VideoFrame::YV16
: {
318 case VideoFrame::kYPlane
:
320 case VideoFrame::kUPlane
:
321 case VideoFrame::kVPlane
:
327 case VideoFrame::UNKNOWN
:
328 case VideoFrame::NATIVE_TEXTURE
:
329 case VideoFrame::HISTOGRAM_MAX
:
330 #if defined(VIDEO_HOLE)
331 case VideoFrame::HOLE
:
332 #endif // defined(VIDEO_HOLE)
335 NOTREACHED() << "Unsupported video frame format/plane: "
336 << format
<< "/" << plane
;
340 // Release data allocated by AllocateYUV().
341 static void ReleaseData(uint8
* data
) {
343 base::AlignedFree(data
);
346 void VideoFrame::AllocateYUV() {
347 DCHECK(format_
== VideoFrame::YV12
|| format_
== VideoFrame::YV16
||
348 format_
== VideoFrame::YV12A
|| format_
== VideoFrame::I420
||
349 format_
== VideoFrame::YV12J
);
350 // Align Y rows at least at 16 byte boundaries. The stride for both
351 // YV12 and YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for
352 // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in
353 // the case of YV12 the strides are identical for the same width surface, but
354 // the number of bytes allocated for YV12 is 1/2 the amount for U & V as
355 // YV16. We also round the height of the surface allocated to be an even
356 // number to avoid any potential of faulting by code that attempts to access
357 // the Y values of the final row, but assumes that the last row of U & V
358 // applies to a full two rows of Y. YV12A is the same as YV12, but with an
359 // additional alpha plane that has the same size and alignment as the Y plane.
361 size_t y_stride
= RoundUp(row_bytes(VideoFrame::kYPlane
),
362 kFrameSizeAlignment
);
363 size_t uv_stride
= RoundUp(row_bytes(VideoFrame::kUPlane
),
364 kFrameSizeAlignment
);
365 // The *2 here is because some formats (e.g. h264) allow interlaced coding,
366 // and then the size needs to be a multiple of two macroblocks (vertically).
367 // See libavcodec/utils.c:avcodec_align_dimensions2().
368 size_t y_height
= RoundUp(coded_size_
.height(), kFrameSizeAlignment
* 2);
370 (format_
== VideoFrame::YV12
|| format_
== VideoFrame::YV12A
||
371 format_
== VideoFrame::I420
)
374 size_t y_bytes
= y_height
* y_stride
;
375 size_t uv_bytes
= uv_height
* uv_stride
;
376 size_t a_bytes
= format_
== VideoFrame::YV12A
? y_bytes
: 0;
378 // The extra line of UV being allocated is because h264 chroma MC
379 // overreads by one line in some cases, see libavcodec/utils.c:
380 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
381 // put_h264_chroma_mc4_ssse3().
382 uint8
* data
= reinterpret_cast<uint8
*>(
384 y_bytes
+ (uv_bytes
* 2 + uv_stride
) + a_bytes
+ kFrameSizePadding
,
385 kFrameAddressAlignment
));
386 no_longer_needed_cb_
= base::Bind(&ReleaseData
, data
);
387 COMPILE_ASSERT(0 == VideoFrame::kYPlane
, y_plane_data_must_be_index_0
);
388 data_
[VideoFrame::kYPlane
] = data
;
389 data_
[VideoFrame::kUPlane
] = data
+ y_bytes
;
390 data_
[VideoFrame::kVPlane
] = data
+ y_bytes
+ uv_bytes
;
391 strides_
[VideoFrame::kYPlane
] = y_stride
;
392 strides_
[VideoFrame::kUPlane
] = uv_stride
;
393 strides_
[VideoFrame::kVPlane
] = uv_stride
;
394 if (format_
== YV12A
) {
395 data_
[VideoFrame::kAPlane
] = data
+ y_bytes
+ (2 * uv_bytes
);
396 strides_
[VideoFrame::kAPlane
] = y_stride
;
400 VideoFrame::VideoFrame(VideoFrame::Format format
,
401 const gfx::Size
& coded_size
,
402 const gfx::Rect
& visible_rect
,
403 const gfx::Size
& natural_size
,
404 base::TimeDelta timestamp
,
407 coded_size_(coded_size
),
408 visible_rect_(visible_rect
),
409 natural_size_(natural_size
),
410 shared_memory_handle_(base::SharedMemory::NULLHandle()),
411 timestamp_(timestamp
),
412 end_of_stream_(end_of_stream
) {
413 memset(&strides_
, 0, sizeof(strides_
));
414 memset(&data_
, 0, sizeof(data_
));
417 VideoFrame::~VideoFrame() {
418 if (!mailbox_holder_release_cb_
.is_null()) {
419 base::ResetAndReturn(&mailbox_holder_release_cb_
)
420 .Run(mailbox_holder_
.get());
422 if (!no_longer_needed_cb_
.is_null())
423 base::ResetAndReturn(&no_longer_needed_cb_
).Run();
426 bool VideoFrame::IsValidPlane(size_t plane
) const {
427 return (plane
< NumPlanes(format_
));
430 int VideoFrame::stride(size_t plane
) const {
431 DCHECK(IsValidPlane(plane
));
432 return strides_
[plane
];
435 int VideoFrame::row_bytes(size_t plane
) const {
436 DCHECK(IsValidPlane(plane
));
437 int width
= coded_size_
.width();
441 if (plane
== kAPlane
)
448 if (plane
== kYPlane
)
450 return RoundUp(width
, 2) / 2;
456 // Intentionally leave out non-production formats.
457 NOTREACHED() << "Unsupported video frame format: " << format_
;
461 int VideoFrame::rows(size_t plane
) const {
462 DCHECK(IsValidPlane(plane
));
463 int height
= coded_size_
.height();
469 if (plane
== kAPlane
)
474 if (plane
== kYPlane
)
476 return RoundUp(height
, 2) / 2;
482 // Intentionally leave out non-production formats.
483 NOTREACHED() << "Unsupported video frame format: " << format_
;
487 uint8
* VideoFrame::data(size_t plane
) const {
488 DCHECK(IsValidPlane(plane
));
492 gpu::MailboxHolder
* VideoFrame::mailbox_holder() const {
493 DCHECK_EQ(format_
, NATIVE_TEXTURE
);
494 return mailbox_holder_
.get();
497 base::SharedMemoryHandle
VideoFrame::shared_memory_handle() const {
498 return shared_memory_handle_
;
501 void VideoFrame::HashFrameForTesting(base::MD5Context
* context
) {
502 for (int plane
= 0; plane
< kMaxPlanes
; ++plane
) {
503 if (!IsValidPlane(plane
))
505 for (int row
= 0; row
< rows(plane
); ++row
) {
506 base::MD5Update(context
, base::StringPiece(
507 reinterpret_cast<char*>(data(plane
) + stride(plane
) * row
),