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