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