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