video_frame.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1accaf19bc1129c0273ec50dba52318e60bc29103Benjamin Kramer// Copyright (c) 2012 The Chromium Authors. All rights reserved.
27196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// Use of this source code is governed by a BSD-style license that can be
37196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// found in the LICENSE file.
47196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
57196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#include "media/base/video_frame.h"
67196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
77196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#include "base/logging.h"
87196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#include "base/string_piece.h"
97196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#include "media/base/limits.h"
107196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#include "media/base/video_util.h"
117196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#if !defined(OS_ANDROID)
127196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#include "media/ffmpeg/ffmpeg_common.h"
137196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#endif
147196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
15684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis#include <algorithm>
167196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
177196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisnamespace media {
187196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
197196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// static
207196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisscoped_refptr<VideoFrame> VideoFrame::CreateFrame(
217196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    VideoFrame::Format format,
227196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    const gfx::Size& coded_size,
237196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    const gfx::Rect& visible_rect,
24684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis    const gfx::Size& natural_size,
25684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis    base::TimeDelta timestamp) {
267196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  DCHECK(IsValidConfig(format, coded_size, visible_rect, natural_size));
277196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  scoped_refptr<VideoFrame> frame(new VideoFrame(
287196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      format, coded_size, visible_rect, natural_size, timestamp));
297196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  switch (format) {
307196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    case VideoFrame::RGB32:
317196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      frame->AllocateRGB(4u);
327196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      break;
335d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis    case VideoFrame::YV12:
345d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis    case VideoFrame::YV16:
355d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis      frame->AllocateYUV();
365d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis      break;
375d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis    default:
385d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis      LOG(FATAL) << "Unsupported frame format: " << format;
395d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  }
405d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  return frame;
417196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis}
427196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
437196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// static
447196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisbool VideoFrame::IsValidConfig(VideoFrame::Format format,
45471c8b49982d1132f30b0b0da27fef94fd6e4f67Benjamin Kramer                               const gfx::Size& coded_size,
462fa67efeaf66a9332c30a026dc1c21bef6c33a6cBenjamin Kramer                               const gfx::Rect& visible_rect,
4718fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis                               const gfx::Size& natural_size) {
482fa67efeaf66a9332c30a026dc1c21bef6c33a6cBenjamin Kramer  return (format != VideoFrame::INVALID &&
497196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          !coded_size.IsEmpty() &&
50471c8b49982d1132f30b0b0da27fef94fd6e4f67Benjamin Kramer          coded_size.GetArea() <= limits::kMaxCanvas &&
51471c8b49982d1132f30b0b0da27fef94fd6e4f67Benjamin Kramer          coded_size.width() <= limits::kMaxDimension &&
528fe83e1df954d72c0f4ffc15d20a5222ec151c21Benjamin Kramer          coded_size.height() <= limits::kMaxDimension &&
537196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          !visible_rect.IsEmpty() &&
547196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          visible_rect.x() >= 0 && visible_rect.y() >= 0 &&
557196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          visible_rect.right() <= coded_size.width() &&
567196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          visible_rect.bottom() <= coded_size.height() &&
577196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          !natural_size.IsEmpty() &&
587196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          natural_size.GetArea() <= limits::kMaxCanvas &&
597196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          natural_size.width() <= limits::kMaxDimension &&
607196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis          natural_size.height() <= limits::kMaxDimension);
617196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis}
627196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
63651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// static
6476a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidisscoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
655d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis    uint32 texture_id,
66651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    uint32 texture_target,
6718fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis    const gfx::Size& coded_size,
687196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    const gfx::Rect& visible_rect,
695d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis    const gfx::Size& natural_size,
707196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    base::TimeDelta timestamp,
717196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    const ReadPixelsCB& read_pixels_cb,
727196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    const base::Closure& no_longer_needed) {
7376a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis  scoped_refptr<VideoFrame> frame(
7476a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis      new VideoFrame(NATIVE_TEXTURE, coded_size, visible_rect, natural_size,
755d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis                     timestamp));
7618fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis  frame->texture_id_ = texture_id;
7718fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis  frame->texture_target_ = texture_target;
7818fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis  frame->read_pixels_cb_ = read_pixels_cb;
7918fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis  frame->texture_no_longer_needed_ = no_longer_needed;
8024016765c905a02c9df94ef0b8a50c5e74fff5c2Argyrios Kyrtzidis  return frame;
8124016765c905a02c9df94ef0b8a50c5e74fff5c2Argyrios Kyrtzidis}
8224016765c905a02c9df94ef0b8a50c5e74fff5c2Argyrios Kyrtzidis
8324016765c905a02c9df94ef0b8a50c5e74fff5c2Argyrios Kyrtzidisvoid VideoFrame::ReadPixelsFromNativeTexture(void* pixels) {
8424016765c905a02c9df94ef0b8a50c5e74fff5c2Argyrios Kyrtzidis  DCHECK_EQ(format_, NATIVE_TEXTURE);
8524016765c905a02c9df94ef0b8a50c5e74fff5c2Argyrios Kyrtzidis  if (!read_pixels_cb_.is_null())
8624016765c905a02c9df94ef0b8a50c5e74fff5c2Argyrios Kyrtzidis    read_pixels_cb_.Run(pixels);
877196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis}
885d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis
895d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis// static
905d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidisscoped_refptr<VideoFrame> VideoFrame::CreateEmptyFrame() {
917196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  return new VideoFrame(
927196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      VideoFrame::EMPTY, gfx::Size(), gfx::Rect(), gfx::Size(),
937196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      base::TimeDelta());
947196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis}
957196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
967196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// static
975d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidisscoped_refptr<VideoFrame> VideoFrame::CreateColorFrame(
987196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    const gfx::Size& size,
997196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    uint8 y, uint8 u, uint8 v,
1007196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    base::TimeDelta timestamp) {
1017196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  DCHECK(IsValidConfig(VideoFrame::YV12, size, gfx::Rect(size), size));
1027196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
1037196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      VideoFrame::YV12, size, gfx::Rect(size), size, timestamp);
1047196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  FillYUV(frame, y, u, v);
1057196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  return frame;
1067196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis}
1077196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1087196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// static
1097196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisscoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(const gfx::Size& size) {
1107196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  const uint8 kBlackY = 0x00;
1117196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  const uint8 kBlackUV = 0x80;
1125d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  const base::TimeDelta kZero;
1137196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  return CreateColorFrame(size, kBlackY, kBlackUV, kBlackUV, kZero);
1147196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis}
1157196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1167196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisstatic inline size_t RoundUp(size_t value, size_t alignment) {
1177196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // Check that |alignment| is a power of 2.
1187196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1)));
1197196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  return ((value + (alignment - 1)) & ~(alignment-1));
1207196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis}
1217196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1227196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisstatic const int kFrameSizeAlignment = 16;
1237196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis// Allows faster SIMD YUV convert. Also, FFmpeg overreads/-writes occasionally.
1247196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisstatic const int kFramePadBytes = 15;
1257196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1267196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisvoid VideoFrame::AllocateRGB(size_t bytes_per_pixel) {
1277196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // Round up to align at least at a 16-byte boundary for each row.
1287196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // This is sufficient for MMX and SSE2 reads (movq/movdqa).
1297196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  size_t bytes_per_row = RoundUp(coded_size_.width(),
1307196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis                                 kFrameSizeAlignment) * bytes_per_pixel;
1317196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  size_t aligned_height = RoundUp(coded_size_.height(), kFrameSizeAlignment);
1327196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  strides_[VideoFrame::kRGBPlane] = bytes_per_row;
1337196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#if !defined(OS_ANDROID)
1347196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // TODO(dalecurtis): use DataAligned or so, so this #ifdef hackery
1357196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // doesn't need to be repeated in every single user of aligned data.
136651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  data_[VideoFrame::kRGBPlane] = reinterpret_cast<uint8*>(
1377196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      av_malloc(bytes_per_row * aligned_height + kFramePadBytes));
1387196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#else
1397196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  data_[VideoFrame::kRGBPlane] = new uint8_t[bytes_per_row * aligned_height];
140651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#endif
1417196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7));
1427196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0);
1437196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis}
1447196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1457196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisvoid VideoFrame::AllocateYUV() {
1467196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16);
1477196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // Align Y rows at least at 16 byte boundaries.  The stride for both
1487196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // YV12 and YV16 is 1/2 of the stride of Y.  For YV12, every row of bytes for
1497196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in
1507196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // the case of YV12 the strides are identical for the same width surface, but
1517196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // the number of bytes allocated for YV12 is 1/2 the amount for U & V as
1522908ffbc5f54323f150405fa2b06f50788ae55c7Fariborz Jahanian  // YV16. We also round the height of the surface allocated to be an even
1532908ffbc5f54323f150405fa2b06f50788ae55c7Fariborz Jahanian  // number to avoid any potential of faulting by code that attempts to access
1542908ffbc5f54323f150405fa2b06f50788ae55c7Fariborz Jahanian  // the Y values of the final row, but assumes that the last row of U & V
1552908ffbc5f54323f150405fa2b06f50788ae55c7Fariborz Jahanian  // applies to a full two rows of Y.
1562908ffbc5f54323f150405fa2b06f50788ae55c7Fariborz Jahanian  size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane),
1572908ffbc5f54323f150405fa2b06f50788ae55c7Fariborz Jahanian                            kFrameSizeAlignment);
158181e3ecc0907ae0103586a9f4db52241995a8267Rafael Espindola  size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane),
1592908ffbc5f54323f150405fa2b06f50788ae55c7Fariborz Jahanian                             kFrameSizeAlignment);
1609c7aed308aa701e0ba573c04ebe8d17a4c1486c4Fariborz Jahanian  // The *2 here is because some formats (e.g. h264) allow interlaced coding,
1612908ffbc5f54323f150405fa2b06f50788ae55c7Fariborz Jahanian  // and then the size needs to be a multiple of two macroblocks (vertically).
1622908ffbc5f54323f150405fa2b06f50788ae55c7Fariborz Jahanian  // See libavcodec/utils.c:avcodec_align_dimensions2().
1632908ffbc5f54323f150405fa2b06f50788ae55c7Fariborz Jahanian  size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2);
1642908ffbc5f54323f150405fa2b06f50788ae55c7Fariborz Jahanian  size_t uv_height = format_ == VideoFrame::YV12 ? y_height / 2 : y_height;
1652908ffbc5f54323f150405fa2b06f50788ae55c7Fariborz Jahanian  size_t y_bytes = y_height * y_stride;
1662908ffbc5f54323f150405fa2b06f50788ae55c7Fariborz Jahanian  size_t uv_bytes = uv_height * uv_stride;
1677196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
1687196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#if !defined(OS_ANDROID)
1697196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // TODO(dalecurtis): use DataAligned or so, so this #ifdef hackery
1707196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // doesn't need to be repeated in every single user of aligned data.
1717196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // The extra line of UV being allocated is because h264 chroma MC
1727196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // overreads by one line in some cases, see libavcodec/utils.c:
1737196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
1747196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // put_h264_chroma_mc4_ssse3().
1757196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  uint8* data = reinterpret_cast<uint8*>(
1767196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      av_malloc(y_bytes + (uv_bytes * 2 + uv_stride) + kFramePadBytes));
1777196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#else
17876a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis  uint8* data = new uint8_t[y_bytes + (uv_bytes * 2)];
17976a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis#endif
18076a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis  COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0);
18176a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis  data_[VideoFrame::kYPlane] = data;
18276a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis  data_[VideoFrame::kUPlane] = data + y_bytes;
18376a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis  data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes;
18476a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis  strides_[VideoFrame::kYPlane] = y_stride;
18576a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis  strides_[VideoFrame::kUPlane] = uv_stride;
18676a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis  strides_[VideoFrame::kVPlane] = uv_stride;
18776a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis}
18876a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis
18976a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios KyrtzidisVideoFrame::VideoFrame(VideoFrame::Format format,
19076a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis                       const gfx::Size& coded_size,
19176a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis                       const gfx::Rect& visible_rect,
19276a5245d7fb558625453ebe2281ee0bc9c93c245Argyrios Kyrtzidis                       const gfx::Size& natural_size,
1937196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis                       base::TimeDelta timestamp)
1947196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    : format_(format),
1957196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      coded_size_(coded_size),
1967196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      visible_rect_(visible_rect),
1977196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      natural_size_(natural_size),
1987196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      texture_id_(0),
1997196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      texture_target_(0),
20018fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis      timestamp_(timestamp) {
20118fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis  memset(&strides_, 0, sizeof(strides_));
20218fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis  memset(&data_, 0, sizeof(data_));
20318fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis}
20418fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis
20518fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios KyrtzidisVideoFrame::~VideoFrame() {
2067196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  if (format_ == NATIVE_TEXTURE && !texture_no_longer_needed_.is_null()) {
2077196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    texture_no_longer_needed_.Run();
2087196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    texture_no_longer_needed_.Reset();
2097196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  }
2107196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
21118fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis  // In multi-plane allocations, only a single block of memory is allocated
21218fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis  // on the heap, and other |data| pointers point inside the same, single block
2137196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  // so just delete index 0.
21418fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis  if (data_[0]) {
2157196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#if !defined(OS_ANDROID)
2167196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    av_free(data_[0]);
2177196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#else
2187196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    delete[] data_[0];
2197196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis#endif
2207196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  }
2217196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis}
2227196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
2237196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisbool VideoFrame::IsValidPlane(size_t plane) const {
2247196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  switch (format_) {
2257196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    case RGB32:
2267196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis      return plane == kRGBPlane;
2277196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
2287196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    case YV12:
229684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis    case YV16:
230684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis      return plane == kYPlane || plane == kUPlane || plane == kVPlane;
231684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis
2327196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis    case NATIVE_TEXTURE:
233684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis      NOTREACHED() << "NATIVE_TEXTUREs don't use plane-related methods!";
234684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis      return false;
2357196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
236684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis    default:
237684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis      break;
238684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis  }
239684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis
240684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis  // Intentionally leave out non-production formats.
241684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis  NOTREACHED() << "Unsupported video frame format: " << format_;
242684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis  return false;
243684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis}
244684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis
245684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidisint VideoFrame::stride(size_t plane) const {
246684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis  DCHECK(IsValidPlane(plane));
247684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis  return strides_[plane];
248684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis}
249684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis
250d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Roseint VideoFrame::row_bytes(size_t plane) const {
251d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose  DCHECK(IsValidPlane(plane));
252d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose  int width = coded_size_.width();
253d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose  switch (format_) {
254d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose    // 32bpp.
255d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose    case RGB32:
256d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose      return width * 4;
257d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose
258d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose    // Planar, 8bpp.
259d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose    case YV12:
260684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis    case YV16:
261d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose      if (plane == kYPlane)
262684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis        return width;
263d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose      return RoundUp(width, 2) / 2;
264684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis
265684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis    default:
266d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose      break;
267684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis  }
268d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose
269d880b3aa6d594d1a7f2d307c29378c6f59b216ffJordan Rose  // Intentionally leave out non-production formats.
270684190b8dbe5258f4708ffbd816b8c5ee5b3502dArgyrios Kyrtzidis  NOTREACHED() << "Unsupported video frame format: " << format_;
2717196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis  return 0;
2727196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis}
2737196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidis
2747196d06c2fb020a91a26e727be1871110b4a0dc9Argyrios Kyrtzidisint VideoFrame::rows(size_t plane) const {
27518fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis  DCHECK(IsValidPlane(plane));
27618fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis  int height = coded_size_.height();
27718fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis  switch (format_) {
27818fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis    case RGB32:
27918fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis    case YV16:
28018fd0c6915b45c4daafe18e3cd324c13306f913fArgyrios Kyrtzidis      return height;
2815d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis
2825d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis    case YV12:
2835d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis      if (plane == kYPlane)
2845d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis        return height;
2855d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis      return RoundUp(height, 2) / 2;
286651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
2875d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis    default:
2885d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis      break;
2895d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  }
2905d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis
2915d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  // Intentionally leave out non-production formats.
2925d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  NOTREACHED() << "Unsupported video frame format: " << format_;
2935d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  return 0;
2945d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis}
2955d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis
2965d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidisuint8* VideoFrame::data(size_t plane) const {
2975d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  DCHECK(IsValidPlane(plane));
2985d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  return data_[plane];
2995d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis}
3005d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis
3015d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidisuint32 VideoFrame::texture_id() const {
3025d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  DCHECK_EQ(format_, NATIVE_TEXTURE);
3035d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  return texture_id_;
3045d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis}
3055d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis
3065d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidisuint32 VideoFrame::texture_target() const {
3075d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  DCHECK_EQ(format_, NATIVE_TEXTURE);
3085d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  return texture_target_;
3095d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis}
3105d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis
3115d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidisbool VideoFrame::IsEndOfStream() const {
3125d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  return format_ == VideoFrame::EMPTY;
3135d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis}
3145d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis
3155d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidisvoid VideoFrame::HashFrameForTesting(base::MD5Context* context) {
3165d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  for(int plane = 0; plane < kMaxPlanes; plane++) {
3175d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis    if (!IsValidPlane(plane))
3185d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis      break;
3195d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis    for(int row = 0; row < rows(plane); row++) {
3205d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis      base::MD5Update(context, base::StringPiece(
3215d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis          reinterpret_cast<char*>(data(plane) + stride(plane) * row),
3225d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis          row_bytes(plane)));
3235d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis    }
3245d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis  }
3255d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis}
3265d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis
3275d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis}  // namespace media
3285d2faa41bc63a2a29535ae3dbbc99daabf14ea2fArgyrios Kyrtzidis