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