video_frame.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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#include "third_party/skia/include/core/SkBitmap.h"
18
19namespace media {
20
21static inline size_t RoundUp(size_t value, size_t alignment) {
22  // Check that |alignment| is a power of 2.
23  DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1)));
24  return ((value + (alignment - 1)) & ~(alignment - 1));
25}
26
27// Rounds up |coded_size| if necessary for |format|.
28static gfx::Size AdjustCodedSize(VideoFrame::Format format,
29                                 const gfx::Size& coded_size) {
30  gfx::Size new_coded_size(coded_size);
31  switch (format) {
32    case VideoFrame::YV12:
33    case VideoFrame::YV12A:
34    case VideoFrame::I420:
35    case VideoFrame::YV12J:
36      new_coded_size.set_height(RoundUp(new_coded_size.height(), 2));
37    // Fallthrough.
38    case VideoFrame::YV16:
39      new_coded_size.set_width(RoundUp(new_coded_size.width(), 2));
40      break;
41    default:
42      break;
43  }
44  return new_coded_size;
45}
46
47// static
48scoped_refptr<VideoFrame> VideoFrame::CreateFrame(
49    VideoFrame::Format format,
50    const gfx::Size& coded_size,
51    const gfx::Rect& visible_rect,
52    const gfx::Size& natural_size,
53    base::TimeDelta timestamp) {
54  DCHECK(format != VideoFrame::UNKNOWN &&
55         format != VideoFrame::NV12 &&
56         format != VideoFrame::NATIVE_TEXTURE);
57#if defined(VIDEO_HOLE)
58  DCHECK(format != VideoFrame::HOLE);
59#endif  // defined(VIDEO_HOLE)
60
61  // Since we're creating a new YUV frame (and allocating memory for it
62  // ourselves), we can pad the requested |coded_size| if necessary if the
63  // request does not line up on sample boundaries.
64  gfx::Size new_coded_size = AdjustCodedSize(format, coded_size);
65  DCHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size));
66
67  scoped_refptr<VideoFrame> frame(
68      new VideoFrame(format,
69                     new_coded_size,
70                     visible_rect,
71                     natural_size,
72                     scoped_ptr<gpu::MailboxHolder>(),
73                     timestamp,
74                     false));
75  frame->AllocateYUV();
76  return frame;
77}
78
79// static
80std::string VideoFrame::FormatToString(VideoFrame::Format format) {
81  switch (format) {
82    case VideoFrame::UNKNOWN:
83      return "UNKNOWN";
84    case VideoFrame::YV12:
85      return "YV12";
86    case VideoFrame::YV16:
87      return "YV16";
88    case VideoFrame::I420:
89      return "I420";
90    case VideoFrame::NATIVE_TEXTURE:
91      return "NATIVE_TEXTURE";
92#if defined(VIDEO_HOLE)
93    case VideoFrame::HOLE:
94      return "HOLE";
95#endif  // defined(VIDEO_HOLE)
96    case VideoFrame::YV12A:
97      return "YV12A";
98    case VideoFrame::YV12J:
99      return "YV12J";
100    case VideoFrame::NV12:
101      return "NV12";
102    case VideoFrame::YV24:
103      return "YV24";
104  }
105  NOTREACHED() << "Invalid videoframe format provided: " << format;
106  return "";
107}
108
109// static
110bool VideoFrame::IsValidConfig(VideoFrame::Format format,
111                               const gfx::Size& coded_size,
112                               const gfx::Rect& visible_rect,
113                               const gfx::Size& natural_size) {
114  // Check maximum limits for all formats.
115  if (coded_size.GetArea() > limits::kMaxCanvas ||
116      coded_size.width() > limits::kMaxDimension ||
117      coded_size.height() > limits::kMaxDimension ||
118      visible_rect.x() < 0 || visible_rect.y() < 0 ||
119      visible_rect.right() > coded_size.width() ||
120      visible_rect.bottom() > coded_size.height() ||
121      natural_size.GetArea() > limits::kMaxCanvas ||
122      natural_size.width() > limits::kMaxDimension ||
123      natural_size.height() > limits::kMaxDimension)
124    return false;
125
126  // Check format-specific width/height requirements.
127  switch (format) {
128    case VideoFrame::UNKNOWN:
129      return (coded_size.IsEmpty() && visible_rect.IsEmpty() &&
130              natural_size.IsEmpty());
131    case VideoFrame::YV24:
132      break;
133    case VideoFrame::YV12:
134    case VideoFrame::YV12J:
135    case VideoFrame::I420:
136    case VideoFrame::YV12A:
137    case VideoFrame::NV12:
138      // Subsampled YUV formats have width/height requirements.
139      if (static_cast<size_t>(coded_size.height()) <
140          RoundUp(visible_rect.bottom(), 2))
141        return false;
142    // Fallthrough.
143    case VideoFrame::YV16:
144      if (static_cast<size_t>(coded_size.width()) <
145          RoundUp(visible_rect.right(), 2))
146        return false;
147      break;
148    case VideoFrame::NATIVE_TEXTURE:
149#if defined(VIDEO_HOLE)
150    case VideoFrame::HOLE:
151#endif  // defined(VIDEO_HOLE)
152      // NATIVE_TEXTURE and HOLE have no software-allocated buffers and are
153      // allowed to skip the below check and be empty.
154      return true;
155  }
156
157  // Check that software-allocated buffer formats are not empty.
158  return (!coded_size.IsEmpty() && !visible_rect.IsEmpty() &&
159          !natural_size.IsEmpty());
160}
161
162// static
163scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
164    scoped_ptr<gpu::MailboxHolder> mailbox_holder,
165    const ReleaseMailboxCB& mailbox_holder_release_cb,
166    const gfx::Size& coded_size,
167    const gfx::Rect& visible_rect,
168    const gfx::Size& natural_size,
169    base::TimeDelta timestamp,
170    const ReadPixelsCB& read_pixels_cb) {
171  scoped_refptr<VideoFrame> frame(new VideoFrame(NATIVE_TEXTURE,
172                                                 coded_size,
173                                                 visible_rect,
174                                                 natural_size,
175                                                 mailbox_holder.Pass(),
176                                                 timestamp,
177                                                 false));
178  frame->mailbox_holder_release_cb_ = mailbox_holder_release_cb;
179  frame->read_pixels_cb_ = read_pixels_cb;
180
181  return frame;
182}
183
184void VideoFrame::ReadPixelsFromNativeTexture(const SkBitmap& pixels) {
185  DCHECK_EQ(format_, NATIVE_TEXTURE);
186  if (!read_pixels_cb_.is_null())
187    read_pixels_cb_.Run(pixels);
188}
189
190// static
191scoped_refptr<VideoFrame> VideoFrame::WrapExternalPackedMemory(
192    Format format,
193    const gfx::Size& coded_size,
194    const gfx::Rect& visible_rect,
195    const gfx::Size& natural_size,
196    uint8* data,
197    size_t data_size,
198    base::SharedMemoryHandle handle,
199    base::TimeDelta timestamp,
200    const base::Closure& no_longer_needed_cb) {
201  gfx::Size new_coded_size = AdjustCodedSize(format, coded_size);
202
203  if (!IsValidConfig(format, new_coded_size, visible_rect, natural_size))
204    return NULL;
205  if (data_size < AllocationSize(format, new_coded_size))
206    return NULL;
207
208  switch (format) {
209    case VideoFrame::I420: {
210      scoped_refptr<VideoFrame> frame(
211          new VideoFrame(format,
212                         new_coded_size,
213                         visible_rect,
214                         natural_size,
215                         scoped_ptr<gpu::MailboxHolder>(),
216                         timestamp,
217                         false));
218      frame->shared_memory_handle_ = handle;
219      frame->strides_[kYPlane] = new_coded_size.width();
220      frame->strides_[kUPlane] = new_coded_size.width() / 2;
221      frame->strides_[kVPlane] = new_coded_size.width() / 2;
222      frame->data_[kYPlane] = data;
223      frame->data_[kUPlane] = data + new_coded_size.GetArea();
224      frame->data_[kVPlane] = data + (new_coded_size.GetArea() * 5 / 4);
225      frame->no_longer_needed_cb_ = no_longer_needed_cb;
226      return frame;
227    }
228    default:
229      NOTIMPLEMENTED();
230      return NULL;
231  }
232}
233
234#if defined(OS_POSIX)
235// static
236scoped_refptr<VideoFrame> VideoFrame::WrapExternalDmabufs(
237    Format format,
238    const gfx::Size& coded_size,
239    const gfx::Rect& visible_rect,
240    const gfx::Size& natural_size,
241    const std::vector<int> dmabuf_fds,
242    base::TimeDelta timestamp,
243    const base::Closure& no_longer_needed_cb) {
244  if (!IsValidConfig(format, coded_size, visible_rect, natural_size))
245    return NULL;
246
247  if (dmabuf_fds.size() != NumPlanes(format)) {
248    LOG(FATAL) << "Not enough dmabuf fds provided!";
249    return NULL;
250  }
251
252  scoped_refptr<VideoFrame> frame(
253      new VideoFrame(format,
254                     coded_size,
255                     visible_rect,
256                     natural_size,
257                     scoped_ptr<gpu::MailboxHolder>(),
258                     timestamp,
259                     false));
260
261  for (size_t i = 0; i < dmabuf_fds.size(); ++i) {
262    int duped_fd = HANDLE_EINTR(dup(dmabuf_fds[i]));
263    if (duped_fd == -1) {
264      // The already-duped in previous iterations fds will be closed when
265      // the partially-created frame drops out of scope here.
266      DLOG(ERROR) << "Failed duplicating a dmabuf fd";
267      return NULL;
268    }
269
270    frame->dmabuf_fds_[i].reset(duped_fd);
271    // Data is accessible only via fds.
272    frame->data_[i] = NULL;
273    frame->strides_[i] = 0;
274  }
275
276  frame->no_longer_needed_cb_ = no_longer_needed_cb;
277  return frame;
278}
279#endif
280
281// static
282scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvData(
283    Format format,
284    const gfx::Size& coded_size,
285    const gfx::Rect& visible_rect,
286    const gfx::Size& natural_size,
287    int32 y_stride,
288    int32 u_stride,
289    int32 v_stride,
290    uint8* y_data,
291    uint8* u_data,
292    uint8* v_data,
293    base::TimeDelta timestamp,
294    const base::Closure& no_longer_needed_cb) {
295  gfx::Size new_coded_size = AdjustCodedSize(format, coded_size);
296  CHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size));
297
298  scoped_refptr<VideoFrame> frame(
299      new VideoFrame(format,
300                     new_coded_size,
301                     visible_rect,
302                     natural_size,
303                     scoped_ptr<gpu::MailboxHolder>(),
304                     timestamp,
305                     false));
306  frame->strides_[kYPlane] = y_stride;
307  frame->strides_[kUPlane] = u_stride;
308  frame->strides_[kVPlane] = v_stride;
309  frame->data_[kYPlane] = y_data;
310  frame->data_[kUPlane] = u_data;
311  frame->data_[kVPlane] = v_data;
312  frame->no_longer_needed_cb_ = no_longer_needed_cb;
313  return frame;
314}
315
316// static
317scoped_refptr<VideoFrame> VideoFrame::WrapVideoFrame(
318      const scoped_refptr<VideoFrame>& frame,
319      const gfx::Rect& visible_rect,
320      const gfx::Size& natural_size,
321      const base::Closure& no_longer_needed_cb) {
322  // NATIVE_TEXTURE frames need mailbox info propagated, and there's no support
323  // for that here yet, see http://crbug/362521.
324  CHECK_NE(frame->format(), NATIVE_TEXTURE);
325
326  DCHECK(frame->visible_rect().Contains(visible_rect));
327  scoped_refptr<VideoFrame> wrapped_frame(
328      new VideoFrame(frame->format(),
329                     frame->coded_size(),
330                     visible_rect,
331                     natural_size,
332                     scoped_ptr<gpu::MailboxHolder>(),
333                     frame->timestamp(),
334                     frame->end_of_stream()));
335
336  for (size_t i = 0; i < NumPlanes(frame->format()); ++i) {
337    wrapped_frame->strides_[i] = frame->stride(i);
338    wrapped_frame->data_[i] = frame->data(i);
339  }
340
341  wrapped_frame->no_longer_needed_cb_ = no_longer_needed_cb;
342  return wrapped_frame;
343}
344
345// static
346scoped_refptr<VideoFrame> VideoFrame::CreateEOSFrame() {
347  return new VideoFrame(VideoFrame::UNKNOWN,
348                        gfx::Size(),
349                        gfx::Rect(),
350                        gfx::Size(),
351                        scoped_ptr<gpu::MailboxHolder>(),
352                        kNoTimestamp(),
353                        true);
354}
355
356// static
357scoped_refptr<VideoFrame> VideoFrame::CreateColorFrame(
358    const gfx::Size& size,
359    uint8 y, uint8 u, uint8 v,
360    base::TimeDelta timestamp) {
361  scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
362      VideoFrame::YV12, size, gfx::Rect(size), size, timestamp);
363  FillYUV(frame.get(), y, u, v);
364  return frame;
365}
366
367// static
368scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(const gfx::Size& size) {
369  const uint8 kBlackY = 0x00;
370  const uint8 kBlackUV = 0x80;
371  const base::TimeDelta kZero;
372  return CreateColorFrame(size, kBlackY, kBlackUV, kBlackUV, kZero);
373}
374
375// static
376scoped_refptr<VideoFrame> VideoFrame::CreateTransparentFrame(
377    const gfx::Size& size) {
378  const uint8 kBlackY = 0x00;
379  const uint8 kBlackUV = 0x00;
380  const uint8 kTransparentA = 0x00;
381  const base::TimeDelta kZero;
382  scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
383      VideoFrame::YV12A, size, gfx::Rect(size), size, kZero);
384  FillYUVA(frame, kBlackY, kBlackUV, kBlackUV, kTransparentA);
385  return frame;
386}
387
388#if defined(VIDEO_HOLE)
389// This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not
390// maintained by the general compositor team. Please contact the following
391// people instead:
392//
393// wonsik@chromium.org
394// ycheo@chromium.org
395
396// static
397scoped_refptr<VideoFrame> VideoFrame::CreateHoleFrame(
398    const gfx::Size& size) {
399  DCHECK(IsValidConfig(VideoFrame::HOLE, size, gfx::Rect(size), size));
400  scoped_refptr<VideoFrame> frame(
401      new VideoFrame(VideoFrame::HOLE,
402                     size,
403                     gfx::Rect(size),
404                     size,
405                     scoped_ptr<gpu::MailboxHolder>(),
406                     base::TimeDelta(),
407                     false));
408  return frame;
409}
410#endif  // defined(VIDEO_HOLE)
411
412// static
413size_t VideoFrame::NumPlanes(Format format) {
414  switch (format) {
415    case VideoFrame::NATIVE_TEXTURE:
416#if defined(VIDEO_HOLE)
417    case VideoFrame::HOLE:
418#endif  // defined(VIDEO_HOLE)
419      return 0;
420    case VideoFrame::NV12:
421      return 2;
422    case VideoFrame::YV12:
423    case VideoFrame::YV16:
424    case VideoFrame::I420:
425    case VideoFrame::YV12J:
426    case VideoFrame::YV24:
427      return 3;
428    case VideoFrame::YV12A:
429      return 4;
430    case VideoFrame::UNKNOWN:
431      break;
432  }
433  NOTREACHED() << "Unsupported video frame format: " << format;
434  return 0;
435}
436
437
438// static
439size_t VideoFrame::AllocationSize(Format format, const gfx::Size& coded_size) {
440  size_t total = 0;
441  for (size_t i = 0; i < NumPlanes(format); ++i)
442    total += PlaneAllocationSize(format, i, coded_size);
443  return total;
444}
445
446// static
447gfx::Size VideoFrame::PlaneSize(Format format,
448                                size_t plane,
449                                const gfx::Size& coded_size) {
450  // Align to multiple-of-two size overall. This ensures that non-subsampled
451  // planes can be addressed by pixel with the same scaling as the subsampled
452  // planes.
453  const int width = RoundUp(coded_size.width(), 2);
454  const int height = RoundUp(coded_size.height(), 2);
455  switch (format) {
456    case VideoFrame::YV24:
457      switch (plane) {
458        case VideoFrame::kYPlane:
459        case VideoFrame::kUPlane:
460        case VideoFrame::kVPlane:
461          return gfx::Size(width, height);
462        default:
463          break;
464      }
465      break;
466    case VideoFrame::YV12:
467    case VideoFrame::YV12J:
468    case VideoFrame::I420:
469      switch (plane) {
470        case VideoFrame::kYPlane:
471          return gfx::Size(width, height);
472        case VideoFrame::kUPlane:
473        case VideoFrame::kVPlane:
474          return gfx::Size(width / 2, height / 2);
475        default:
476          break;
477      }
478      break;
479    case VideoFrame::YV12A:
480      switch (plane) {
481        case VideoFrame::kYPlane:
482        case VideoFrame::kAPlane:
483          return gfx::Size(width, height);
484        case VideoFrame::kUPlane:
485        case VideoFrame::kVPlane:
486          return gfx::Size(width / 2, height / 2);
487        default:
488          break;
489      }
490      break;
491    case VideoFrame::YV16:
492      switch (plane) {
493        case VideoFrame::kYPlane:
494          return gfx::Size(width, height);
495        case VideoFrame::kUPlane:
496        case VideoFrame::kVPlane:
497          return gfx::Size(width / 2, height);
498        default:
499          break;
500      }
501      break;
502    case VideoFrame::NV12:
503      switch (plane) {
504        case VideoFrame::kYPlane:
505          return gfx::Size(width, height);
506        case VideoFrame::kUVPlane:
507          return gfx::Size(width, height / 2);
508        default:
509          break;
510      }
511      break;
512    case VideoFrame::UNKNOWN:
513    case VideoFrame::NATIVE_TEXTURE:
514#if defined(VIDEO_HOLE)
515    case VideoFrame::HOLE:
516#endif  // defined(VIDEO_HOLE)
517      break;
518  }
519  NOTREACHED() << "Unsupported video frame format/plane: "
520               << format << "/" << plane;
521  return gfx::Size();
522}
523
524size_t VideoFrame::PlaneAllocationSize(Format format,
525                                       size_t plane,
526                                       const gfx::Size& coded_size) {
527  // VideoFrame formats are (so far) all YUV and 1 byte per sample.
528  return PlaneSize(format, plane, coded_size).GetArea();
529}
530
531// static
532int VideoFrame::PlaneHorizontalBitsPerPixel(Format format, size_t plane) {
533  switch (format) {
534    case VideoFrame::YV24:
535      switch (plane) {
536        case kYPlane:
537        case kUPlane:
538        case kVPlane:
539          return 8;
540        default:
541          break;
542      }
543      break;
544    case VideoFrame::YV12:
545    case VideoFrame::YV16:
546    case VideoFrame::I420:
547    case VideoFrame::YV12J:
548      switch (plane) {
549        case kYPlane:
550          return 8;
551        case kUPlane:
552        case kVPlane:
553          return 2;
554        default:
555          break;
556      }
557      break;
558    case VideoFrame::YV12A:
559      switch (plane) {
560        case kYPlane:
561        case kAPlane:
562          return 8;
563        case kUPlane:
564        case kVPlane:
565          return 2;
566        default:
567          break;
568      }
569      break;
570    case VideoFrame::NV12:
571      switch (plane) {
572        case kYPlane:
573          return 8;
574        case kUVPlane:
575          return 4;
576        default:
577          break;
578      }
579      break;
580    case VideoFrame::UNKNOWN:
581#if defined(VIDEO_HOLE)
582    case VideoFrame::HOLE:
583#endif  // defined(VIDEO_HOLE)
584    case VideoFrame::NATIVE_TEXTURE:
585      break;
586  }
587  NOTREACHED() << "Unsupported video frame format/plane: "
588               << format << "/" << plane;
589  return 0;
590}
591
592// Release data allocated by AllocateYUV().
593static void ReleaseData(uint8* data) {
594  DCHECK(data);
595  base::AlignedFree(data);
596}
597
598void VideoFrame::AllocateYUV() {
599  DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 ||
600         format_ == VideoFrame::YV12A || format_ == VideoFrame::I420 ||
601         format_ == VideoFrame::YV12J || format_ == VideoFrame::YV24);
602  // Align Y rows at least at 16 byte boundaries.  The stride for both
603  // YV12 and YV16 is 1/2 of the stride of Y.  For YV12, every row of bytes for
604  // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in
605  // the case of YV12 the strides are identical for the same width surface, but
606  // the number of bytes allocated for YV12 is 1/2 the amount for U & V as
607  // YV16. We also round the height of the surface allocated to be an even
608  // number to avoid any potential of faulting by code that attempts to access
609  // the Y values of the final row, but assumes that the last row of U & V
610  // applies to a full two rows of Y. YV12A is the same as YV12, but with an
611  // additional alpha plane that has the same size and alignment as the Y plane.
612  size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane),
613                            kFrameSizeAlignment);
614  size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane),
615                             kFrameSizeAlignment);
616
617  // The *2 here is because some formats (e.g. h264) allow interlaced coding,
618  // and then the size needs to be a multiple of two macroblocks (vertically).
619  // See libavcodec/utils.c:avcodec_align_dimensions2().
620  size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2);
621  size_t uv_height =
622      (format_ == VideoFrame::YV12 || format_ == VideoFrame::YV12A ||
623       format_ == VideoFrame::I420)
624          ? y_height / 2
625          : y_height;
626  size_t y_bytes = y_height * y_stride;
627  size_t uv_bytes = uv_height * uv_stride;
628  size_t a_bytes = format_ == VideoFrame::YV12A ? y_bytes : 0;
629
630  // The extra line of UV being allocated is because h264 chroma MC
631  // overreads by one line in some cases, see libavcodec/utils.c:
632  // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
633  // put_h264_chroma_mc4_ssse3().
634  const size_t data_size =
635      y_bytes + (uv_bytes * 2 + uv_stride) + a_bytes + kFrameSizePadding;
636  uint8* data = reinterpret_cast<uint8*>(
637      base::AlignedAlloc(data_size, kFrameAddressAlignment));
638  // FFmpeg expects the initialize allocation to be zero-initialized.  Failure
639  // to do so can lead to unitialized value usage.  See http://crbug.com/390941
640  memset(data, 0, data_size);
641  no_longer_needed_cb_ = base::Bind(&ReleaseData, data);
642  COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0);
643  data_[VideoFrame::kYPlane] = data;
644  data_[VideoFrame::kUPlane] = data + y_bytes;
645  data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes;
646  strides_[VideoFrame::kYPlane] = y_stride;
647  strides_[VideoFrame::kUPlane] = uv_stride;
648  strides_[VideoFrame::kVPlane] = uv_stride;
649  if (format_ == YV12A) {
650    data_[VideoFrame::kAPlane] = data + y_bytes + (2 * uv_bytes);
651    strides_[VideoFrame::kAPlane] = y_stride;
652  }
653}
654
655VideoFrame::VideoFrame(VideoFrame::Format format,
656                       const gfx::Size& coded_size,
657                       const gfx::Rect& visible_rect,
658                       const gfx::Size& natural_size,
659                       scoped_ptr<gpu::MailboxHolder> mailbox_holder,
660                       base::TimeDelta timestamp,
661                       bool end_of_stream)
662    : format_(format),
663      coded_size_(coded_size),
664      visible_rect_(visible_rect),
665      natural_size_(natural_size),
666      mailbox_holder_(mailbox_holder.Pass()),
667      shared_memory_handle_(base::SharedMemory::NULLHandle()),
668      timestamp_(timestamp),
669      end_of_stream_(end_of_stream) {
670  DCHECK(IsValidConfig(format_, coded_size_, visible_rect_, natural_size_));
671
672  memset(&strides_, 0, sizeof(strides_));
673  memset(&data_, 0, sizeof(data_));
674}
675
676VideoFrame::~VideoFrame() {
677  if (!mailbox_holder_release_cb_.is_null()) {
678    std::vector<uint32> release_sync_points;
679    {
680      base::AutoLock locker(release_sync_point_lock_);
681      release_sync_points_.swap(release_sync_points);
682    }
683    base::ResetAndReturn(&mailbox_holder_release_cb_).Run(release_sync_points);
684  }
685  if (!no_longer_needed_cb_.is_null())
686    base::ResetAndReturn(&no_longer_needed_cb_).Run();
687}
688
689bool VideoFrame::IsValidPlane(size_t plane) const {
690  return (plane < NumPlanes(format_));
691}
692
693int VideoFrame::stride(size_t plane) const {
694  DCHECK(IsValidPlane(plane));
695  return strides_[plane];
696}
697
698int VideoFrame::row_bytes(size_t plane) const {
699  DCHECK(IsValidPlane(plane));
700  int width = coded_size_.width();
701  switch (format_) {
702    case VideoFrame::YV24:
703      switch (plane) {
704        case kYPlane:
705        case kUPlane:
706        case kVPlane:
707          return width;
708        default:
709          break;
710      }
711      break;
712    case VideoFrame::YV12:
713    case VideoFrame::YV16:
714    case VideoFrame::I420:
715    case VideoFrame::YV12J:
716      switch (plane) {
717        case kYPlane:
718          return width;
719        case kUPlane:
720        case kVPlane:
721          return RoundUp(width, 2) / 2;
722        default:
723          break;
724      }
725      break;
726    case VideoFrame::YV12A:
727      switch (plane) {
728        case kYPlane:
729        case kAPlane:
730          return width;
731        case kUPlane:
732        case kVPlane:
733          return RoundUp(width, 2) / 2;
734        default:
735          break;
736      }
737      break;
738    case VideoFrame::NV12:
739      switch (plane) {
740        case kYPlane:
741        case kUVPlane:
742          return width;
743        default:
744          break;
745      }
746      break;
747    case VideoFrame::UNKNOWN:
748#if defined(VIDEO_HOLE)
749    case VideoFrame::HOLE:
750#endif  // defined(VIDEO_HOLE)
751    case VideoFrame::NATIVE_TEXTURE:
752      break;
753  }
754  NOTREACHED() << "Unsupported video frame format/plane: "
755               << format_ << "/" << plane;
756  return 0;
757}
758
759int VideoFrame::rows(size_t plane) const {
760  DCHECK(IsValidPlane(plane));
761  int height = coded_size_.height();
762  switch (format_) {
763    case VideoFrame::YV24:
764    case VideoFrame::YV16:
765      switch (plane) {
766        case kYPlane:
767        case kUPlane:
768        case kVPlane:
769          return height;
770        default:
771          break;
772      }
773      break;
774    case VideoFrame::YV12:
775    case VideoFrame::YV12J:
776    case VideoFrame::I420:
777      switch (plane) {
778        case kYPlane:
779          return height;
780        case kUPlane:
781        case kVPlane:
782          return RoundUp(height, 2) / 2;
783        default:
784          break;
785      }
786      break;
787    case VideoFrame::YV12A:
788      switch (plane) {
789        case kYPlane:
790        case kAPlane:
791          return height;
792        case kUPlane:
793        case kVPlane:
794          return RoundUp(height, 2) / 2;
795        default:
796          break;
797      }
798      break;
799    case VideoFrame::NV12:
800      switch (plane) {
801        case kYPlane:
802          return height;
803        case kUVPlane:
804          return RoundUp(height, 2) / 2;
805        default:
806          break;
807      }
808      break;
809    case VideoFrame::UNKNOWN:
810#if defined(VIDEO_HOLE)
811    case VideoFrame::HOLE:
812#endif  // defined(VIDEO_HOLE)
813    case VideoFrame::NATIVE_TEXTURE:
814      break;
815  }
816  NOTREACHED() << "Unsupported video frame format/plane: "
817               << format_ << "/" << plane;
818  return 0;
819}
820
821uint8* VideoFrame::data(size_t plane) const {
822  DCHECK(IsValidPlane(plane));
823  return data_[plane];
824}
825
826const gpu::MailboxHolder* VideoFrame::mailbox_holder() const {
827  DCHECK_EQ(format_, NATIVE_TEXTURE);
828  return mailbox_holder_.get();
829}
830
831base::SharedMemoryHandle VideoFrame::shared_memory_handle() const {
832  return shared_memory_handle_;
833}
834
835void VideoFrame::AppendReleaseSyncPoint(uint32 sync_point) {
836  DCHECK_EQ(format_, NATIVE_TEXTURE);
837  if (!sync_point)
838    return;
839  base::AutoLock locker(release_sync_point_lock_);
840  release_sync_points_.push_back(sync_point);
841}
842
843#if defined(OS_POSIX)
844int VideoFrame::dmabuf_fd(size_t plane) const {
845  return dmabuf_fds_[plane].get();
846}
847#endif
848
849void VideoFrame::HashFrameForTesting(base::MD5Context* context) {
850  for (int plane = 0; plane < kMaxPlanes; ++plane) {
851    if (!IsValidPlane(plane))
852      break;
853    for (int row = 0; row < rows(plane); ++row) {
854      base::MD5Update(context, base::StringPiece(
855          reinterpret_cast<char*>(data(plane) + stride(plane) * row),
856          row_bytes(plane)));
857    }
858  }
859}
860
861}  // namespace media
862