video_frame.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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
18namespace media {
19
20// static
21scoped_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));
30  switch (format) {
31    case VideoFrame::RGB32:
32      frame->AllocateRGB(4u);
33      break;
34    case VideoFrame::YV12:
35    case VideoFrame::YV12A:
36    case VideoFrame::YV16:
37      frame->AllocateYUV();
38      break;
39    default:
40      LOG(FATAL) << "Unsupported frame format: " << format;
41  }
42  return frame;
43}
44
45// static
46bool VideoFrame::IsValidConfig(VideoFrame::Format format,
47                               const gfx::Size& coded_size,
48                               const gfx::Rect& visible_rect,
49                               const gfx::Size& natural_size) {
50  return (format != VideoFrame::INVALID &&
51          !coded_size.IsEmpty() &&
52          coded_size.GetArea() <= limits::kMaxCanvas &&
53          coded_size.width() <= limits::kMaxDimension &&
54          coded_size.height() <= limits::kMaxDimension &&
55          !visible_rect.IsEmpty() &&
56          visible_rect.x() >= 0 && visible_rect.y() >= 0 &&
57          visible_rect.right() <= coded_size.width() &&
58          visible_rect.bottom() <= coded_size.height() &&
59          !natural_size.IsEmpty() &&
60          natural_size.GetArea() <= limits::kMaxCanvas &&
61          natural_size.width() <= limits::kMaxDimension &&
62          natural_size.height() <= limits::kMaxDimension);
63}
64
65// static
66scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
67    const scoped_refptr<MailboxHolder>& mailbox_holder,
68    uint32 texture_target,
69    const gfx::Size& coded_size,
70    const gfx::Rect& visible_rect,
71    const gfx::Size& natural_size,
72    base::TimeDelta timestamp,
73    const ReadPixelsCB& read_pixels_cb,
74    const base::Closure& no_longer_needed_cb) {
75  scoped_refptr<VideoFrame> frame(new VideoFrame(
76      NATIVE_TEXTURE, coded_size, visible_rect, natural_size, timestamp));
77  frame->texture_mailbox_holder_ = mailbox_holder;
78  frame->texture_target_ = texture_target;
79  frame->read_pixels_cb_ = read_pixels_cb;
80  frame->no_longer_needed_cb_ = no_longer_needed_cb;
81
82  return frame;
83}
84
85void VideoFrame::ReadPixelsFromNativeTexture(const SkBitmap& pixels) {
86  DCHECK_EQ(format_, NATIVE_TEXTURE);
87  if (!read_pixels_cb_.is_null())
88    read_pixels_cb_.Run(pixels);
89}
90
91// static
92scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvData(
93    Format format,
94    const gfx::Size& coded_size,
95    const gfx::Rect& visible_rect,
96    const gfx::Size& natural_size,
97    int32 y_stride, int32 u_stride, int32 v_stride,
98    uint8* y_data, uint8* u_data, uint8* v_data,
99    base::TimeDelta timestamp,
100    base::SharedMemoryHandle shm_handle,
101    const base::Closure& no_longer_needed_cb) {
102  DCHECK(format == YV12 || format == YV16 || format == I420) << format;
103  scoped_refptr<VideoFrame> frame(new VideoFrame(
104      format, coded_size, visible_rect, natural_size, timestamp));
105  frame->shared_memory_handle_ = shm_handle;
106  frame->strides_[kYPlane] = y_stride;
107  frame->strides_[kUPlane] = u_stride;
108  frame->strides_[kVPlane] = v_stride;
109  frame->data_[kYPlane] = y_data;
110  frame->data_[kUPlane] = u_data;
111  frame->data_[kVPlane] = v_data;
112  frame->no_longer_needed_cb_ = no_longer_needed_cb;
113  return frame;
114}
115
116// static
117scoped_refptr<VideoFrame> VideoFrame::CreateEmptyFrame() {
118  return new VideoFrame(
119      VideoFrame::EMPTY, gfx::Size(), gfx::Rect(), gfx::Size(),
120      base::TimeDelta());
121}
122
123// static
124scoped_refptr<VideoFrame> VideoFrame::CreateColorFrame(
125    const gfx::Size& size,
126    uint8 y, uint8 u, uint8 v,
127    base::TimeDelta timestamp) {
128  DCHECK(IsValidConfig(VideoFrame::YV12, size, gfx::Rect(size), size));
129  scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
130      VideoFrame::YV12, size, gfx::Rect(size), size, timestamp);
131  FillYUV(frame.get(), y, u, v);
132  return frame;
133}
134
135// static
136scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(const gfx::Size& size) {
137  const uint8 kBlackY = 0x00;
138  const uint8 kBlackUV = 0x80;
139  const base::TimeDelta kZero;
140  return CreateColorFrame(size, kBlackY, kBlackUV, kBlackUV, kZero);
141}
142
143#if defined(GOOGLE_TV)
144// This block and other blocks wrapped around #if defined(GOOGLE_TV) is not
145// maintained by the general compositor team. Please contact the following
146// people instead:
147//
148// wonsik@chromium.org
149// ycheo@chromium.org
150
151// static
152scoped_refptr<VideoFrame> VideoFrame::CreateHoleFrame(
153    const gfx::Size& size) {
154  DCHECK(IsValidConfig(VideoFrame::HOLE, size, gfx::Rect(size), size));
155  scoped_refptr<VideoFrame> frame(new VideoFrame(
156      VideoFrame::HOLE, size, gfx::Rect(size), size, base::TimeDelta()));
157  return frame;
158}
159#endif
160
161// static
162size_t VideoFrame::NumPlanes(Format format) {
163  switch (format) {
164    case VideoFrame::NATIVE_TEXTURE:
165#if defined(GOOGLE_TV)
166    case VideoFrame::HOLE:
167#endif
168      return 0;
169    case VideoFrame::RGB32:
170      return 1;
171    case VideoFrame::YV12:
172    case VideoFrame::YV16:
173      return 3;
174    case VideoFrame::YV12A:
175      return 4;
176    case VideoFrame::EMPTY:
177    case VideoFrame::I420:
178    case VideoFrame::INVALID:
179      break;
180  }
181  NOTREACHED() << "Unsupported video frame format: " << format;
182  return 0;
183}
184
185static inline size_t RoundUp(size_t value, size_t alignment) {
186  // Check that |alignment| is a power of 2.
187  DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1)));
188  return ((value + (alignment - 1)) & ~(alignment-1));
189}
190
191// Release data allocated by AllocateRGB() or AllocateYUV().
192static void ReleaseData(uint8* data) {
193  DCHECK(data);
194  base::AlignedFree(data);
195}
196
197void VideoFrame::AllocateRGB(size_t bytes_per_pixel) {
198  // Round up to align at least at a 16-byte boundary for each row.
199  // This is sufficient for MMX and SSE2 reads (movq/movdqa).
200  size_t bytes_per_row = RoundUp(coded_size_.width(),
201                                 kFrameSizeAlignment) * bytes_per_pixel;
202  size_t aligned_height = RoundUp(coded_size_.height(), kFrameSizeAlignment);
203  strides_[VideoFrame::kRGBPlane] = bytes_per_row;
204  data_[VideoFrame::kRGBPlane] = reinterpret_cast<uint8*>(
205      base::AlignedAlloc(bytes_per_row * aligned_height + kFrameSizePadding,
206                         kFrameAddressAlignment));
207  no_longer_needed_cb_ = base::Bind(&ReleaseData, data_[VideoFrame::kRGBPlane]);
208  DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7));
209  COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0);
210}
211
212void VideoFrame::AllocateYUV() {
213  DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 ||
214         format_ == VideoFrame::YV12A);
215  // Align Y rows at least at 16 byte boundaries.  The stride for both
216  // YV12 and YV16 is 1/2 of the stride of Y.  For YV12, every row of bytes for
217  // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in
218  // the case of YV12 the strides are identical for the same width surface, but
219  // the number of bytes allocated for YV12 is 1/2 the amount for U & V as
220  // YV16. We also round the height of the surface allocated to be an even
221  // number to avoid any potential of faulting by code that attempts to access
222  // the Y values of the final row, but assumes that the last row of U & V
223  // applies to a full two rows of Y. YV12A is the same as YV12, but with an
224  // additional alpha plane that has the same size and alignment as the Y plane.
225
226  size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane),
227                            kFrameSizeAlignment);
228  size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane),
229                             kFrameSizeAlignment);
230  // The *2 here is because some formats (e.g. h264) allow interlaced coding,
231  // and then the size needs to be a multiple of two macroblocks (vertically).
232  // See libavcodec/utils.c:avcodec_align_dimensions2().
233  size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2);
234  size_t uv_height = (format_ == VideoFrame::YV12 ||
235                      format_ == VideoFrame::YV12A) ?
236                              y_height / 2 : y_height;
237  size_t y_bytes = y_height * y_stride;
238  size_t uv_bytes = uv_height * uv_stride;
239  size_t a_bytes = format_ == VideoFrame::YV12A ? y_bytes : 0;
240
241  // The extra line of UV being allocated is because h264 chroma MC
242  // overreads by one line in some cases, see libavcodec/utils.c:
243  // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
244  // put_h264_chroma_mc4_ssse3().
245  uint8* data = reinterpret_cast<uint8*>(
246      base::AlignedAlloc(
247          y_bytes + (uv_bytes * 2 + uv_stride) + a_bytes + kFrameSizePadding,
248          kFrameAddressAlignment));
249  no_longer_needed_cb_ = base::Bind(&ReleaseData, data);
250  COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0);
251  data_[VideoFrame::kYPlane] = data;
252  data_[VideoFrame::kUPlane] = data + y_bytes;
253  data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes;
254  strides_[VideoFrame::kYPlane] = y_stride;
255  strides_[VideoFrame::kUPlane] = uv_stride;
256  strides_[VideoFrame::kVPlane] = uv_stride;
257  if (format_ == YV12A) {
258    data_[VideoFrame::kAPlane] = data + y_bytes + (2 * uv_bytes);
259    strides_[VideoFrame::kAPlane] = y_stride;
260  }
261}
262
263VideoFrame::VideoFrame(VideoFrame::Format format,
264                       const gfx::Size& coded_size,
265                       const gfx::Rect& visible_rect,
266                       const gfx::Size& natural_size,
267                       base::TimeDelta timestamp)
268    : format_(format),
269      coded_size_(coded_size),
270      visible_rect_(visible_rect),
271      natural_size_(natural_size),
272      texture_target_(0),
273      shared_memory_handle_(base::SharedMemory::NULLHandle()),
274      timestamp_(timestamp) {
275  memset(&strides_, 0, sizeof(strides_));
276  memset(&data_, 0, sizeof(data_));
277}
278
279VideoFrame::~VideoFrame() {
280  if (!no_longer_needed_cb_.is_null())
281    base::ResetAndReturn(&no_longer_needed_cb_).Run();
282}
283
284bool VideoFrame::IsValidPlane(size_t plane) const {
285  return (plane < NumPlanes(format_));
286}
287
288int VideoFrame::stride(size_t plane) const {
289  DCHECK(IsValidPlane(plane));
290  return strides_[plane];
291}
292
293int VideoFrame::row_bytes(size_t plane) const {
294  DCHECK(IsValidPlane(plane));
295  int width = coded_size_.width();
296  switch (format_) {
297    // 32bpp.
298    case RGB32:
299      return width * 4;
300
301    // Planar, 8bpp.
302    case YV12:
303    case YV16:
304    case YV12A:
305      if (plane == kYPlane || plane == kAPlane)
306        return width;
307      return RoundUp(width, 2) / 2;
308
309    default:
310      break;
311  }
312
313  // Intentionally leave out non-production formats.
314  NOTREACHED() << "Unsupported video frame format: " << format_;
315  return 0;
316}
317
318int VideoFrame::rows(size_t plane) const {
319  DCHECK(IsValidPlane(plane));
320  int height = coded_size_.height();
321  switch (format_) {
322    case RGB32:
323    case YV16:
324      return height;
325
326    case YV12:
327    case YV12A:
328      if (plane == kYPlane || plane == kAPlane)
329        return height;
330      return RoundUp(height, 2) / 2;
331
332    default:
333      break;
334  }
335
336  // Intentionally leave out non-production formats.
337  NOTREACHED() << "Unsupported video frame format: " << format_;
338  return 0;
339}
340
341uint8* VideoFrame::data(size_t plane) const {
342  DCHECK(IsValidPlane(plane));
343  return data_[plane];
344}
345
346const scoped_refptr<VideoFrame::MailboxHolder>& VideoFrame::texture_mailbox()
347    const {
348  DCHECK_EQ(format_, NATIVE_TEXTURE);
349  return texture_mailbox_holder_;
350}
351
352uint32 VideoFrame::texture_target() const {
353  DCHECK_EQ(format_, NATIVE_TEXTURE);
354  return texture_target_;
355}
356
357base::SharedMemoryHandle VideoFrame::shared_memory_handle() const {
358  return shared_memory_handle_;
359}
360
361bool VideoFrame::IsEndOfStream() const {
362  return format_ == VideoFrame::EMPTY;
363}
364
365void VideoFrame::HashFrameForTesting(base::MD5Context* context) {
366  for (int plane = 0; plane < kMaxPlanes; ++plane) {
367    if (!IsValidPlane(plane))
368      break;
369    for (int row = 0; row < rows(plane); ++row) {
370      base::MD5Update(context, base::StringPiece(
371          reinterpret_cast<char*>(data(plane) + stride(plane) * row),
372          row_bytes(plane)));
373    }
374  }
375}
376
377VideoFrame::MailboxHolder::MailboxHolder(
378    const gpu::Mailbox& mailbox,
379    unsigned sync_point,
380    const TextureNoLongerNeededCallback& release_callback)
381    : mailbox_(mailbox),
382      sync_point_(sync_point),
383      release_callback_(release_callback) {}
384
385VideoFrame::MailboxHolder::~MailboxHolder() {
386  if (!release_callback_.is_null())
387    release_callback_.Run(sync_point_);
388}
389
390}  // namespace media
391