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 "media/base/limits.h"
     15 #include "media/base/video_util.h"
     16 #include "third_party/skia/include/core/SkBitmap.h"
     17 
     18 namespace media {
     19 
     20 // static
     21 scoped_refptr<VideoFrame> VideoFrame::CreateFrame(
     22     VideoFrame::Format format,
     23     const gfx::Size& coded_size,
     24     const gfx::Rect& visible_rect,
     25     const gfx::Size& natural_size,
     26     base::TimeDelta timestamp) {
     27   DCHECK(IsValidConfig(format, coded_size, visible_rect, natural_size));
     28   scoped_refptr<VideoFrame> frame(new VideoFrame(
     29       format, coded_size, visible_rect, natural_size, timestamp, false));
     30   switch (format) {
     31     case VideoFrame::YV12:
     32     case VideoFrame::YV12A:
     33     case VideoFrame::YV16:
     34     case VideoFrame::I420:
     35     case VideoFrame::YV12J:
     36       frame->AllocateYUV();
     37       break;
     38     default:
     39       LOG(FATAL) << "Unsupported frame format: " << format;
     40   }
     41   return frame;
     42 }
     43 
     44 // static
     45 std::string VideoFrame::FormatToString(VideoFrame::Format format) {
     46   switch (format) {
     47     case VideoFrame::UNKNOWN:
     48       return "UNKNOWN";
     49     case VideoFrame::YV12:
     50       return "YV12";
     51     case VideoFrame::YV16:
     52       return "YV16";
     53     case VideoFrame::I420:
     54       return "I420";
     55     case VideoFrame::NATIVE_TEXTURE:
     56       return "NATIVE_TEXTURE";
     57 #if defined(VIDEO_HOLE)
     58     case VideoFrame::HOLE:
     59       return "HOLE";
     60 #endif  // defined(VIDEO_HOLE)
     61     case VideoFrame::YV12A:
     62       return "YV12A";
     63     case VideoFrame::YV12J:
     64       return "YV12J";
     65     case VideoFrame::HISTOGRAM_MAX:
     66       return "HISTOGRAM_MAX";
     67   }
     68   NOTREACHED() << "Invalid videoframe format provided: " << format;
     69   return "";
     70 }
     71 
     72 // static
     73 bool VideoFrame::IsValidConfig(VideoFrame::Format format,
     74                                const gfx::Size& coded_size,
     75                                const gfx::Rect& visible_rect,
     76                                const gfx::Size& natural_size) {
     77   return (format != VideoFrame::UNKNOWN &&
     78           !coded_size.IsEmpty() &&
     79           coded_size.GetArea() <= limits::kMaxCanvas &&
     80           coded_size.width() <= limits::kMaxDimension &&
     81           coded_size.height() <= limits::kMaxDimension &&
     82           !visible_rect.IsEmpty() &&
     83           visible_rect.x() >= 0 && visible_rect.y() >= 0 &&
     84           visible_rect.right() <= coded_size.width() &&
     85           visible_rect.bottom() <= coded_size.height() &&
     86           !natural_size.IsEmpty() &&
     87           natural_size.GetArea() <= limits::kMaxCanvas &&
     88           natural_size.width() <= limits::kMaxDimension &&
     89           natural_size.height() <= limits::kMaxDimension);
     90 }
     91 
     92 // static
     93 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
     94     scoped_ptr<MailboxHolder> mailbox_holder,
     95     uint32 texture_target,
     96     const gfx::Size& coded_size,
     97     const gfx::Rect& visible_rect,
     98     const gfx::Size& natural_size,
     99     base::TimeDelta timestamp,
    100     const ReadPixelsCB& read_pixels_cb,
    101     const base::Closure& no_longer_needed_cb) {
    102   scoped_refptr<VideoFrame> frame(new VideoFrame(NATIVE_TEXTURE,
    103                                                  coded_size,
    104                                                  visible_rect,
    105                                                  natural_size,
    106                                                  timestamp,
    107                                                  false));
    108   frame->texture_mailbox_holder_ = mailbox_holder.Pass();
    109   frame->texture_target_ = texture_target;
    110   frame->read_pixels_cb_ = read_pixels_cb;
    111   frame->no_longer_needed_cb_ = no_longer_needed_cb;
    112 
    113   return frame;
    114 }
    115 
    116 void VideoFrame::ReadPixelsFromNativeTexture(const SkBitmap& pixels) {
    117   DCHECK_EQ(format_, NATIVE_TEXTURE);
    118   if (!read_pixels_cb_.is_null())
    119     read_pixels_cb_.Run(pixels);
    120 }
    121 
    122 // static
    123 scoped_refptr<VideoFrame> VideoFrame::WrapExternalPackedMemory(
    124     Format format,
    125     const gfx::Size& coded_size,
    126     const gfx::Rect& visible_rect,
    127     const gfx::Size& natural_size,
    128     uint8* data,
    129     size_t data_size,
    130     base::SharedMemoryHandle handle,
    131     base::TimeDelta timestamp,
    132     const base::Closure& no_longer_needed_cb) {
    133   if (data_size < AllocationSize(format, coded_size))
    134     return NULL;
    135 
    136   switch (format) {
    137     case I420: {
    138       scoped_refptr<VideoFrame> frame(new VideoFrame(
    139           format, coded_size, visible_rect, natural_size, timestamp, false));
    140       frame->shared_memory_handle_ = handle;
    141       frame->strides_[kYPlane] = coded_size.width();
    142       frame->strides_[kUPlane] = coded_size.width() / 2;
    143       frame->strides_[kVPlane] = coded_size.width() / 2;
    144       frame->data_[kYPlane] = data;
    145       frame->data_[kUPlane] = data + coded_size.GetArea();
    146       frame->data_[kVPlane] = data + (coded_size.GetArea() * 5 / 4);
    147       frame->no_longer_needed_cb_ = no_longer_needed_cb;
    148       return frame;
    149     }
    150     default:
    151       NOTIMPLEMENTED();
    152       return NULL;
    153   }
    154 }
    155 
    156 // static
    157 scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvData(
    158     Format format,
    159     const gfx::Size& coded_size,
    160     const gfx::Rect& visible_rect,
    161     const gfx::Size& natural_size,
    162     int32 y_stride,
    163     int32 u_stride,
    164     int32 v_stride,
    165     uint8* y_data,
    166     uint8* u_data,
    167     uint8* v_data,
    168     base::TimeDelta timestamp,
    169     const base::Closure& no_longer_needed_cb) {
    170   DCHECK(format == YV12 || format == YV16 || format == I420) << format;
    171   scoped_refptr<VideoFrame> frame(new VideoFrame(
    172       format, coded_size, visible_rect, natural_size, timestamp, false));
    173   frame->strides_[kYPlane] = y_stride;
    174   frame->strides_[kUPlane] = u_stride;
    175   frame->strides_[kVPlane] = v_stride;
    176   frame->data_[kYPlane] = y_data;
    177   frame->data_[kUPlane] = u_data;
    178   frame->data_[kVPlane] = v_data;
    179   frame->no_longer_needed_cb_ = no_longer_needed_cb;
    180   return frame;
    181 }
    182 
    183 // static
    184 scoped_refptr<VideoFrame> VideoFrame::WrapVideoFrame(
    185       const scoped_refptr<VideoFrame>& frame,
    186       const base::Closure& no_longer_needed_cb) {
    187   scoped_refptr<VideoFrame> wrapped_frame(new VideoFrame(
    188       frame->format(), frame->coded_size(), frame->visible_rect(),
    189       frame->natural_size(), frame->GetTimestamp(), frame->end_of_stream()));
    190 
    191   for (size_t i = 0; i < NumPlanes(frame->format()); ++i) {
    192     wrapped_frame->strides_[i] = frame->stride(i);
    193     wrapped_frame->data_[i] = frame->data(i);
    194   }
    195 
    196   wrapped_frame->no_longer_needed_cb_ = no_longer_needed_cb;
    197   return wrapped_frame;
    198 }
    199 
    200 // static
    201 scoped_refptr<VideoFrame> VideoFrame::CreateEOSFrame() {
    202   return new VideoFrame(VideoFrame::UNKNOWN,
    203                         gfx::Size(),
    204                         gfx::Rect(),
    205                         gfx::Size(),
    206                         kNoTimestamp(),
    207                         true);
    208 }
    209 
    210 // static
    211 scoped_refptr<VideoFrame> VideoFrame::CreateColorFrame(
    212     const gfx::Size& size,
    213     uint8 y, uint8 u, uint8 v,
    214     base::TimeDelta timestamp) {
    215   DCHECK(IsValidConfig(VideoFrame::YV12, size, gfx::Rect(size), size));
    216   scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
    217       VideoFrame::YV12, size, gfx::Rect(size), size, timestamp);
    218   FillYUV(frame.get(), y, u, v);
    219   return frame;
    220 }
    221 
    222 // static
    223 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(const gfx::Size& size) {
    224   const uint8 kBlackY = 0x00;
    225   const uint8 kBlackUV = 0x80;
    226   const base::TimeDelta kZero;
    227   return CreateColorFrame(size, kBlackY, kBlackUV, kBlackUV, kZero);
    228 }
    229 
    230 #if defined(VIDEO_HOLE)
    231 // This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not
    232 // maintained by the general compositor team. Please contact the following
    233 // people instead:
    234 //
    235 // wonsik (at) chromium.org
    236 // ycheo (at) chromium.org
    237 
    238 // static
    239 scoped_refptr<VideoFrame> VideoFrame::CreateHoleFrame(
    240     const gfx::Size& size) {
    241   DCHECK(IsValidConfig(VideoFrame::HOLE, size, gfx::Rect(size), size));
    242   scoped_refptr<VideoFrame> frame(new VideoFrame(
    243       VideoFrame::HOLE, size, gfx::Rect(size), size, base::TimeDelta(), false));
    244   return frame;
    245 }
    246 #endif  // defined(VIDEO_HOLE)
    247 
    248 // static
    249 size_t VideoFrame::NumPlanes(Format format) {
    250   switch (format) {
    251     case VideoFrame::NATIVE_TEXTURE:
    252 #if defined(VIDEO_HOLE)
    253     case VideoFrame::HOLE:
    254 #endif  // defined(VIDEO_HOLE)
    255       return 0;
    256     case VideoFrame::YV12:
    257     case VideoFrame::YV16:
    258     case VideoFrame::I420:
    259     case VideoFrame::YV12J:
    260       return 3;
    261     case VideoFrame::YV12A:
    262       return 4;
    263     case VideoFrame::UNKNOWN:
    264     case VideoFrame::HISTOGRAM_MAX:
    265       break;
    266   }
    267   NOTREACHED() << "Unsupported video frame format: " << format;
    268   return 0;
    269 }
    270 
    271 static inline size_t RoundUp(size_t value, size_t alignment) {
    272   // Check that |alignment| is a power of 2.
    273   DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1)));
    274   return ((value + (alignment - 1)) & ~(alignment-1));
    275 }
    276 
    277 // static
    278 size_t VideoFrame::AllocationSize(Format format, const gfx::Size& coded_size) {
    279   size_t total = 0;
    280   for (size_t i = 0; i < NumPlanes(format); ++i)
    281     total += PlaneAllocationSize(format, i, coded_size);
    282   return total;
    283 }
    284 
    285 // static
    286 size_t VideoFrame::PlaneAllocationSize(Format format,
    287                                        size_t plane,
    288                                        const gfx::Size& coded_size) {
    289   const size_t area =
    290       RoundUp(coded_size.width(), 2) * RoundUp(coded_size.height(), 2);
    291   switch (format) {
    292     case VideoFrame::YV12:
    293     case VideoFrame::YV12J:
    294     case VideoFrame::I420: {
    295       switch (plane) {
    296         case VideoFrame::kYPlane:
    297           return area;
    298         case VideoFrame::kUPlane:
    299         case VideoFrame::kVPlane:
    300           return area / 4;
    301         default:
    302           break;
    303       }
    304     }
    305     case VideoFrame::YV12A: {
    306       switch (plane) {
    307         case VideoFrame::kYPlane:
    308         case VideoFrame::kAPlane:
    309           return area;
    310         case VideoFrame::kUPlane:
    311         case VideoFrame::kVPlane:
    312           return area / 4;
    313         default:
    314           break;
    315       }
    316     }
    317     case VideoFrame::YV16: {
    318       switch (plane) {
    319         case VideoFrame::kYPlane:
    320           return area;
    321         case VideoFrame::kUPlane:
    322         case VideoFrame::kVPlane:
    323           return area / 2;
    324         default:
    325           break;
    326       }
    327     }
    328     case VideoFrame::UNKNOWN:
    329     case VideoFrame::NATIVE_TEXTURE:
    330     case VideoFrame::HISTOGRAM_MAX:
    331 #if defined(VIDEO_HOLE)
    332     case VideoFrame::HOLE:
    333 #endif  // defined(VIDEO_HOLE)
    334       break;
    335   }
    336   NOTREACHED() << "Unsupported video frame format/plane: "
    337                << format << "/" << plane;
    338   return 0;
    339 }
    340 
    341 // Release data allocated by AllocateYUV().
    342 static void ReleaseData(uint8* data) {
    343   DCHECK(data);
    344   base::AlignedFree(data);
    345 }
    346 
    347 void VideoFrame::AllocateYUV() {
    348   DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 ||
    349          format_ == VideoFrame::YV12A || format_ == VideoFrame::I420 ||
    350          format_ == VideoFrame::YV12J);
    351   // Align Y rows at least at 16 byte boundaries.  The stride for both
    352   // YV12 and YV16 is 1/2 of the stride of Y.  For YV12, every row of bytes for
    353   // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in
    354   // the case of YV12 the strides are identical for the same width surface, but
    355   // the number of bytes allocated for YV12 is 1/2 the amount for U & V as
    356   // YV16. We also round the height of the surface allocated to be an even
    357   // number to avoid any potential of faulting by code that attempts to access
    358   // the Y values of the final row, but assumes that the last row of U & V
    359   // applies to a full two rows of Y. YV12A is the same as YV12, but with an
    360   // additional alpha plane that has the same size and alignment as the Y plane.
    361 
    362   size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane),
    363                             kFrameSizeAlignment);
    364   size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane),
    365                              kFrameSizeAlignment);
    366   // The *2 here is because some formats (e.g. h264) allow interlaced coding,
    367   // and then the size needs to be a multiple of two macroblocks (vertically).
    368   // See libavcodec/utils.c:avcodec_align_dimensions2().
    369   size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2);
    370   size_t uv_height =
    371       (format_ == VideoFrame::YV12 || format_ == VideoFrame::YV12A ||
    372        format_ == VideoFrame::I420)
    373           ? y_height / 2
    374           : y_height;
    375   size_t y_bytes = y_height * y_stride;
    376   size_t uv_bytes = uv_height * uv_stride;
    377   size_t a_bytes = format_ == VideoFrame::YV12A ? y_bytes : 0;
    378 
    379   // The extra line of UV being allocated is because h264 chroma MC
    380   // overreads by one line in some cases, see libavcodec/utils.c:
    381   // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
    382   // put_h264_chroma_mc4_ssse3().
    383   uint8* data = reinterpret_cast<uint8*>(
    384       base::AlignedAlloc(
    385           y_bytes + (uv_bytes * 2 + uv_stride) + a_bytes + kFrameSizePadding,
    386           kFrameAddressAlignment));
    387   no_longer_needed_cb_ = base::Bind(&ReleaseData, data);
    388   COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0);
    389   data_[VideoFrame::kYPlane] = data;
    390   data_[VideoFrame::kUPlane] = data + y_bytes;
    391   data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes;
    392   strides_[VideoFrame::kYPlane] = y_stride;
    393   strides_[VideoFrame::kUPlane] = uv_stride;
    394   strides_[VideoFrame::kVPlane] = uv_stride;
    395   if (format_ == YV12A) {
    396     data_[VideoFrame::kAPlane] = data + y_bytes + (2 * uv_bytes);
    397     strides_[VideoFrame::kAPlane] = y_stride;
    398   }
    399 }
    400 
    401 VideoFrame::VideoFrame(VideoFrame::Format format,
    402                        const gfx::Size& coded_size,
    403                        const gfx::Rect& visible_rect,
    404                        const gfx::Size& natural_size,
    405                        base::TimeDelta timestamp,
    406                        bool end_of_stream)
    407     : format_(format),
    408       coded_size_(coded_size),
    409       visible_rect_(visible_rect),
    410       natural_size_(natural_size),
    411       texture_target_(0),
    412       shared_memory_handle_(base::SharedMemory::NULLHandle()),
    413       timestamp_(timestamp),
    414       end_of_stream_(end_of_stream) {
    415   memset(&strides_, 0, sizeof(strides_));
    416   memset(&data_, 0, sizeof(data_));
    417 }
    418 
    419 VideoFrame::~VideoFrame() {
    420   if (!no_longer_needed_cb_.is_null())
    421     base::ResetAndReturn(&no_longer_needed_cb_).Run();
    422 }
    423 
    424 bool VideoFrame::IsValidPlane(size_t plane) const {
    425   return (plane < NumPlanes(format_));
    426 }
    427 
    428 int VideoFrame::stride(size_t plane) const {
    429   DCHECK(IsValidPlane(plane));
    430   return strides_[plane];
    431 }
    432 
    433 int VideoFrame::row_bytes(size_t plane) const {
    434   DCHECK(IsValidPlane(plane));
    435   int width = coded_size_.width();
    436   switch (format_) {
    437     // Planar, 8bpp.
    438     case YV12A:
    439       if (plane == kAPlane)
    440         return width;
    441     // Fallthrough.
    442     case YV12:
    443     case YV16:
    444     case I420:
    445     case YV12J:
    446       if (plane == kYPlane)
    447         return width;
    448       return RoundUp(width, 2) / 2;
    449 
    450     default:
    451       break;
    452   }
    453 
    454   // Intentionally leave out non-production formats.
    455   NOTREACHED() << "Unsupported video frame format: " << format_;
    456   return 0;
    457 }
    458 
    459 int VideoFrame::rows(size_t plane) const {
    460   DCHECK(IsValidPlane(plane));
    461   int height = coded_size_.height();
    462   switch (format_) {
    463     case YV16:
    464       return height;
    465 
    466     case YV12A:
    467       if (plane == kAPlane)
    468         return height;
    469     // Fallthrough.
    470     case YV12:
    471     case I420:
    472       if (plane == kYPlane)
    473         return height;
    474       return RoundUp(height, 2) / 2;
    475 
    476     default:
    477       break;
    478   }
    479 
    480   // Intentionally leave out non-production formats.
    481   NOTREACHED() << "Unsupported video frame format: " << format_;
    482   return 0;
    483 }
    484 
    485 uint8* VideoFrame::data(size_t plane) const {
    486   DCHECK(IsValidPlane(plane));
    487   return data_[plane];
    488 }
    489 
    490 VideoFrame::MailboxHolder* VideoFrame::texture_mailbox() const {
    491   DCHECK_EQ(format_, NATIVE_TEXTURE);
    492   return texture_mailbox_holder_.get();
    493 }
    494 
    495 uint32 VideoFrame::texture_target() const {
    496   DCHECK_EQ(format_, NATIVE_TEXTURE);
    497   return texture_target_;
    498 }
    499 
    500 base::SharedMemoryHandle VideoFrame::shared_memory_handle() const {
    501   return shared_memory_handle_;
    502 }
    503 
    504 void VideoFrame::HashFrameForTesting(base::MD5Context* context) {
    505   for (int plane = 0; plane < kMaxPlanes; ++plane) {
    506     if (!IsValidPlane(plane))
    507       break;
    508     for (int row = 0; row < rows(plane); ++row) {
    509       base::MD5Update(context, base::StringPiece(
    510           reinterpret_cast<char*>(data(plane) + stride(plane) * row),
    511           row_bytes(plane)));
    512     }
    513   }
    514 }
    515 
    516 VideoFrame::MailboxHolder::MailboxHolder(
    517     const gpu::Mailbox& mailbox,
    518     unsigned sync_point,
    519     const TextureNoLongerNeededCallback& release_callback)
    520     : mailbox_(mailbox),
    521       sync_point_(sync_point),
    522       release_callback_(release_callback) {}
    523 
    524 VideoFrame::MailboxHolder::~MailboxHolder() {
    525   if (!release_callback_.is_null())
    526     release_callback_.Run(sync_point_);
    527 }
    528 
    529 }  // namespace media
    530