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