Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / media / base / video_frame.cc
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
19 namespace media {
20
21 static 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|.
28 static 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
48 scoped_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
80 std::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
110 bool 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
163 scoped_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
184 void 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
191 scoped_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
236 scoped_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
282 scoped_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
317 scoped_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
346 scoped_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
357 scoped_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
368 scoped_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
376 scoped_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
397 scoped_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
413 size_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
439 size_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
447 gfx::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
524 size_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
532 int 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().
593 static void ReleaseData(uint8* data) {
594   DCHECK(data);
595   base::AlignedFree(data);
596 }
597
598 void 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
655 VideoFrame::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       release_sync_point_(0),
670       end_of_stream_(end_of_stream) {
671   DCHECK(IsValidConfig(format_, coded_size_, visible_rect_, natural_size_));
672
673   memset(&strides_, 0, sizeof(strides_));
674   memset(&data_, 0, sizeof(data_));
675 }
676
677 VideoFrame::~VideoFrame() {
678   if (!mailbox_holder_release_cb_.is_null()) {
679     uint32 release_sync_point;
680     {
681       // To ensure that changes to |release_sync_point_| are visible on this
682       // thread (imply a memory barrier).
683       base::AutoLock locker(release_sync_point_lock_);
684       release_sync_point = release_sync_point_;
685     }
686     base::ResetAndReturn(&mailbox_holder_release_cb_).Run(release_sync_point);
687   }
688   if (!no_longer_needed_cb_.is_null())
689     base::ResetAndReturn(&no_longer_needed_cb_).Run();
690 }
691
692 bool VideoFrame::IsValidPlane(size_t plane) const {
693   return (plane < NumPlanes(format_));
694 }
695
696 int VideoFrame::stride(size_t plane) const {
697   DCHECK(IsValidPlane(plane));
698   return strides_[plane];
699 }
700
701 int VideoFrame::row_bytes(size_t plane) const {
702   DCHECK(IsValidPlane(plane));
703   int width = coded_size_.width();
704   switch (format_) {
705     case VideoFrame::YV24:
706       switch (plane) {
707         case kYPlane:
708         case kUPlane:
709         case kVPlane:
710           return width;
711         default:
712           break;
713       }
714       break;
715     case VideoFrame::YV12:
716     case VideoFrame::YV16:
717     case VideoFrame::I420:
718     case VideoFrame::YV12J:
719       switch (plane) {
720         case kYPlane:
721           return width;
722         case kUPlane:
723         case kVPlane:
724           return RoundUp(width, 2) / 2;
725         default:
726           break;
727       }
728       break;
729     case VideoFrame::YV12A:
730       switch (plane) {
731         case kYPlane:
732         case kAPlane:
733           return width;
734         case kUPlane:
735         case kVPlane:
736           return RoundUp(width, 2) / 2;
737         default:
738           break;
739       }
740       break;
741     case VideoFrame::NV12:
742       switch (plane) {
743         case kYPlane:
744         case kUVPlane:
745           return width;
746         default:
747           break;
748       }
749       break;
750     case VideoFrame::UNKNOWN:
751 #if defined(VIDEO_HOLE)
752     case VideoFrame::HOLE:
753 #endif  // defined(VIDEO_HOLE)
754     case VideoFrame::NATIVE_TEXTURE:
755       break;
756   }
757   NOTREACHED() << "Unsupported video frame format/plane: "
758                << format_ << "/" << plane;
759   return 0;
760 }
761
762 int VideoFrame::rows(size_t plane) const {
763   DCHECK(IsValidPlane(plane));
764   int height = coded_size_.height();
765   switch (format_) {
766     case VideoFrame::YV24:
767     case VideoFrame::YV16:
768       switch (plane) {
769         case kYPlane:
770         case kUPlane:
771         case kVPlane:
772           return height;
773         default:
774           break;
775       }
776       break;
777     case VideoFrame::YV12:
778     case VideoFrame::YV12J:
779     case VideoFrame::I420:
780       switch (plane) {
781         case kYPlane:
782           return height;
783         case kUPlane:
784         case kVPlane:
785           return RoundUp(height, 2) / 2;
786         default:
787           break;
788       }
789       break;
790     case VideoFrame::YV12A:
791       switch (plane) {
792         case kYPlane:
793         case kAPlane:
794           return height;
795         case kUPlane:
796         case kVPlane:
797           return RoundUp(height, 2) / 2;
798         default:
799           break;
800       }
801       break;
802     case VideoFrame::NV12:
803       switch (plane) {
804         case kYPlane:
805           return height;
806         case kUVPlane:
807           return RoundUp(height, 2) / 2;
808         default:
809           break;
810       }
811       break;
812     case VideoFrame::UNKNOWN:
813 #if defined(VIDEO_HOLE)
814     case VideoFrame::HOLE:
815 #endif  // defined(VIDEO_HOLE)
816     case VideoFrame::NATIVE_TEXTURE:
817       break;
818   }
819   NOTREACHED() << "Unsupported video frame format/plane: "
820                << format_ << "/" << plane;
821   return 0;
822 }
823
824 uint8* VideoFrame::data(size_t plane) const {
825   DCHECK(IsValidPlane(plane));
826   return data_[plane];
827 }
828
829 const gpu::MailboxHolder* VideoFrame::mailbox_holder() const {
830   DCHECK_EQ(format_, NATIVE_TEXTURE);
831   return mailbox_holder_.get();
832 }
833
834 base::SharedMemoryHandle VideoFrame::shared_memory_handle() const {
835   return shared_memory_handle_;
836 }
837
838 void VideoFrame::UpdateReleaseSyncPoint(SyncPointClient* client) {
839   DCHECK_EQ(format_, NATIVE_TEXTURE);
840   base::AutoLock locker(release_sync_point_lock_);
841   // Must wait on the previous sync point before inserting a new sync point so
842   // that |mailbox_holder_release_cb_| guarantees the previous sync point
843   // occurred when it waits on |release_sync_point_|.
844   if (release_sync_point_)
845     client->WaitSyncPoint(release_sync_point_);
846   release_sync_point_ = client->InsertSyncPoint();
847 }
848
849 #if defined(OS_POSIX)
850 int VideoFrame::dmabuf_fd(size_t plane) const {
851   return dmabuf_fds_[plane].get();
852 }
853 #endif
854
855 void VideoFrame::HashFrameForTesting(base::MD5Context* context) {
856   for (int plane = 0; plane < kMaxPlanes; ++plane) {
857     if (!IsValidPlane(plane))
858       break;
859     for (int row = 0; row < rows(plane); ++row) {
860       base::MD5Update(context, base::StringPiece(
861           reinterpret_cast<char*>(data(plane) + stride(plane) * row),
862           row_bytes(plane)));
863     }
864   }
865 }
866
867 }  // namespace media