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.
4
5 #include "media/base/video_frame.h"
6
7 #include <algorithm>
8
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 "third_party/skia/include/core/SkBitmap.h"
18
19 namespace media {
20
RoundUp(size_t value,size_t alignment)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));
25 }
26
27 // static
CreateFrame(VideoFrame::Format format,const gfx::Size & coded_size,const gfx::Rect & visible_rect,const gfx::Size & natural_size,base::TimeDelta timestamp)28 scoped_refptr<VideoFrame> VideoFrame::CreateFrame(
29 VideoFrame::Format format,
30 const gfx::Size& coded_size,
31 const gfx::Rect& visible_rect,
32 const gfx::Size& natural_size,
33 base::TimeDelta timestamp) {
34 // Since we're creating a new YUV frame (and allocating memory for it
35 // ourselves), we can pad the requested |coded_size| if necessary if the
36 // request does not line up on sample boundaries.
37 gfx::Size new_coded_size(coded_size);
38 switch (format) {
39 case VideoFrame::YV24:
40 break;
41 case VideoFrame::YV12:
42 case VideoFrame::YV12A:
43 case VideoFrame::I420:
44 case VideoFrame::YV12J:
45 new_coded_size.set_height((new_coded_size.height() + 1) / 2 * 2);
46 // Fallthrough.
47 case VideoFrame::YV16:
48 new_coded_size.set_width((new_coded_size.width() + 1) / 2 * 2);
49 break;
50 case VideoFrame::UNKNOWN:
51 case VideoFrame::NV12:
52 #if defined(VIDEO_HOLE)
53 case VideoFrame::HOLE:
54 #endif // defined(VIDEO_HOLE)
55 case VideoFrame::NATIVE_TEXTURE:
56 LOG(FATAL) << "Only YUV formats supported: " << format;
57 return NULL;
58 }
59 DCHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size));
60 scoped_refptr<VideoFrame> frame(
61 new VideoFrame(format,
62 new_coded_size,
63 visible_rect,
64 natural_size,
65 scoped_ptr<gpu::MailboxHolder>(),
66 timestamp,
67 false));
68 frame->AllocateYUV();
69 return frame;
70 }
71
72 // static
FormatToString(VideoFrame::Format format)73 std::string VideoFrame::FormatToString(VideoFrame::Format format) {
74 switch (format) {
75 case VideoFrame::UNKNOWN:
76 return "UNKNOWN";
77 case VideoFrame::YV12:
78 return "YV12";
79 case VideoFrame::YV16:
80 return "YV16";
81 case VideoFrame::I420:
82 return "I420";
83 case VideoFrame::NATIVE_TEXTURE:
84 return "NATIVE_TEXTURE";
85 #if defined(VIDEO_HOLE)
86 case VideoFrame::HOLE:
87 return "HOLE";
88 #endif // defined(VIDEO_HOLE)
89 case VideoFrame::YV12A:
90 return "YV12A";
91 case VideoFrame::YV12J:
92 return "YV12J";
93 case VideoFrame::NV12:
94 return "NV12";
95 case VideoFrame::YV24:
96 return "YV24";
97 }
98 NOTREACHED() << "Invalid videoframe format provided: " << format;
99 return "";
100 }
101
102 // static
IsValidConfig(VideoFrame::Format format,const gfx::Size & coded_size,const gfx::Rect & visible_rect,const gfx::Size & natural_size)103 bool VideoFrame::IsValidConfig(VideoFrame::Format format,
104 const gfx::Size& coded_size,
105 const gfx::Rect& visible_rect,
106 const gfx::Size& natural_size) {
107 // Check maximum limits for all formats.
108 if (coded_size.GetArea() > limits::kMaxCanvas ||
109 coded_size.width() > limits::kMaxDimension ||
110 coded_size.height() > limits::kMaxDimension ||
111 visible_rect.x() < 0 || visible_rect.y() < 0 ||
112 visible_rect.right() > coded_size.width() ||
113 visible_rect.bottom() > coded_size.height() ||
114 natural_size.GetArea() > limits::kMaxCanvas ||
115 natural_size.width() > limits::kMaxDimension ||
116 natural_size.height() > limits::kMaxDimension)
117 return false;
118
119 // Check format-specific width/height requirements.
120 switch (format) {
121 case VideoFrame::UNKNOWN:
122 return (coded_size.IsEmpty() && visible_rect.IsEmpty() &&
123 natural_size.IsEmpty());
124 case VideoFrame::YV24:
125 break;
126 case VideoFrame::YV12:
127 case VideoFrame::YV12J:
128 case VideoFrame::I420:
129 case VideoFrame::YV12A:
130 case VideoFrame::NV12:
131 // Subsampled YUV formats have width/height requirements.
132 if (static_cast<size_t>(coded_size.height()) <
133 RoundUp(visible_rect.bottom(), 2))
134 return false;
135 // Fallthrough.
136 case VideoFrame::YV16:
137 if (static_cast<size_t>(coded_size.width()) <
138 RoundUp(visible_rect.right(), 2))
139 return false;
140 break;
141 case VideoFrame::NATIVE_TEXTURE:
142 #if defined(VIDEO_HOLE)
143 case VideoFrame::HOLE:
144 #endif // defined(VIDEO_HOLE)
145 // NATIVE_TEXTURE and HOLE have no software-allocated buffers and are
146 // allowed to skip the below check and be empty.
147 return true;
148 }
149
150 // Check that software-allocated buffer formats are not empty.
151 return (!coded_size.IsEmpty() && !visible_rect.IsEmpty() &&
152 !natural_size.IsEmpty());
153 }
154
155 // static
WrapNativeTexture(scoped_ptr<gpu::MailboxHolder> mailbox_holder,const ReleaseMailboxCB & mailbox_holder_release_cb,const gfx::Size & coded_size,const gfx::Rect & visible_rect,const gfx::Size & natural_size,base::TimeDelta timestamp,const ReadPixelsCB & read_pixels_cb)156 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
157 scoped_ptr<gpu::MailboxHolder> mailbox_holder,
158 const ReleaseMailboxCB& mailbox_holder_release_cb,
159 const gfx::Size& coded_size,
160 const gfx::Rect& visible_rect,
161 const gfx::Size& natural_size,
162 base::TimeDelta timestamp,
163 const ReadPixelsCB& read_pixels_cb) {
164 scoped_refptr<VideoFrame> frame(new VideoFrame(NATIVE_TEXTURE,
165 coded_size,
166 visible_rect,
167 natural_size,
168 mailbox_holder.Pass(),
169 timestamp,
170 false));
171 frame->mailbox_holder_release_cb_ = mailbox_holder_release_cb;
172 frame->read_pixels_cb_ = read_pixels_cb;
173
174 return frame;
175 }
176
ReadPixelsFromNativeTexture(const SkBitmap & pixels)177 void VideoFrame::ReadPixelsFromNativeTexture(const SkBitmap& pixels) {
178 DCHECK_EQ(format_, NATIVE_TEXTURE);
179 if (!read_pixels_cb_.is_null())
180 read_pixels_cb_.Run(pixels);
181 }
182
183 // static
WrapExternalPackedMemory(Format format,const gfx::Size & coded_size,const gfx::Rect & visible_rect,const gfx::Size & natural_size,uint8 * data,size_t data_size,base::SharedMemoryHandle handle,base::TimeDelta timestamp,const base::Closure & no_longer_needed_cb)184 scoped_refptr<VideoFrame> VideoFrame::WrapExternalPackedMemory(
185 Format format,
186 const gfx::Size& coded_size,
187 const gfx::Rect& visible_rect,
188 const gfx::Size& natural_size,
189 uint8* data,
190 size_t data_size,
191 base::SharedMemoryHandle handle,
192 base::TimeDelta timestamp,
193 const base::Closure& no_longer_needed_cb) {
194 if (!IsValidConfig(format, coded_size, visible_rect, natural_size))
195 return NULL;
196 if (data_size < AllocationSize(format, coded_size))
197 return NULL;
198
199 switch (format) {
200 case VideoFrame::I420: {
201 scoped_refptr<VideoFrame> frame(
202 new VideoFrame(format,
203 coded_size,
204 visible_rect,
205 natural_size,
206 scoped_ptr<gpu::MailboxHolder>(),
207 timestamp,
208 false));
209 frame->shared_memory_handle_ = handle;
210 frame->strides_[kYPlane] = coded_size.width();
211 frame->strides_[kUPlane] = coded_size.width() / 2;
212 frame->strides_[kVPlane] = coded_size.width() / 2;
213 frame->data_[kYPlane] = data;
214 frame->data_[kUPlane] = data + coded_size.GetArea();
215 frame->data_[kVPlane] = data + (coded_size.GetArea() * 5 / 4);
216 frame->no_longer_needed_cb_ = no_longer_needed_cb;
217 return frame;
218 }
219 default:
220 NOTIMPLEMENTED();
221 return NULL;
222 }
223 }
224
225 #if defined(OS_POSIX)
226 // static
WrapExternalDmabufs(Format format,const gfx::Size & coded_size,const gfx::Rect & visible_rect,const gfx::Size & natural_size,const std::vector<int> dmabuf_fds,base::TimeDelta timestamp,const base::Closure & no_longer_needed_cb)227 scoped_refptr<VideoFrame> VideoFrame::WrapExternalDmabufs(
228 Format format,
229 const gfx::Size& coded_size,
230 const gfx::Rect& visible_rect,
231 const gfx::Size& natural_size,
232 const std::vector<int> dmabuf_fds,
233 base::TimeDelta timestamp,
234 const base::Closure& no_longer_needed_cb) {
235 if (!IsValidConfig(format, coded_size, visible_rect, natural_size))
236 return NULL;
237
238 if (dmabuf_fds.size() != NumPlanes(format)) {
239 LOG(FATAL) << "Not enough dmabuf fds provided!";
240 return NULL;
241 }
242
243 scoped_refptr<VideoFrame> frame(
244 new VideoFrame(format,
245 coded_size,
246 visible_rect,
247 natural_size,
248 scoped_ptr<gpu::MailboxHolder>(),
249 timestamp,
250 false));
251
252 for (size_t i = 0; i < dmabuf_fds.size(); ++i) {
253 int duped_fd = HANDLE_EINTR(dup(dmabuf_fds[i]));
254 if (duped_fd == -1) {
255 // The already-duped in previous iterations fds will be closed when
256 // the partially-created frame drops out of scope here.
257 DLOG(ERROR) << "Failed duplicating a dmabuf fd";
258 return NULL;
259 }
260
261 frame->dmabuf_fds_[i].reset(duped_fd);
262 // Data is accessible only via fds.
263 frame->data_[i] = NULL;
264 frame->strides_[i] = 0;
265 }
266
267 frame->no_longer_needed_cb_ = no_longer_needed_cb;
268 return frame;
269 }
270 #endif
271
272 // static
WrapExternalYuvData(Format format,const gfx::Size & coded_size,const gfx::Rect & visible_rect,const gfx::Size & natural_size,int32 y_stride,int32 u_stride,int32 v_stride,uint8 * y_data,uint8 * u_data,uint8 * v_data,base::TimeDelta timestamp,const base::Closure & no_longer_needed_cb)273 scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvData(
274 Format format,
275 const gfx::Size& coded_size,
276 const gfx::Rect& visible_rect,
277 const gfx::Size& natural_size,
278 int32 y_stride,
279 int32 u_stride,
280 int32 v_stride,
281 uint8* y_data,
282 uint8* u_data,
283 uint8* v_data,
284 base::TimeDelta timestamp,
285 const base::Closure& no_longer_needed_cb) {
286 if (!IsValidConfig(format, coded_size, visible_rect, natural_size))
287 return NULL;
288
289 scoped_refptr<VideoFrame> frame(
290 new VideoFrame(format,
291 coded_size,
292 visible_rect,
293 natural_size,
294 scoped_ptr<gpu::MailboxHolder>(),
295 timestamp,
296 false));
297 frame->strides_[kYPlane] = y_stride;
298 frame->strides_[kUPlane] = u_stride;
299 frame->strides_[kVPlane] = v_stride;
300 frame->data_[kYPlane] = y_data;
301 frame->data_[kUPlane] = u_data;
302 frame->data_[kVPlane] = v_data;
303 frame->no_longer_needed_cb_ = no_longer_needed_cb;
304 return frame;
305 }
306
307 // static
WrapVideoFrame(const scoped_refptr<VideoFrame> & frame,const gfx::Rect & visible_rect,const gfx::Size & natural_size,const base::Closure & no_longer_needed_cb)308 scoped_refptr<VideoFrame> VideoFrame::WrapVideoFrame(
309 const scoped_refptr<VideoFrame>& frame,
310 const gfx::Rect& visible_rect,
311 const gfx::Size& natural_size,
312 const base::Closure& no_longer_needed_cb) {
313 // NATIVE_TEXTURE frames need mailbox info propagated, and there's no support
314 // for that here yet, see http://crbug/362521.
315 CHECK(frame->format() != NATIVE_TEXTURE);
316
317 DCHECK(frame->visible_rect().Contains(visible_rect));
318 scoped_refptr<VideoFrame> wrapped_frame(
319 new VideoFrame(frame->format(),
320 frame->coded_size(),
321 visible_rect,
322 natural_size,
323 scoped_ptr<gpu::MailboxHolder>(),
324 frame->timestamp(),
325 frame->end_of_stream()));
326
327 for (size_t i = 0; i < NumPlanes(frame->format()); ++i) {
328 wrapped_frame->strides_[i] = frame->stride(i);
329 wrapped_frame->data_[i] = frame->data(i);
330 }
331
332 wrapped_frame->no_longer_needed_cb_ = no_longer_needed_cb;
333 return wrapped_frame;
334 }
335
336 // static
CreateEOSFrame()337 scoped_refptr<VideoFrame> VideoFrame::CreateEOSFrame() {
338 return new VideoFrame(VideoFrame::UNKNOWN,
339 gfx::Size(),
340 gfx::Rect(),
341 gfx::Size(),
342 scoped_ptr<gpu::MailboxHolder>(),
343 kNoTimestamp(),
344 true);
345 }
346
347 // static
CreateColorFrame(const gfx::Size & size,uint8 y,uint8 u,uint8 v,base::TimeDelta timestamp)348 scoped_refptr<VideoFrame> VideoFrame::CreateColorFrame(
349 const gfx::Size& size,
350 uint8 y, uint8 u, uint8 v,
351 base::TimeDelta timestamp) {
352 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
353 VideoFrame::YV12, size, gfx::Rect(size), size, timestamp);
354 FillYUV(frame.get(), y, u, v);
355 return frame;
356 }
357
358 // static
CreateBlackFrame(const gfx::Size & size)359 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(const gfx::Size& size) {
360 const uint8 kBlackY = 0x00;
361 const uint8 kBlackUV = 0x80;
362 const base::TimeDelta kZero;
363 return CreateColorFrame(size, kBlackY, kBlackUV, kBlackUV, kZero);
364 }
365
366 #if defined(VIDEO_HOLE)
367 // This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not
368 // maintained by the general compositor team. Please contact the following
369 // people instead:
370 //
371 // wonsik@chromium.org
372 // ycheo@chromium.org
373
374 // static
CreateHoleFrame(const gfx::Size & size)375 scoped_refptr<VideoFrame> VideoFrame::CreateHoleFrame(
376 const gfx::Size& size) {
377 DCHECK(IsValidConfig(VideoFrame::HOLE, size, gfx::Rect(size), size));
378 scoped_refptr<VideoFrame> frame(
379 new VideoFrame(VideoFrame::HOLE,
380 size,
381 gfx::Rect(size),
382 size,
383 scoped_ptr<gpu::MailboxHolder>(),
384 base::TimeDelta(),
385 false));
386 return frame;
387 }
388 #endif // defined(VIDEO_HOLE)
389
390 // static
NumPlanes(Format format)391 size_t VideoFrame::NumPlanes(Format format) {
392 switch (format) {
393 case VideoFrame::NATIVE_TEXTURE:
394 #if defined(VIDEO_HOLE)
395 case VideoFrame::HOLE:
396 #endif // defined(VIDEO_HOLE)
397 return 0;
398 case VideoFrame::NV12:
399 return 2;
400 case VideoFrame::YV12:
401 case VideoFrame::YV16:
402 case VideoFrame::I420:
403 case VideoFrame::YV12J:
404 case VideoFrame::YV24:
405 return 3;
406 case VideoFrame::YV12A:
407 return 4;
408 case VideoFrame::UNKNOWN:
409 break;
410 }
411 NOTREACHED() << "Unsupported video frame format: " << format;
412 return 0;
413 }
414
415
416 // static
AllocationSize(Format format,const gfx::Size & coded_size)417 size_t VideoFrame::AllocationSize(Format format, const gfx::Size& coded_size) {
418 size_t total = 0;
419 for (size_t i = 0; i < NumPlanes(format); ++i)
420 total += PlaneAllocationSize(format, i, coded_size);
421 return total;
422 }
423
424 // static
PlaneSize(Format format,size_t plane,const gfx::Size & coded_size)425 gfx::Size VideoFrame::PlaneSize(Format format,
426 size_t plane,
427 const gfx::Size& coded_size) {
428 // Align to multiple-of-two size overall. This ensures that non-subsampled
429 // planes can be addressed by pixel with the same scaling as the subsampled
430 // planes.
431 const int width = RoundUp(coded_size.width(), 2);
432 const int height = RoundUp(coded_size.height(), 2);
433 switch (format) {
434 case VideoFrame::YV24:
435 switch (plane) {
436 case VideoFrame::kYPlane:
437 case VideoFrame::kUPlane:
438 case VideoFrame::kVPlane:
439 return gfx::Size(width, height);
440 default:
441 break;
442 }
443 break;
444 case VideoFrame::YV12:
445 case VideoFrame::YV12J:
446 case VideoFrame::I420:
447 switch (plane) {
448 case VideoFrame::kYPlane:
449 return gfx::Size(width, height);
450 case VideoFrame::kUPlane:
451 case VideoFrame::kVPlane:
452 return gfx::Size(width / 2, height / 2);
453 default:
454 break;
455 }
456 break;
457 case VideoFrame::YV12A:
458 switch (plane) {
459 case VideoFrame::kYPlane:
460 case VideoFrame::kAPlane:
461 return gfx::Size(width, height);
462 case VideoFrame::kUPlane:
463 case VideoFrame::kVPlane:
464 return gfx::Size(width / 2, height / 2);
465 default:
466 break;
467 }
468 break;
469 case VideoFrame::YV16:
470 switch (plane) {
471 case VideoFrame::kYPlane:
472 return gfx::Size(width, height);
473 case VideoFrame::kUPlane:
474 case VideoFrame::kVPlane:
475 return gfx::Size(width / 2, height);
476 default:
477 break;
478 }
479 break;
480 case VideoFrame::NV12:
481 switch (plane) {
482 case VideoFrame::kYPlane:
483 return gfx::Size(width, height);
484 case VideoFrame::kUVPlane:
485 return gfx::Size(width, height / 2);
486 default:
487 break;
488 }
489 break;
490 case VideoFrame::UNKNOWN:
491 case VideoFrame::NATIVE_TEXTURE:
492 #if defined(VIDEO_HOLE)
493 case VideoFrame::HOLE:
494 #endif // defined(VIDEO_HOLE)
495 break;
496 }
497 NOTREACHED() << "Unsupported video frame format/plane: "
498 << format << "/" << plane;
499 return gfx::Size();
500 }
501
PlaneAllocationSize(Format format,size_t plane,const gfx::Size & coded_size)502 size_t VideoFrame::PlaneAllocationSize(Format format,
503 size_t plane,
504 const gfx::Size& coded_size) {
505 // VideoFrame formats are (so far) all YUV and 1 byte per sample.
506 return PlaneSize(format, plane, coded_size).GetArea();
507 }
508
509 // static
PlaneHorizontalBitsPerPixel(Format format,size_t plane)510 int VideoFrame::PlaneHorizontalBitsPerPixel(Format format, size_t plane) {
511 switch (format) {
512 case VideoFrame::YV24:
513 switch (plane) {
514 case kYPlane:
515 case kUPlane:
516 case kVPlane:
517 return 8;
518 default:
519 break;
520 }
521 break;
522 case VideoFrame::YV12:
523 case VideoFrame::YV16:
524 case VideoFrame::I420:
525 case VideoFrame::YV12J:
526 switch (plane) {
527 case kYPlane:
528 return 8;
529 case kUPlane:
530 case kVPlane:
531 return 2;
532 default:
533 break;
534 }
535 break;
536 case VideoFrame::YV12A:
537 switch (plane) {
538 case kYPlane:
539 case kAPlane:
540 return 8;
541 case kUPlane:
542 case kVPlane:
543 return 2;
544 default:
545 break;
546 }
547 break;
548 case VideoFrame::NV12:
549 switch (plane) {
550 case kYPlane:
551 return 8;
552 case kUVPlane:
553 return 4;
554 default:
555 break;
556 }
557 break;
558 case VideoFrame::UNKNOWN:
559 #if defined(VIDEO_HOLE)
560 case VideoFrame::HOLE:
561 #endif // defined(VIDEO_HOLE)
562 case VideoFrame::NATIVE_TEXTURE:
563 break;
564 }
565 NOTREACHED() << "Unsupported video frame format/plane: "
566 << format << "/" << plane;
567 return 0;
568 }
569
570 // Release data allocated by AllocateYUV().
ReleaseData(uint8 * data)571 static void ReleaseData(uint8* data) {
572 DCHECK(data);
573 base::AlignedFree(data);
574 }
575
AllocateYUV()576 void VideoFrame::AllocateYUV() {
577 DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 ||
578 format_ == VideoFrame::YV12A || format_ == VideoFrame::I420 ||
579 format_ == VideoFrame::YV12J || format_ == VideoFrame::YV24);
580 // Align Y rows at least at 16 byte boundaries. The stride for both
581 // YV12 and YV16 is 1/2 of the stride of Y. For YV12, every row of bytes for
582 // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in
583 // the case of YV12 the strides are identical for the same width surface, but
584 // the number of bytes allocated for YV12 is 1/2 the amount for U & V as
585 // YV16. We also round the height of the surface allocated to be an even
586 // number to avoid any potential of faulting by code that attempts to access
587 // the Y values of the final row, but assumes that the last row of U & V
588 // applies to a full two rows of Y. YV12A is the same as YV12, but with an
589 // additional alpha plane that has the same size and alignment as the Y plane.
590 size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane),
591 kFrameSizeAlignment);
592 size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane),
593 kFrameSizeAlignment);
594
595 // The *2 here is because some formats (e.g. h264) allow interlaced coding,
596 // and then the size needs to be a multiple of two macroblocks (vertically).
597 // See libavcodec/utils.c:avcodec_align_dimensions2().
598 size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2);
599 size_t uv_height =
600 (format_ == VideoFrame::YV12 || format_ == VideoFrame::YV12A ||
601 format_ == VideoFrame::I420)
602 ? y_height / 2
603 : y_height;
604 size_t y_bytes = y_height * y_stride;
605 size_t uv_bytes = uv_height * uv_stride;
606 size_t a_bytes = format_ == VideoFrame::YV12A ? y_bytes : 0;
607
608 // The extra line of UV being allocated is because h264 chroma MC
609 // overreads by one line in some cases, see libavcodec/utils.c:
610 // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
611 // put_h264_chroma_mc4_ssse3().
612 uint8* data = reinterpret_cast<uint8*>(
613 base::AlignedAlloc(
614 y_bytes + (uv_bytes * 2 + uv_stride) + a_bytes + kFrameSizePadding,
615 kFrameAddressAlignment));
616 no_longer_needed_cb_ = base::Bind(&ReleaseData, data);
617 COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0);
618 data_[VideoFrame::kYPlane] = data;
619 data_[VideoFrame::kUPlane] = data + y_bytes;
620 data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes;
621 strides_[VideoFrame::kYPlane] = y_stride;
622 strides_[VideoFrame::kUPlane] = uv_stride;
623 strides_[VideoFrame::kVPlane] = uv_stride;
624 if (format_ == YV12A) {
625 data_[VideoFrame::kAPlane] = data + y_bytes + (2 * uv_bytes);
626 strides_[VideoFrame::kAPlane] = y_stride;
627 }
628 }
629
VideoFrame(VideoFrame::Format format,const gfx::Size & coded_size,const gfx::Rect & visible_rect,const gfx::Size & natural_size,scoped_ptr<gpu::MailboxHolder> mailbox_holder,base::TimeDelta timestamp,bool end_of_stream)630 VideoFrame::VideoFrame(VideoFrame::Format format,
631 const gfx::Size& coded_size,
632 const gfx::Rect& visible_rect,
633 const gfx::Size& natural_size,
634 scoped_ptr<gpu::MailboxHolder> mailbox_holder,
635 base::TimeDelta timestamp,
636 bool end_of_stream)
637 : format_(format),
638 coded_size_(coded_size),
639 visible_rect_(visible_rect),
640 natural_size_(natural_size),
641 mailbox_holder_(mailbox_holder.Pass()),
642 shared_memory_handle_(base::SharedMemory::NULLHandle()),
643 timestamp_(timestamp),
644 end_of_stream_(end_of_stream) {
645 DCHECK(IsValidConfig(format_, coded_size_, visible_rect_, natural_size_));
646
647 memset(&strides_, 0, sizeof(strides_));
648 memset(&data_, 0, sizeof(data_));
649 }
650
~VideoFrame()651 VideoFrame::~VideoFrame() {
652 if (!mailbox_holder_release_cb_.is_null()) {
653 std::vector<uint32> release_sync_points;
654 {
655 base::AutoLock locker(release_sync_point_lock_);
656 release_sync_points_.swap(release_sync_points);
657 }
658 base::ResetAndReturn(&mailbox_holder_release_cb_).Run(release_sync_points);
659 }
660 if (!no_longer_needed_cb_.is_null())
661 base::ResetAndReturn(&no_longer_needed_cb_).Run();
662 }
663
IsValidPlane(size_t plane) const664 bool VideoFrame::IsValidPlane(size_t plane) const {
665 return (plane < NumPlanes(format_));
666 }
667
stride(size_t plane) const668 int VideoFrame::stride(size_t plane) const {
669 DCHECK(IsValidPlane(plane));
670 return strides_[plane];
671 }
672
row_bytes(size_t plane) const673 int VideoFrame::row_bytes(size_t plane) const {
674 DCHECK(IsValidPlane(plane));
675 int width = coded_size_.width();
676 switch (format_) {
677 case VideoFrame::YV24:
678 switch (plane) {
679 case kYPlane:
680 case kUPlane:
681 case kVPlane:
682 return width;
683 default:
684 break;
685 }
686 break;
687 case VideoFrame::YV12:
688 case VideoFrame::YV16:
689 case VideoFrame::I420:
690 case VideoFrame::YV12J:
691 switch (plane) {
692 case kYPlane:
693 return width;
694 case kUPlane:
695 case kVPlane:
696 return RoundUp(width, 2) / 2;
697 default:
698 break;
699 }
700 break;
701 case VideoFrame::YV12A:
702 switch (plane) {
703 case kYPlane:
704 case kAPlane:
705 return width;
706 case kUPlane:
707 case kVPlane:
708 return RoundUp(width, 2) / 2;
709 default:
710 break;
711 }
712 break;
713 case VideoFrame::NV12:
714 switch (plane) {
715 case kYPlane:
716 case kUVPlane:
717 return width;
718 default:
719 break;
720 }
721 break;
722 case VideoFrame::UNKNOWN:
723 #if defined(VIDEO_HOLE)
724 case VideoFrame::HOLE:
725 #endif // defined(VIDEO_HOLE)
726 case VideoFrame::NATIVE_TEXTURE:
727 break;
728 }
729 NOTREACHED() << "Unsupported video frame format/plane: "
730 << format_ << "/" << plane;
731 return 0;
732 }
733
rows(size_t plane) const734 int VideoFrame::rows(size_t plane) const {
735 DCHECK(IsValidPlane(plane));
736 int height = coded_size_.height();
737 switch (format_) {
738 case VideoFrame::YV24:
739 case VideoFrame::YV16:
740 switch (plane) {
741 case kYPlane:
742 case kUPlane:
743 case kVPlane:
744 return height;
745 default:
746 break;
747 }
748 break;
749 case VideoFrame::YV12:
750 case VideoFrame::YV12J:
751 case VideoFrame::I420:
752 switch (plane) {
753 case kYPlane:
754 return height;
755 case kUPlane:
756 case kVPlane:
757 return RoundUp(height, 2) / 2;
758 default:
759 break;
760 }
761 break;
762 case VideoFrame::YV12A:
763 switch (plane) {
764 case kYPlane:
765 case kAPlane:
766 return height;
767 case kUPlane:
768 case kVPlane:
769 return RoundUp(height, 2) / 2;
770 default:
771 break;
772 }
773 break;
774 case VideoFrame::NV12:
775 switch (plane) {
776 case kYPlane:
777 return height;
778 case kUVPlane:
779 return RoundUp(height, 2) / 2;
780 default:
781 break;
782 }
783 break;
784 case VideoFrame::UNKNOWN:
785 #if defined(VIDEO_HOLE)
786 case VideoFrame::HOLE:
787 #endif // defined(VIDEO_HOLE)
788 case VideoFrame::NATIVE_TEXTURE:
789 break;
790 }
791 NOTREACHED() << "Unsupported video frame format/plane: "
792 << format_ << "/" << plane;
793 return 0;
794 }
795
data(size_t plane) const796 uint8* VideoFrame::data(size_t plane) const {
797 DCHECK(IsValidPlane(plane));
798 return data_[plane];
799 }
800
mailbox_holder() const801 const gpu::MailboxHolder* VideoFrame::mailbox_holder() const {
802 DCHECK_EQ(format_, NATIVE_TEXTURE);
803 return mailbox_holder_.get();
804 }
805
shared_memory_handle() const806 base::SharedMemoryHandle VideoFrame::shared_memory_handle() const {
807 return shared_memory_handle_;
808 }
809
AppendReleaseSyncPoint(uint32 sync_point)810 void VideoFrame::AppendReleaseSyncPoint(uint32 sync_point) {
811 DCHECK_EQ(format_, NATIVE_TEXTURE);
812 if (!sync_point)
813 return;
814 base::AutoLock locker(release_sync_point_lock_);
815 release_sync_points_.push_back(sync_point);
816 }
817
818 #if defined(OS_POSIX)
dmabuf_fd(size_t plane) const819 int VideoFrame::dmabuf_fd(size_t plane) const {
820 return dmabuf_fds_[plane].get();
821 }
822 #endif
823
HashFrameForTesting(base::MD5Context * context)824 void VideoFrame::HashFrameForTesting(base::MD5Context* context) {
825 for (int plane = 0; plane < kMaxPlanes; ++plane) {
826 if (!IsValidPlane(plane))
827 break;
828 for (int row = 0; row < rows(plane); ++row) {
829 base::MD5Update(context, base::StringPiece(
830 reinterpret_cast<char*>(data(plane) + stride(plane) * row),
831 row_bytes(plane)));
832 }
833 }
834 }
835
836 } // namespace media
837