Home | History | Annotate | Download | only in base
      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 
     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
     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
     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
    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
    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 
    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
    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
    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
    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
    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
    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
    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
    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 (at) chromium.org
    372 // ycheo (at) chromium.org
    373 
    374 // static
    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
    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
    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
    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 
    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
    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().
    571 static void ReleaseData(uint8* data) {
    572   DCHECK(data);
    573   base::AlignedFree(data);
    574 }
    575 
    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 
    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 
    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 
    664 bool VideoFrame::IsValidPlane(size_t plane) const {
    665   return (plane < NumPlanes(format_));
    666 }
    667 
    668 int VideoFrame::stride(size_t plane) const {
    669   DCHECK(IsValidPlane(plane));
    670   return strides_[plane];
    671 }
    672 
    673 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 
    734 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 
    796 uint8* VideoFrame::data(size_t plane) const {
    797   DCHECK(IsValidPlane(plane));
    798   return data_[plane];
    799 }
    800 
    801 const gpu::MailboxHolder* VideoFrame::mailbox_holder() const {
    802   DCHECK_EQ(format_, NATIVE_TEXTURE);
    803   return mailbox_holder_.get();
    804 }
    805 
    806 base::SharedMemoryHandle VideoFrame::shared_memory_handle() const {
    807   return shared_memory_handle_;
    808 }
    809 
    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)
    819 int VideoFrame::dmabuf_fd(size_t plane) const {
    820   return dmabuf_fds_[plane].get();
    821 }
    822 #endif
    823 
    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