video_frame.cc revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "media/base/video_frame.h"
6
7#include <algorithm>
8
9#include "base/bind.h"
10#include "base/callback_helpers.h"
11#include "base/logging.h"
12#include "base/memory/aligned_memory.h"
13#include "base/strings/string_piece.h"
14#include "gpu/command_buffer/common/mailbox_holder.h"
15#include "media/base/limits.h"
16#include "media/base/video_util.h"
17#include "third_party/skia/include/core/SkBitmap.h"
18
19namespace media {
20
21static inline size_t RoundUp(size_t value, size_t alignment) {
22  // Check that |alignment| is a power of 2.
23  DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1)));
24  return ((value + (alignment - 1)) & ~(alignment - 1));
25}
26
27// static
28scoped_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::YV12:
40    case VideoFrame::YV12A:
41    case VideoFrame::I420:
42    case VideoFrame::YV12J:
43      new_coded_size.set_height((new_coded_size.height() + 1) / 2 * 2);
44    // Fallthrough.
45    case VideoFrame::YV16:
46      new_coded_size.set_width((new_coded_size.width() + 1) / 2 * 2);
47      break;
48    default:
49      LOG(FATAL) << "Only YUV formats supported: " << format;
50      return NULL;
51  }
52  DCHECK(IsValidConfig(format, new_coded_size, visible_rect, natural_size));
53  scoped_refptr<VideoFrame> frame(
54      new VideoFrame(format,
55                     new_coded_size,
56                     visible_rect,
57                     natural_size,
58                     scoped_ptr<gpu::MailboxHolder>(),
59                     timestamp,
60                     false));
61  frame->AllocateYUV();
62  return frame;
63}
64
65// static
66std::string VideoFrame::FormatToString(VideoFrame::Format format) {
67  switch (format) {
68    case VideoFrame::UNKNOWN:
69      return "UNKNOWN";
70    case VideoFrame::YV12:
71      return "YV12";
72    case VideoFrame::YV16:
73      return "YV16";
74    case VideoFrame::I420:
75      return "I420";
76    case VideoFrame::NATIVE_TEXTURE:
77      return "NATIVE_TEXTURE";
78#if defined(VIDEO_HOLE)
79    case VideoFrame::HOLE:
80      return "HOLE";
81#endif  // defined(VIDEO_HOLE)
82    case VideoFrame::YV12A:
83      return "YV12A";
84    case VideoFrame::YV12J:
85      return "YV12J";
86  }
87  NOTREACHED() << "Invalid videoframe format provided: " << format;
88  return "";
89}
90
91// static
92bool VideoFrame::IsValidConfig(VideoFrame::Format format,
93                               const gfx::Size& coded_size,
94                               const gfx::Rect& visible_rect,
95                               const gfx::Size& natural_size) {
96  // Check maximum limits for all formats.
97  if (coded_size.GetArea() > limits::kMaxCanvas ||
98      coded_size.width() > limits::kMaxDimension ||
99      coded_size.height() > limits::kMaxDimension ||
100      visible_rect.x() < 0 || visible_rect.y() < 0 ||
101      visible_rect.right() > coded_size.width() ||
102      visible_rect.bottom() > coded_size.height() ||
103      natural_size.GetArea() > limits::kMaxCanvas ||
104      natural_size.width() > limits::kMaxDimension ||
105      natural_size.height() > limits::kMaxDimension)
106    return false;
107
108  // Check format-specific width/height requirements.
109  switch (format) {
110    case VideoFrame::UNKNOWN:
111      return (coded_size.IsEmpty() && visible_rect.IsEmpty() &&
112              natural_size.IsEmpty());
113    case VideoFrame::YV12:
114    case VideoFrame::YV12J:
115    case VideoFrame::I420:
116    case VideoFrame::YV12A:
117      // YUV formats have width/height requirements due to chroma subsampling.
118      if (static_cast<size_t>(coded_size.height()) <
119          RoundUp(visible_rect.bottom(), 2))
120        return false;
121    // Fallthrough.
122    case VideoFrame::YV16:
123      if (static_cast<size_t>(coded_size.width()) <
124          RoundUp(visible_rect.right(), 2))
125        return false;
126      break;
127    case VideoFrame::NATIVE_TEXTURE:
128#if defined(VIDEO_HOLE)
129    case VideoFrame::HOLE:
130#endif  // defined(VIDEO_HOLE)
131      // NATIVE_TEXTURE and HOLE have no software-allocated buffers and are
132      // allowed to skip the below check and be empty.
133      return true;
134  }
135
136  // Check that software-allocated buffer formats are not empty.
137  return (!coded_size.IsEmpty() && !visible_rect.IsEmpty() &&
138          !natural_size.IsEmpty());
139}
140
141// static
142scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
143    scoped_ptr<gpu::MailboxHolder> mailbox_holder,
144    const ReleaseMailboxCB& mailbox_holder_release_cb,
145    const gfx::Size& coded_size,
146    const gfx::Rect& visible_rect,
147    const gfx::Size& natural_size,
148    base::TimeDelta timestamp,
149    const ReadPixelsCB& read_pixels_cb) {
150  scoped_refptr<VideoFrame> frame(new VideoFrame(NATIVE_TEXTURE,
151                                                 coded_size,
152                                                 visible_rect,
153                                                 natural_size,
154                                                 mailbox_holder.Pass(),
155                                                 timestamp,
156                                                 false));
157  frame->mailbox_holder_release_cb_ = mailbox_holder_release_cb;
158  frame->read_pixels_cb_ = read_pixels_cb;
159
160  return frame;
161}
162
163void VideoFrame::ReadPixelsFromNativeTexture(const SkBitmap& pixels) {
164  DCHECK_EQ(format_, NATIVE_TEXTURE);
165  if (!read_pixels_cb_.is_null())
166    read_pixels_cb_.Run(pixels);
167}
168
169// static
170scoped_refptr<VideoFrame> VideoFrame::WrapExternalPackedMemory(
171    Format format,
172    const gfx::Size& coded_size,
173    const gfx::Rect& visible_rect,
174    const gfx::Size& natural_size,
175    uint8* data,
176    size_t data_size,
177    base::SharedMemoryHandle handle,
178    base::TimeDelta timestamp,
179    const base::Closure& no_longer_needed_cb) {
180  if (!IsValidConfig(format, coded_size, visible_rect, natural_size))
181    return NULL;
182  if (data_size < AllocationSize(format, coded_size))
183    return NULL;
184
185  switch (format) {
186    case I420: {
187      scoped_refptr<VideoFrame> frame(
188          new VideoFrame(format,
189                         coded_size,
190                         visible_rect,
191                         natural_size,
192                         scoped_ptr<gpu::MailboxHolder>(),
193                         timestamp,
194                         false));
195      frame->shared_memory_handle_ = handle;
196      frame->strides_[kYPlane] = coded_size.width();
197      frame->strides_[kUPlane] = coded_size.width() / 2;
198      frame->strides_[kVPlane] = coded_size.width() / 2;
199      frame->data_[kYPlane] = data;
200      frame->data_[kUPlane] = data + coded_size.GetArea();
201      frame->data_[kVPlane] = data + (coded_size.GetArea() * 5 / 4);
202      frame->no_longer_needed_cb_ = no_longer_needed_cb;
203      return frame;
204    }
205    default:
206      NOTIMPLEMENTED();
207      return NULL;
208  }
209}
210
211// static
212scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvData(
213    Format format,
214    const gfx::Size& coded_size,
215    const gfx::Rect& visible_rect,
216    const gfx::Size& natural_size,
217    int32 y_stride,
218    int32 u_stride,
219    int32 v_stride,
220    uint8* y_data,
221    uint8* u_data,
222    uint8* v_data,
223    base::TimeDelta timestamp,
224    const base::Closure& no_longer_needed_cb) {
225  if (!IsValidConfig(format, coded_size, visible_rect, natural_size))
226    return NULL;
227
228  scoped_refptr<VideoFrame> frame(
229      new VideoFrame(format,
230                     coded_size,
231                     visible_rect,
232                     natural_size,
233                     scoped_ptr<gpu::MailboxHolder>(),
234                     timestamp,
235                     false));
236  frame->strides_[kYPlane] = y_stride;
237  frame->strides_[kUPlane] = u_stride;
238  frame->strides_[kVPlane] = v_stride;
239  frame->data_[kYPlane] = y_data;
240  frame->data_[kUPlane] = u_data;
241  frame->data_[kVPlane] = v_data;
242  frame->no_longer_needed_cb_ = no_longer_needed_cb;
243  return frame;
244}
245
246// static
247scoped_refptr<VideoFrame> VideoFrame::WrapVideoFrame(
248      const scoped_refptr<VideoFrame>& frame,
249      const gfx::Rect& visible_rect,
250      const gfx::Size& natural_size,
251      const base::Closure& no_longer_needed_cb) {
252  // NATIVE_TEXTURE frames need mailbox info propagated, and there's no support
253  // for that here yet, see http://crbug/362521.
254  CHECK(frame->format() != NATIVE_TEXTURE);
255
256  DCHECK(frame->visible_rect().Contains(visible_rect));
257  scoped_refptr<VideoFrame> wrapped_frame(
258      new VideoFrame(frame->format(),
259                     frame->coded_size(),
260                     visible_rect,
261                     natural_size,
262                     scoped_ptr<gpu::MailboxHolder>(),
263                     frame->timestamp(),
264                     frame->end_of_stream()));
265
266  for (size_t i = 0; i < NumPlanes(frame->format()); ++i) {
267    wrapped_frame->strides_[i] = frame->stride(i);
268    wrapped_frame->data_[i] = frame->data(i);
269  }
270
271  wrapped_frame->no_longer_needed_cb_ = no_longer_needed_cb;
272  return wrapped_frame;
273}
274
275// static
276scoped_refptr<VideoFrame> VideoFrame::CreateEOSFrame() {
277  return new VideoFrame(VideoFrame::UNKNOWN,
278                        gfx::Size(),
279                        gfx::Rect(),
280                        gfx::Size(),
281                        scoped_ptr<gpu::MailboxHolder>(),
282                        kNoTimestamp(),
283                        true);
284}
285
286// static
287scoped_refptr<VideoFrame> VideoFrame::CreateColorFrame(
288    const gfx::Size& size,
289    uint8 y, uint8 u, uint8 v,
290    base::TimeDelta timestamp) {
291  scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
292      VideoFrame::YV12, size, gfx::Rect(size), size, timestamp);
293  FillYUV(frame.get(), y, u, v);
294  return frame;
295}
296
297// static
298scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(const gfx::Size& size) {
299  const uint8 kBlackY = 0x00;
300  const uint8 kBlackUV = 0x80;
301  const base::TimeDelta kZero;
302  return CreateColorFrame(size, kBlackY, kBlackUV, kBlackUV, kZero);
303}
304
305#if defined(VIDEO_HOLE)
306// This block and other blocks wrapped around #if defined(VIDEO_HOLE) is not
307// maintained by the general compositor team. Please contact the following
308// people instead:
309//
310// wonsik@chromium.org
311// ycheo@chromium.org
312
313// static
314scoped_refptr<VideoFrame> VideoFrame::CreateHoleFrame(
315    const gfx::Size& size) {
316  DCHECK(IsValidConfig(VideoFrame::HOLE, size, gfx::Rect(size), size));
317  scoped_refptr<VideoFrame> frame(
318      new VideoFrame(VideoFrame::HOLE,
319                     size,
320                     gfx::Rect(size),
321                     size,
322                     scoped_ptr<gpu::MailboxHolder>(),
323                     base::TimeDelta(),
324                     false));
325  return frame;
326}
327#endif  // defined(VIDEO_HOLE)
328
329// static
330size_t VideoFrame::NumPlanes(Format format) {
331  switch (format) {
332    case VideoFrame::NATIVE_TEXTURE:
333#if defined(VIDEO_HOLE)
334    case VideoFrame::HOLE:
335#endif  // defined(VIDEO_HOLE)
336      return 0;
337    case VideoFrame::YV12:
338    case VideoFrame::YV16:
339    case VideoFrame::I420:
340    case VideoFrame::YV12J:
341      return 3;
342    case VideoFrame::YV12A:
343      return 4;
344    case VideoFrame::UNKNOWN:
345      break;
346  }
347  NOTREACHED() << "Unsupported video frame format: " << format;
348  return 0;
349}
350
351
352// static
353size_t VideoFrame::AllocationSize(Format format, const gfx::Size& coded_size) {
354  size_t total = 0;
355  for (size_t i = 0; i < NumPlanes(format); ++i)
356    total += PlaneAllocationSize(format, i, coded_size);
357  return total;
358}
359
360// static
361gfx::Size VideoFrame::PlaneSize(Format format,
362                                size_t plane,
363                                const gfx::Size& coded_size) {
364  const int width = RoundUp(coded_size.width(), 2);
365  const int height = RoundUp(coded_size.height(), 2);
366  switch (format) {
367    case VideoFrame::YV12:
368    case VideoFrame::YV12J:
369    case VideoFrame::I420: {
370      switch (plane) {
371        case VideoFrame::kYPlane:
372          return gfx::Size(width, height);
373        case VideoFrame::kUPlane:
374        case VideoFrame::kVPlane:
375          return gfx::Size(width / 2, height / 2);
376        default:
377          break;
378      }
379    }
380    case VideoFrame::YV12A: {
381      switch (plane) {
382        case VideoFrame::kYPlane:
383        case VideoFrame::kAPlane:
384          return gfx::Size(width, height);
385        case VideoFrame::kUPlane:
386        case VideoFrame::kVPlane:
387          return gfx::Size(width / 2, height / 2);
388        default:
389          break;
390      }
391    }
392    case VideoFrame::YV16: {
393      switch (plane) {
394        case VideoFrame::kYPlane:
395          return gfx::Size(width, height);
396        case VideoFrame::kUPlane:
397        case VideoFrame::kVPlane:
398          return gfx::Size(width / 2, height);
399        default:
400          break;
401      }
402    }
403    case VideoFrame::UNKNOWN:
404    case VideoFrame::NATIVE_TEXTURE:
405#if defined(VIDEO_HOLE)
406    case VideoFrame::HOLE:
407#endif  // defined(VIDEO_HOLE)
408      break;
409  }
410  NOTREACHED() << "Unsupported video frame format/plane: "
411               << format << "/" << plane;
412  return gfx::Size();
413}
414
415size_t VideoFrame::PlaneAllocationSize(Format format,
416                                       size_t plane,
417                                       const gfx::Size& coded_size) {
418  // VideoFrame formats are (so far) all YUV and 1 byte per sample.
419  return PlaneSize(format, plane, coded_size).GetArea();
420}
421
422// Release data allocated by AllocateYUV().
423static void ReleaseData(uint8* data) {
424  DCHECK(data);
425  base::AlignedFree(data);
426}
427
428void VideoFrame::AllocateYUV() {
429  DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 ||
430         format_ == VideoFrame::YV12A || format_ == VideoFrame::I420 ||
431         format_ == VideoFrame::YV12J);
432  // Align Y rows at least at 16 byte boundaries.  The stride for both
433  // YV12 and YV16 is 1/2 of the stride of Y.  For YV12, every row of bytes for
434  // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in
435  // the case of YV12 the strides are identical for the same width surface, but
436  // the number of bytes allocated for YV12 is 1/2 the amount for U & V as
437  // YV16. We also round the height of the surface allocated to be an even
438  // number to avoid any potential of faulting by code that attempts to access
439  // the Y values of the final row, but assumes that the last row of U & V
440  // applies to a full two rows of Y. YV12A is the same as YV12, but with an
441  // additional alpha plane that has the same size and alignment as the Y plane.
442
443  size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane),
444                            kFrameSizeAlignment);
445  size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane),
446                             kFrameSizeAlignment);
447  // The *2 here is because some formats (e.g. h264) allow interlaced coding,
448  // and then the size needs to be a multiple of two macroblocks (vertically).
449  // See libavcodec/utils.c:avcodec_align_dimensions2().
450  size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2);
451  size_t uv_height =
452      (format_ == VideoFrame::YV12 || format_ == VideoFrame::YV12A ||
453       format_ == VideoFrame::I420)
454          ? y_height / 2
455          : y_height;
456  size_t y_bytes = y_height * y_stride;
457  size_t uv_bytes = uv_height * uv_stride;
458  size_t a_bytes = format_ == VideoFrame::YV12A ? y_bytes : 0;
459
460  // The extra line of UV being allocated is because h264 chroma MC
461  // overreads by one line in some cases, see libavcodec/utils.c:
462  // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
463  // put_h264_chroma_mc4_ssse3().
464  uint8* data = reinterpret_cast<uint8*>(
465      base::AlignedAlloc(
466          y_bytes + (uv_bytes * 2 + uv_stride) + a_bytes + kFrameSizePadding,
467          kFrameAddressAlignment));
468  no_longer_needed_cb_ = base::Bind(&ReleaseData, data);
469  COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0);
470  data_[VideoFrame::kYPlane] = data;
471  data_[VideoFrame::kUPlane] = data + y_bytes;
472  data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes;
473  strides_[VideoFrame::kYPlane] = y_stride;
474  strides_[VideoFrame::kUPlane] = uv_stride;
475  strides_[VideoFrame::kVPlane] = uv_stride;
476  if (format_ == YV12A) {
477    data_[VideoFrame::kAPlane] = data + y_bytes + (2 * uv_bytes);
478    strides_[VideoFrame::kAPlane] = y_stride;
479  }
480}
481
482VideoFrame::VideoFrame(VideoFrame::Format format,
483                       const gfx::Size& coded_size,
484                       const gfx::Rect& visible_rect,
485                       const gfx::Size& natural_size,
486                       scoped_ptr<gpu::MailboxHolder> mailbox_holder,
487                       base::TimeDelta timestamp,
488                       bool end_of_stream)
489    : format_(format),
490      coded_size_(coded_size),
491      visible_rect_(visible_rect),
492      natural_size_(natural_size),
493      mailbox_holder_(mailbox_holder.Pass()),
494      shared_memory_handle_(base::SharedMemory::NULLHandle()),
495      timestamp_(timestamp),
496      end_of_stream_(end_of_stream) {
497  DCHECK(IsValidConfig(format_, coded_size_, visible_rect_, natural_size_));
498
499  memset(&strides_, 0, sizeof(strides_));
500  memset(&data_, 0, sizeof(data_));
501}
502
503VideoFrame::~VideoFrame() {
504  if (!mailbox_holder_release_cb_.is_null()) {
505    std::vector<uint32> release_sync_points;
506    {
507      base::AutoLock locker(release_sync_point_lock_);
508      release_sync_points_.swap(release_sync_points);
509    }
510    base::ResetAndReturn(&mailbox_holder_release_cb_).Run(release_sync_points);
511  }
512  if (!no_longer_needed_cb_.is_null())
513    base::ResetAndReturn(&no_longer_needed_cb_).Run();
514}
515
516bool VideoFrame::IsValidPlane(size_t plane) const {
517  return (plane < NumPlanes(format_));
518}
519
520int VideoFrame::stride(size_t plane) const {
521  DCHECK(IsValidPlane(plane));
522  return strides_[plane];
523}
524
525int VideoFrame::row_bytes(size_t plane) const {
526  DCHECK(IsValidPlane(plane));
527  int width = coded_size_.width();
528  switch (format_) {
529    // Planar, 8bpp.
530    case YV12A:
531      if (plane == kAPlane)
532        return width;
533    // Fallthrough.
534    case YV12:
535    case YV16:
536    case I420:
537    case YV12J:
538      if (plane == kYPlane)
539        return width;
540      return RoundUp(width, 2) / 2;
541
542    default:
543      break;
544  }
545
546  // Intentionally leave out non-production formats.
547  NOTREACHED() << "Unsupported video frame format: " << format_;
548  return 0;
549}
550
551int VideoFrame::rows(size_t plane) const {
552  DCHECK(IsValidPlane(plane));
553  int height = coded_size_.height();
554  switch (format_) {
555    case YV16:
556      return height;
557
558    case YV12A:
559      if (plane == kAPlane)
560        return height;
561    // Fallthrough.
562    case YV12:
563    case I420:
564      if (plane == kYPlane)
565        return height;
566      return RoundUp(height, 2) / 2;
567
568    default:
569      break;
570  }
571
572  // Intentionally leave out non-production formats.
573  NOTREACHED() << "Unsupported video frame format: " << format_;
574  return 0;
575}
576
577uint8* VideoFrame::data(size_t plane) const {
578  DCHECK(IsValidPlane(plane));
579  return data_[plane];
580}
581
582const gpu::MailboxHolder* VideoFrame::mailbox_holder() const {
583  DCHECK_EQ(format_, NATIVE_TEXTURE);
584  return mailbox_holder_.get();
585}
586
587base::SharedMemoryHandle VideoFrame::shared_memory_handle() const {
588  return shared_memory_handle_;
589}
590
591void VideoFrame::AppendReleaseSyncPoint(uint32 sync_point) {
592  DCHECK_EQ(format_, NATIVE_TEXTURE);
593  if (!sync_point)
594    return;
595  base::AutoLock locker(release_sync_point_lock_);
596  release_sync_points_.push_back(sync_point);
597}
598
599void VideoFrame::HashFrameForTesting(base::MD5Context* context) {
600  for (int plane = 0; plane < kMaxPlanes; ++plane) {
601    if (!IsValidPlane(plane))
602      break;
603    for (int row = 0; row < rows(plane); ++row) {
604      base::MD5Update(context, base::StringPiece(
605          reinterpret_cast<char*>(data(plane) + stride(plane) * row),
606          row_bytes(plane)));
607    }
608  }
609}
610
611}  // namespace media
612