- add sources.
[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 "media/base/limits.h"
15 #include "media/base/video_util.h"
16 #include "third_party/skia/include/core/SkBitmap.h"
17
18 namespace media {
19
20 // static
21 scoped_refptr<VideoFrame> VideoFrame::CreateFrame(
22     VideoFrame::Format format,
23     const gfx::Size& coded_size,
24     const gfx::Rect& visible_rect,
25     const gfx::Size& natural_size,
26     base::TimeDelta timestamp) {
27   DCHECK(IsValidConfig(format, coded_size, visible_rect, natural_size));
28   scoped_refptr<VideoFrame> frame(new VideoFrame(
29       format, coded_size, visible_rect, natural_size, timestamp));
30   switch (format) {
31     case VideoFrame::RGB32:
32       frame->AllocateRGB(4u);
33       break;
34     case VideoFrame::YV12:
35     case VideoFrame::YV12A:
36     case VideoFrame::YV16:
37     case VideoFrame::I420:
38       frame->AllocateYUV();
39       break;
40     default:
41       LOG(FATAL) << "Unsupported frame format: " << format;
42   }
43   return frame;
44 }
45
46 // static
47 std::string VideoFrame::FormatToString(VideoFrame::Format format) {
48   switch (format) {
49     case VideoFrame::UNKNOWN:
50       return "UNKNOWN";
51     case VideoFrame::RGB32:
52       return "RGB32";
53     case VideoFrame::YV12:
54       return "YV12";
55     case VideoFrame::YV16:
56       return "YV16";
57     case VideoFrame::EMPTY:
58       return "EMPTY";
59     case VideoFrame::I420:
60       return "I420";
61     case VideoFrame::NATIVE_TEXTURE:
62       return "NATIVE_TEXTURE";
63 #if defined(GOOGLE_TV)
64     case VideoFrame::HOLE:
65       return "HOLE";
66 #endif
67     case VideoFrame::YV12A:
68       return "YV12A";
69   }
70   NOTREACHED() << "Invalid videoframe format provided: " << format;
71   return "";
72 }
73
74 // static
75 bool VideoFrame::IsValidConfig(VideoFrame::Format format,
76                                const gfx::Size& coded_size,
77                                const gfx::Rect& visible_rect,
78                                const gfx::Size& natural_size) {
79   return (format != VideoFrame::UNKNOWN &&
80           !coded_size.IsEmpty() &&
81           coded_size.GetArea() <= limits::kMaxCanvas &&
82           coded_size.width() <= limits::kMaxDimension &&
83           coded_size.height() <= limits::kMaxDimension &&
84           !visible_rect.IsEmpty() &&
85           visible_rect.x() >= 0 && visible_rect.y() >= 0 &&
86           visible_rect.right() <= coded_size.width() &&
87           visible_rect.bottom() <= coded_size.height() &&
88           !natural_size.IsEmpty() &&
89           natural_size.GetArea() <= limits::kMaxCanvas &&
90           natural_size.width() <= limits::kMaxDimension &&
91           natural_size.height() <= limits::kMaxDimension);
92 }
93
94 // static
95 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTexture(
96     const scoped_refptr<MailboxHolder>& mailbox_holder,
97     uint32 texture_target,
98     const gfx::Size& coded_size,
99     const gfx::Rect& visible_rect,
100     const gfx::Size& natural_size,
101     base::TimeDelta timestamp,
102     const ReadPixelsCB& read_pixels_cb,
103     const base::Closure& no_longer_needed_cb) {
104   scoped_refptr<VideoFrame> frame(new VideoFrame(
105       NATIVE_TEXTURE, coded_size, visible_rect, natural_size, timestamp));
106   frame->texture_mailbox_holder_ = mailbox_holder;
107   frame->texture_target_ = texture_target;
108   frame->read_pixels_cb_ = read_pixels_cb;
109   frame->no_longer_needed_cb_ = no_longer_needed_cb;
110
111   return frame;
112 }
113
114 void VideoFrame::ReadPixelsFromNativeTexture(const SkBitmap& pixels) {
115   DCHECK_EQ(format_, NATIVE_TEXTURE);
116   if (!read_pixels_cb_.is_null())
117     read_pixels_cb_.Run(pixels);
118 }
119
120 // static
121 scoped_refptr<VideoFrame> VideoFrame::WrapExternalSharedMemory(
122     Format format,
123     const gfx::Size& coded_size,
124     const gfx::Rect& visible_rect,
125     const gfx::Size& natural_size,
126     uint8* data,
127     size_t data_size,
128     base::SharedMemoryHandle handle,
129     base::TimeDelta timestamp,
130     const base::Closure& no_longer_needed_cb) {
131   if (data_size < AllocationSize(format, coded_size))
132     return NULL;
133
134   switch (format) {
135     case I420: {
136       scoped_refptr<VideoFrame> frame(new VideoFrame(
137           format, coded_size, visible_rect, natural_size, timestamp));
138       frame->shared_memory_handle_ = handle;
139       frame->strides_[kYPlane] = coded_size.width();
140       frame->strides_[kUPlane] = coded_size.width() / 2;
141       frame->strides_[kVPlane] = coded_size.width() / 2;
142       frame->data_[kYPlane] = data;
143       frame->data_[kUPlane] = data + coded_size.GetArea();
144       frame->data_[kVPlane] = data + (coded_size.GetArea() * 5 / 4);
145       frame->no_longer_needed_cb_ = no_longer_needed_cb;
146       return frame;
147     }
148     default:
149       NOTIMPLEMENTED();
150       return NULL;
151   }
152 }
153
154 // static
155 scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvData(
156     Format format,
157     const gfx::Size& coded_size,
158     const gfx::Rect& visible_rect,
159     const gfx::Size& natural_size,
160     int32 y_stride,
161     int32 u_stride,
162     int32 v_stride,
163     uint8* y_data,
164     uint8* u_data,
165     uint8* v_data,
166     base::TimeDelta timestamp,
167     const base::Closure& no_longer_needed_cb) {
168   DCHECK(format == YV12 || format == YV16 || format == I420) << format;
169   scoped_refptr<VideoFrame> frame(new VideoFrame(
170       format, coded_size, visible_rect, natural_size, timestamp));
171   frame->strides_[kYPlane] = y_stride;
172   frame->strides_[kUPlane] = u_stride;
173   frame->strides_[kVPlane] = v_stride;
174   frame->data_[kYPlane] = y_data;
175   frame->data_[kUPlane] = u_data;
176   frame->data_[kVPlane] = v_data;
177   frame->no_longer_needed_cb_ = no_longer_needed_cb;
178   return frame;
179 }
180
181 // static
182 scoped_refptr<VideoFrame> VideoFrame::CreateEmptyFrame() {
183   return new VideoFrame(
184       VideoFrame::EMPTY, gfx::Size(), gfx::Rect(), gfx::Size(),
185       base::TimeDelta());
186 }
187
188 // static
189 scoped_refptr<VideoFrame> VideoFrame::CreateColorFrame(
190     const gfx::Size& size,
191     uint8 y, uint8 u, uint8 v,
192     base::TimeDelta timestamp) {
193   DCHECK(IsValidConfig(VideoFrame::YV12, size, gfx::Rect(size), size));
194   scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
195       VideoFrame::YV12, size, gfx::Rect(size), size, timestamp);
196   FillYUV(frame.get(), y, u, v);
197   return frame;
198 }
199
200 // static
201 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(const gfx::Size& size) {
202   const uint8 kBlackY = 0x00;
203   const uint8 kBlackUV = 0x80;
204   const base::TimeDelta kZero;
205   return CreateColorFrame(size, kBlackY, kBlackUV, kBlackUV, kZero);
206 }
207
208 #if defined(GOOGLE_TV)
209 // This block and other blocks wrapped around #if defined(GOOGLE_TV) is not
210 // maintained by the general compositor team. Please contact the following
211 // people instead:
212 //
213 // wonsik@chromium.org
214 // ycheo@chromium.org
215
216 // static
217 scoped_refptr<VideoFrame> VideoFrame::CreateHoleFrame(
218     const gfx::Size& size) {
219   DCHECK(IsValidConfig(VideoFrame::HOLE, size, gfx::Rect(size), size));
220   scoped_refptr<VideoFrame> frame(new VideoFrame(
221       VideoFrame::HOLE, size, gfx::Rect(size), size, base::TimeDelta()));
222   return frame;
223 }
224 #endif
225
226 // static
227 size_t VideoFrame::NumPlanes(Format format) {
228   switch (format) {
229     case VideoFrame::NATIVE_TEXTURE:
230 #if defined(GOOGLE_TV)
231     case VideoFrame::HOLE:
232 #endif
233       return 0;
234     case VideoFrame::RGB32:
235       return 1;
236     case VideoFrame::YV12:
237     case VideoFrame::YV16:
238     case VideoFrame::I420:
239       return 3;
240     case VideoFrame::YV12A:
241       return 4;
242     case VideoFrame::EMPTY:
243     case VideoFrame::UNKNOWN:
244       break;
245   }
246   NOTREACHED() << "Unsupported video frame format: " << format;
247   return 0;
248 }
249
250 static inline size_t RoundUp(size_t value, size_t alignment) {
251   // Check that |alignment| is a power of 2.
252   DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1)));
253   return ((value + (alignment - 1)) & ~(alignment-1));
254 }
255
256 // static
257 size_t VideoFrame::AllocationSize(Format format, const gfx::Size& coded_size) {
258   switch (format) {
259     case VideoFrame::RGB32:
260       return coded_size.GetArea() * 4;
261     case VideoFrame::YV12:
262     case VideoFrame::I420: {
263       const size_t rounded_size =
264           RoundUp(coded_size.width(), 2) * RoundUp(coded_size.height(), 2);
265       return rounded_size * 3 / 2;
266     }
267     case VideoFrame::YV12A: {
268       const size_t rounded_size =
269           RoundUp(coded_size.width(), 2) * RoundUp(coded_size.height(), 2);
270       return rounded_size * 5 / 2;
271     }
272     case VideoFrame::YV16: {
273       const size_t rounded_size =
274           RoundUp(coded_size.width(), 2) * RoundUp(coded_size.height(), 2);
275       return rounded_size * 2;
276     }
277     case VideoFrame::UNKNOWN:
278     case VideoFrame::EMPTY:
279     case VideoFrame::NATIVE_TEXTURE:
280 #if defined(GOOGLE_TV)
281     case VideoFrame::HOLE:
282 #endif
283       break;
284   }
285   NOTREACHED() << "Unsupported video frame format: " << format;
286   return 0;
287 }
288
289 // Release data allocated by AllocateRGB() or AllocateYUV().
290 static void ReleaseData(uint8* data) {
291   DCHECK(data);
292   base::AlignedFree(data);
293 }
294
295 void VideoFrame::AllocateRGB(size_t bytes_per_pixel) {
296   // Round up to align at least at a 16-byte boundary for each row.
297   // This is sufficient for MMX and SSE2 reads (movq/movdqa).
298   size_t bytes_per_row = RoundUp(coded_size_.width(),
299                                  kFrameSizeAlignment) * bytes_per_pixel;
300   size_t aligned_height = RoundUp(coded_size_.height(), kFrameSizeAlignment);
301   strides_[VideoFrame::kRGBPlane] = bytes_per_row;
302   data_[VideoFrame::kRGBPlane] = reinterpret_cast<uint8*>(
303       base::AlignedAlloc(bytes_per_row * aligned_height + kFrameSizePadding,
304                          kFrameAddressAlignment));
305   no_longer_needed_cb_ = base::Bind(&ReleaseData, data_[VideoFrame::kRGBPlane]);
306   DCHECK(!(reinterpret_cast<intptr_t>(data_[VideoFrame::kRGBPlane]) & 7));
307   COMPILE_ASSERT(0 == VideoFrame::kRGBPlane, RGB_data_must_be_index_0);
308 }
309
310 void VideoFrame::AllocateYUV() {
311   DCHECK(format_ == VideoFrame::YV12 || format_ == VideoFrame::YV16 ||
312          format_ == VideoFrame::YV12A || format_ == VideoFrame::I420);
313   // Align Y rows at least at 16 byte boundaries.  The stride for both
314   // YV12 and YV16 is 1/2 of the stride of Y.  For YV12, every row of bytes for
315   // U and V applies to two rows of Y (one byte of UV for 4 bytes of Y), so in
316   // the case of YV12 the strides are identical for the same width surface, but
317   // the number of bytes allocated for YV12 is 1/2 the amount for U & V as
318   // YV16. We also round the height of the surface allocated to be an even
319   // number to avoid any potential of faulting by code that attempts to access
320   // the Y values of the final row, but assumes that the last row of U & V
321   // applies to a full two rows of Y. YV12A is the same as YV12, but with an
322   // additional alpha plane that has the same size and alignment as the Y plane.
323
324   size_t y_stride = RoundUp(row_bytes(VideoFrame::kYPlane),
325                             kFrameSizeAlignment);
326   size_t uv_stride = RoundUp(row_bytes(VideoFrame::kUPlane),
327                              kFrameSizeAlignment);
328   // The *2 here is because some formats (e.g. h264) allow interlaced coding,
329   // and then the size needs to be a multiple of two macroblocks (vertically).
330   // See libavcodec/utils.c:avcodec_align_dimensions2().
331   size_t y_height = RoundUp(coded_size_.height(), kFrameSizeAlignment * 2);
332   size_t uv_height =
333       (format_ == VideoFrame::YV12 || format_ == VideoFrame::YV12A ||
334        format_ == VideoFrame::I420)
335           ? y_height / 2
336           : y_height;
337   size_t y_bytes = y_height * y_stride;
338   size_t uv_bytes = uv_height * uv_stride;
339   size_t a_bytes = format_ == VideoFrame::YV12A ? y_bytes : 0;
340
341   // The extra line of UV being allocated is because h264 chroma MC
342   // overreads by one line in some cases, see libavcodec/utils.c:
343   // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
344   // put_h264_chroma_mc4_ssse3().
345   uint8* data = reinterpret_cast<uint8*>(
346       base::AlignedAlloc(
347           y_bytes + (uv_bytes * 2 + uv_stride) + a_bytes + kFrameSizePadding,
348           kFrameAddressAlignment));
349   no_longer_needed_cb_ = base::Bind(&ReleaseData, data);
350   COMPILE_ASSERT(0 == VideoFrame::kYPlane, y_plane_data_must_be_index_0);
351   data_[VideoFrame::kYPlane] = data;
352   data_[VideoFrame::kUPlane] = data + y_bytes;
353   data_[VideoFrame::kVPlane] = data + y_bytes + uv_bytes;
354   strides_[VideoFrame::kYPlane] = y_stride;
355   strides_[VideoFrame::kUPlane] = uv_stride;
356   strides_[VideoFrame::kVPlane] = uv_stride;
357   if (format_ == YV12A) {
358     data_[VideoFrame::kAPlane] = data + y_bytes + (2 * uv_bytes);
359     strides_[VideoFrame::kAPlane] = y_stride;
360   }
361 }
362
363 VideoFrame::VideoFrame(VideoFrame::Format format,
364                        const gfx::Size& coded_size,
365                        const gfx::Rect& visible_rect,
366                        const gfx::Size& natural_size,
367                        base::TimeDelta timestamp)
368     : format_(format),
369       coded_size_(coded_size),
370       visible_rect_(visible_rect),
371       natural_size_(natural_size),
372       texture_target_(0),
373       shared_memory_handle_(base::SharedMemory::NULLHandle()),
374       timestamp_(timestamp) {
375   memset(&strides_, 0, sizeof(strides_));
376   memset(&data_, 0, sizeof(data_));
377 }
378
379 VideoFrame::~VideoFrame() {
380   if (!no_longer_needed_cb_.is_null())
381     base::ResetAndReturn(&no_longer_needed_cb_).Run();
382 }
383
384 bool VideoFrame::IsValidPlane(size_t plane) const {
385   return (plane < NumPlanes(format_));
386 }
387
388 int VideoFrame::stride(size_t plane) const {
389   DCHECK(IsValidPlane(plane));
390   return strides_[plane];
391 }
392
393 int VideoFrame::row_bytes(size_t plane) const {
394   DCHECK(IsValidPlane(plane));
395   int width = coded_size_.width();
396   switch (format_) {
397     // 32bpp.
398     case RGB32:
399       return width * 4;
400
401     // Planar, 8bpp.
402     case YV12A:
403       if (plane == kAPlane)
404         return width;
405     // Fallthrough.
406     case YV12:
407     case YV16:
408     case I420:
409       if (plane == kYPlane)
410         return width;
411       return RoundUp(width, 2) / 2;
412
413     default:
414       break;
415   }
416
417   // Intentionally leave out non-production formats.
418   NOTREACHED() << "Unsupported video frame format: " << format_;
419   return 0;
420 }
421
422 int VideoFrame::rows(size_t plane) const {
423   DCHECK(IsValidPlane(plane));
424   int height = coded_size_.height();
425   switch (format_) {
426     case RGB32:
427     case YV16:
428       return height;
429
430     case YV12A:
431       if (plane == kAPlane)
432         return height;
433     // Fallthrough.
434     case YV12:
435     case I420:
436       if (plane == kYPlane)
437         return height;
438       return RoundUp(height, 2) / 2;
439
440     default:
441       break;
442   }
443
444   // Intentionally leave out non-production formats.
445   NOTREACHED() << "Unsupported video frame format: " << format_;
446   return 0;
447 }
448
449 uint8* VideoFrame::data(size_t plane) const {
450   DCHECK(IsValidPlane(plane));
451   return data_[plane];
452 }
453
454 const scoped_refptr<VideoFrame::MailboxHolder>& VideoFrame::texture_mailbox()
455     const {
456   DCHECK_EQ(format_, NATIVE_TEXTURE);
457   return texture_mailbox_holder_;
458 }
459
460 uint32 VideoFrame::texture_target() const {
461   DCHECK_EQ(format_, NATIVE_TEXTURE);
462   return texture_target_;
463 }
464
465 base::SharedMemoryHandle VideoFrame::shared_memory_handle() const {
466   return shared_memory_handle_;
467 }
468
469 bool VideoFrame::IsEndOfStream() const {
470   return format_ == VideoFrame::EMPTY;
471 }
472
473 void VideoFrame::HashFrameForTesting(base::MD5Context* context) {
474   for (int plane = 0; plane < kMaxPlanes; ++plane) {
475     if (!IsValidPlane(plane))
476       break;
477     for (int row = 0; row < rows(plane); ++row) {
478       base::MD5Update(context, base::StringPiece(
479           reinterpret_cast<char*>(data(plane) + stride(plane) * row),
480           row_bytes(plane)));
481     }
482   }
483 }
484
485 VideoFrame::MailboxHolder::MailboxHolder(
486     const gpu::Mailbox& mailbox,
487     unsigned sync_point,
488     const TextureNoLongerNeededCallback& release_callback)
489     : mailbox_(mailbox),
490       sync_point_(sync_point),
491       release_callback_(release_callback) {}
492
493 VideoFrame::MailboxHolder::~MailboxHolder() {
494   if (!release_callback_.is_null())
495     release_callback_.Run(sync_point_);
496 }
497
498 }  // namespace media