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 
     18 #if !defined(MEDIA_FOR_CAST_IOS)
     19 #include "third_party/skia/include/core/SkBitmap.h"
     20 #endif
     21 
     22 namespace media {
     23 
     24 static 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|.
     31 static 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
     51 scoped_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
     83 std::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
    113 bool 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
    166 scoped_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)
    188 void 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
    196 scoped_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
    241 scoped_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
    288 scoped_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
    332 scoped_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
    367 scoped_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
    396 scoped_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
    407 scoped_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
    418 scoped_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
    426 scoped_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 (at) chromium.org
    444 // ycheo (at) chromium.org
    445 
    446 // static
    447 scoped_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
    463 size_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
    489 size_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
    497 gfx::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 
    574 size_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
    582 int 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().
    643 static void ReleaseData(uint8* data) {
    644   DCHECK(data);
    645   base::AlignedFree(data);
    646 }
    647 
    648 void 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 
    705 VideoFrame::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 
    727 VideoFrame::~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
    743 bool VideoFrame::IsValidPlane(size_t plane, VideoFrame::Format format) {
    744   return (plane < NumPlanes(format));
    745 }
    746 
    747 int VideoFrame::stride(size_t plane) const {
    748   DCHECK(IsValidPlane(plane, format_));
    749   return strides_[plane];
    750 }
    751 
    752 // static
    753 size_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 
    814 int VideoFrame::row_bytes(size_t plane) const {
    815   return RowBytes(plane, format_, coded_size_.width());
    816 }
    817 
    818 // static
    819 size_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 
    880 int VideoFrame::rows(size_t plane) const {
    881   return Rows(plane, format_, coded_size_.height());
    882 }
    883 
    884 uint8* VideoFrame::data(size_t plane) const {
    885   DCHECK(IsValidPlane(plane, format_));
    886   return data_[plane];
    887 }
    888 
    889 const gpu::MailboxHolder* VideoFrame::mailbox_holder() const {
    890   DCHECK_EQ(format_, NATIVE_TEXTURE);
    891   return mailbox_holder_.get();
    892 }
    893 
    894 base::SharedMemoryHandle VideoFrame::shared_memory_handle() const {
    895   return shared_memory_handle_;
    896 }
    897 
    898 void 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)
    910 int VideoFrame::dmabuf_fd(size_t plane) const {
    911   return dmabuf_fds_[plane].get();
    912 }
    913 #endif
    914 
    915 #if defined(OS_MACOSX)
    916 CVPixelBufferRef VideoFrame::cv_pixel_buffer() const {
    917   return cv_pixel_buffer_.get();
    918 }
    919 #endif
    920 
    921 void 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