[M120 Migration][MM][WebRTC] Base implementation for webrtc video hole stream
[platform/framework/web/chromium-efl.git] / media / base / video_frame.cc
1 // Copyright 2012 The Chromium Authors
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 <GLES2/gl2.h>
8 #include <GLES2/gl2ext.h>
9
10 #include <algorithm>
11 #include <atomic>
12 #include <climits>
13 #include <numeric>
14 #include <utility>
15
16 #include "base/bits.h"
17 #include "base/functional/bind.h"
18 #include "base/functional/callback_helpers.h"
19 #include "base/logging.h"
20 #include "base/process/memory.h"
21 #include "base/strings/string_piece.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/synchronization/lock.h"
24 #include "build/build_config.h"
25 #include "media/base/color_plane_layout.h"
26 #include "media/base/format_utils.h"
27 #include "media/base/limits.h"
28 #include "media/base/timestamp_constants.h"
29 #include "media/base/video_util.h"
30 #include "ui/gfx/buffer_format_util.h"
31 #include "ui/gfx/geometry/point.h"
32 #include "ui/gfx/gpu_memory_buffer.h"
33 #if BUILDFLAG(IS_APPLE)
34 #include "ui/gfx/mac/io_surface.h"
35 #endif
36 #if defined(TIZEN_TBM_SUPPORT)
37 #include "base/threading/thread_task_runner_handle.h"
38 #include "base/trace_event/trace_event.h"
39 #include "gpu/GLES2/gl2extchromium.h"
40 #include "gpu/command_buffer/client/gles2_interface.h"
41 #include "media/base/bind_to_current_loop.h"
42 #endif
43
44 namespace media {
45
46 namespace {
47
48 VideoFrame::ID GetNextID() {
49   static std::atomic_uint64_t counter(1u);
50   return VideoFrame::ID::FromUnsafeValue(
51       counter.fetch_add(1u, std::memory_order_relaxed));
52 }
53
54 // Helper to provide gfx::Rect::Intersect() as an expression.
55 gfx::Rect Intersection(gfx::Rect a, const gfx::Rect& b) {
56   a.Intersect(b);
57   return a;
58 }
59
60 void ReleaseMailboxAndDropGpuMemoryBuffer(
61     VideoFrame::ReleaseMailboxCB cb,
62     const gpu::SyncToken& sync_token,
63     std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer) {
64   std::move(cb).Run(sync_token);
65 }
66
67 VideoFrame::ReleaseMailboxAndGpuMemoryBufferCB WrapReleaseMailboxCB(
68     VideoFrame::ReleaseMailboxCB cb) {
69   if (cb.is_null())
70     return VideoFrame::ReleaseMailboxAndGpuMemoryBufferCB();
71   return base::BindOnce(&ReleaseMailboxAndDropGpuMemoryBuffer, std::move(cb));
72 }
73
74 }  // namespace
75
76 // static
77 std::string VideoFrame::StorageTypeToString(
78     const VideoFrame::StorageType storage_type) {
79   switch (storage_type) {
80     case VideoFrame::STORAGE_UNKNOWN:
81       return "UNKNOWN";
82     case VideoFrame::STORAGE_OPAQUE:
83       return "OPAQUE";
84     case VideoFrame::STORAGE_UNOWNED_MEMORY:
85       return "UNOWNED_MEMORY";
86     case VideoFrame::STORAGE_OWNED_MEMORY:
87       return "OWNED_MEMORY";
88     case VideoFrame::STORAGE_SHMEM:
89       return "SHMEM";
90 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
91     case VideoFrame::STORAGE_DMABUFS:
92       return "DMABUFS";
93 #endif
94 #if defined(TIZEN_TBM_SUPPORT)
95     case VideoFrame::STORAGE_TBM_SURFACE:
96       return "TBM_SURFACE";
97 #endif
98 #if defined(TIZEN_VIDEO_HOLE)
99     case VideoFrame::STORAGE_HOLE:
100       return "HOLE";
101 #endif
102     case VideoFrame::STORAGE_GPU_MEMORY_BUFFER:
103       return "GPU_MEMORY_BUFFER";
104   }
105
106   NOTREACHED() << "Invalid StorageType provided: " << storage_type;
107   return "INVALID";
108 }
109
110 // static
111 bool VideoFrame::IsStorageTypeMappable(VideoFrame::StorageType storage_type) {
112   return
113 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
114       // This is not strictly needed but makes explicit that, at VideoFrame
115       // level, DmaBufs are not mappable from userspace.
116       storage_type != VideoFrame::STORAGE_DMABUFS &&
117 #endif
118       // GpuMemoryBuffer is not mappable at VideoFrame level. In most places
119       // GpuMemoryBuffer is opaque to the CPU, and for places that really need
120       // to access the data on CPU they can get the buffer with
121       // GetGpuMemoryBuffer() and call gfx::GpuMemoryBuffer::Map().
122       (storage_type == VideoFrame::STORAGE_UNOWNED_MEMORY ||
123        storage_type == VideoFrame::STORAGE_OWNED_MEMORY ||
124        storage_type == VideoFrame::STORAGE_SHMEM);
125 }
126
127 // static
128 bool VideoFrame::IsValidPlane(VideoPixelFormat format, size_t plane) {
129   DCHECK_LE(NumPlanes(format), static_cast<size_t>(kMaxPlanes));
130   return plane < NumPlanes(format);
131 }
132
133 // static
134 gfx::Size VideoFrame::SampleSize(VideoPixelFormat format, size_t plane) {
135   DCHECK(IsValidPlane(format, plane));
136
137   switch (plane) {
138     case kYPlane:  // and kARGBPlane:
139     case kAPlane:
140       return gfx::Size(1, 1);
141
142     case kUPlane:  // and kUVPlane:
143     case kVPlane:  // and kAPlaneTriPlanar:
144       switch (format) {
145         case PIXEL_FORMAT_I444:
146         case PIXEL_FORMAT_YUV444P9:
147         case PIXEL_FORMAT_YUV444P10:
148         case PIXEL_FORMAT_YUV444P12:
149         case PIXEL_FORMAT_Y16:
150         case PIXEL_FORMAT_I444A:
151         case PIXEL_FORMAT_YUV444AP10:
152           return gfx::Size(1, 1);
153
154         case PIXEL_FORMAT_I422:
155         case PIXEL_FORMAT_YUV422P9:
156         case PIXEL_FORMAT_YUV422P10:
157         case PIXEL_FORMAT_YUV422P12:
158         case PIXEL_FORMAT_I422A:
159         case PIXEL_FORMAT_YUV422AP10:
160           return gfx::Size(2, 1);
161
162         case PIXEL_FORMAT_YV12:
163         case PIXEL_FORMAT_I420:
164         case PIXEL_FORMAT_I420A:
165         case PIXEL_FORMAT_NV12:
166         case PIXEL_FORMAT_NV21:
167         case PIXEL_FORMAT_YUV420P9:
168         case PIXEL_FORMAT_YUV420P10:
169         case PIXEL_FORMAT_YUV420P12:
170         case PIXEL_FORMAT_P016LE:
171         case PIXEL_FORMAT_YUV420AP10:
172 #if defined(TIZEN_TBM_SUPPORT)
173         case PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER:
174 #endif
175           return gfx::Size(2, 2);
176
177         case PIXEL_FORMAT_NV12A:
178           return plane == kUVPlane ? gfx::Size(2, 2) : gfx::Size(1, 1);
179
180         case PIXEL_FORMAT_UYVY:
181         case PIXEL_FORMAT_UNKNOWN:
182         case PIXEL_FORMAT_YUY2:
183         case PIXEL_FORMAT_ARGB:
184         case PIXEL_FORMAT_XRGB:
185         case PIXEL_FORMAT_RGB24:
186         case PIXEL_FORMAT_MJPEG:
187         case PIXEL_FORMAT_ABGR:
188         case PIXEL_FORMAT_XBGR:
189         case PIXEL_FORMAT_XR30:
190         case PIXEL_FORMAT_XB30:
191         case PIXEL_FORMAT_BGRA:
192         case PIXEL_FORMAT_RGBAF16:
193 #if BUILDFLAG(IS_TIZEN)
194         case PIXEL_FORMAT_ENCODED:
195 #endif
196 #if defined(TIZEN_TBM_SUPPORT)
197         case PIXEL_FORMAT_TBM_SURFACE:
198 #endif
199           break;
200       }
201   }
202   NOTREACHED_NORETURN();
203 }
204
205 // Checks if |source_format| can be wrapped into a |target_format| frame.
206 static bool AreValidPixelFormatsForWrap(VideoPixelFormat source_format,
207                                         VideoPixelFormat target_format) {
208   return source_format == target_format ||
209          (source_format == PIXEL_FORMAT_I420A &&
210           target_format == PIXEL_FORMAT_I420) ||
211          (source_format == PIXEL_FORMAT_ARGB &&
212           target_format == PIXEL_FORMAT_XRGB) ||
213          (source_format == PIXEL_FORMAT_ABGR &&
214           target_format == PIXEL_FORMAT_XBGR);
215 }
216
217 // If it is required to allocate aligned to multiple-of-two size overall for the
218 // frame of pixel |format|.
219 static bool RequiresEvenSizeAllocation(VideoPixelFormat format) {
220   switch (format) {
221     case PIXEL_FORMAT_ARGB:
222     case PIXEL_FORMAT_XRGB:
223     case PIXEL_FORMAT_RGB24:
224     case PIXEL_FORMAT_Y16:
225     case PIXEL_FORMAT_ABGR:
226     case PIXEL_FORMAT_XBGR:
227     case PIXEL_FORMAT_XR30:
228     case PIXEL_FORMAT_XB30:
229     case PIXEL_FORMAT_BGRA:
230     case PIXEL_FORMAT_RGBAF16:
231 #if BUILDFLAG(IS_TIZEN)
232     case PIXEL_FORMAT_ENCODED:
233 #endif
234 #if defined(TIZEN_TBM_SUPPORT)
235     case PIXEL_FORMAT_TBM_SURFACE:
236     case PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER:
237 #endif
238       return false;
239     case PIXEL_FORMAT_NV12:
240     case PIXEL_FORMAT_NV12A:
241     case PIXEL_FORMAT_NV21:
242     case PIXEL_FORMAT_I420:
243     case PIXEL_FORMAT_MJPEG:
244     case PIXEL_FORMAT_YUY2:
245     case PIXEL_FORMAT_YV12:
246     case PIXEL_FORMAT_I422:
247     case PIXEL_FORMAT_I444:
248     case PIXEL_FORMAT_YUV420P9:
249     case PIXEL_FORMAT_YUV422P9:
250     case PIXEL_FORMAT_YUV444P9:
251     case PIXEL_FORMAT_YUV420P10:
252     case PIXEL_FORMAT_YUV422P10:
253     case PIXEL_FORMAT_YUV444P10:
254     case PIXEL_FORMAT_YUV420P12:
255     case PIXEL_FORMAT_YUV422P12:
256     case PIXEL_FORMAT_YUV444P12:
257     case PIXEL_FORMAT_I420A:
258     case PIXEL_FORMAT_UYVY:
259     case PIXEL_FORMAT_P016LE:
260     case PIXEL_FORMAT_I422A:
261     case PIXEL_FORMAT_I444A:
262     case PIXEL_FORMAT_YUV420AP10:
263     case PIXEL_FORMAT_YUV422AP10:
264     case PIXEL_FORMAT_YUV444AP10:
265       return true;
266     case PIXEL_FORMAT_UNKNOWN:
267       break;
268   }
269   NOTREACHED() << "Unsupported video frame format: " << format;
270   return false;
271 }
272
273 // Creates VideoFrameLayout for tightly packed frame.
274 static absl::optional<VideoFrameLayout> GetDefaultLayout(
275     VideoPixelFormat format,
276     const gfx::Size& coded_size) {
277   std::vector<ColorPlaneLayout> planes;
278
279   switch (format) {
280     case PIXEL_FORMAT_I420: {
281       int uv_width = (coded_size.width() + 1) / 2;
282       int uv_height = (coded_size.height() + 1) / 2;
283       int uv_stride = uv_width;
284       int uv_size = uv_stride * uv_height;
285       planes = std::vector<ColorPlaneLayout>{
286           ColorPlaneLayout(coded_size.width(), 0, coded_size.GetArea()),
287           ColorPlaneLayout(uv_stride, coded_size.GetArea(), uv_size),
288           ColorPlaneLayout(uv_stride, coded_size.GetArea() + uv_size, uv_size),
289       };
290       break;
291     }
292
293     case PIXEL_FORMAT_Y16:
294       planes = std::vector<ColorPlaneLayout>{ColorPlaneLayout(
295           coded_size.width() * 2, 0, coded_size.GetArea() * 2)};
296       break;
297
298     case PIXEL_FORMAT_ARGB:
299     case PIXEL_FORMAT_XRGB:
300     case PIXEL_FORMAT_ABGR:
301     case PIXEL_FORMAT_XBGR:
302       planes = std::vector<ColorPlaneLayout>{ColorPlaneLayout(
303           coded_size.width() * 4, 0, coded_size.GetArea() * 4)};
304       break;
305
306     case PIXEL_FORMAT_NV12: {
307       int uv_width = (coded_size.width() + 1) / 2;
308       int uv_height = (coded_size.height() + 1) / 2;
309       int uv_stride = uv_width * 2;
310       int uv_size = uv_stride * uv_height;
311       planes = std::vector<ColorPlaneLayout>{
312           ColorPlaneLayout(coded_size.width(), 0, coded_size.GetArea()),
313           ColorPlaneLayout(uv_stride, coded_size.GetArea(), uv_size),
314       };
315       break;
316     }
317
318     case PIXEL_FORMAT_NV12A: {
319       int uv_width = (coded_size.width() + 1) / 2;
320       int uv_height = (coded_size.height() + 1) / 2;
321       int uv_stride = uv_width * 2;
322       int uv_size = uv_stride * uv_height;
323       planes = std::vector<ColorPlaneLayout>{
324           ColorPlaneLayout(coded_size.width(), 0, coded_size.GetArea()),
325           ColorPlaneLayout(uv_stride, coded_size.GetArea(), uv_size),
326           ColorPlaneLayout(coded_size.width(), 0, coded_size.GetArea()),
327       };
328       break;
329     }
330
331     default:
332       DLOG(ERROR) << "Unsupported pixel format"
333                   << VideoPixelFormatToString(format);
334       return absl::nullopt;
335   }
336
337   return VideoFrameLayout::CreateWithPlanes(format, coded_size, planes);
338 }
339
340 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
341 // This class allows us to embed a vector<ScopedFD> into a scoped_refptr, and
342 // thus to have several VideoFrames share the same set of DMABUF FDs.
343 class VideoFrame::DmabufHolder
344     : public base::RefCountedThreadSafe<DmabufHolder> {
345  public:
346   DmabufHolder() = default;
347   DmabufHolder(std::vector<base::ScopedFD>&& fds) : fds_(std::move(fds)) {}
348
349   const std::vector<base::ScopedFD>& fds() const { return fds_; }
350   size_t size() const { return fds_.size(); }
351
352  private:
353   std::vector<base::ScopedFD> fds_;
354
355   friend class base::RefCountedThreadSafe<DmabufHolder>;
356   ~DmabufHolder() = default;
357 };
358 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
359
360 // static
361 bool VideoFrame::IsValidConfig(VideoPixelFormat format,
362                                StorageType storage_type,
363                                const gfx::Size& coded_size,
364                                const gfx::Rect& visible_rect,
365                                const gfx::Size& natural_size) {
366   return IsValidConfigInternal(format, FrameControlType::kNone, coded_size,
367                                visible_rect, natural_size);
368 }
369
370 // static
371 scoped_refptr<VideoFrame> VideoFrame::CreateFrame(VideoPixelFormat format,
372                                                   const gfx::Size& coded_size,
373                                                   const gfx::Rect& visible_rect,
374                                                   const gfx::Size& natural_size,
375                                                   base::TimeDelta timestamp) {
376   return CreateFrameInternal(format, coded_size, visible_rect, natural_size,
377                              timestamp, false);
378 }
379
380 // static
381 scoped_refptr<VideoFrame> VideoFrame::CreateVideoHoleFrame(
382     const base::UnguessableToken& overlay_plane_id,
383     const gfx::Size& natural_size,
384     base::TimeDelta timestamp) {
385   auto layout = VideoFrameLayout::Create(PIXEL_FORMAT_UNKNOWN, natural_size);
386   if (!layout) {
387     DLOG(ERROR) << "Invalid layout.";
388     return nullptr;
389   }
390   scoped_refptr<VideoFrame> frame = new VideoFrame(
391       *layout, StorageType::STORAGE_OPAQUE, gfx::Rect(natural_size),
392       natural_size, timestamp, FrameControlType::kVideoHole);
393   frame->metadata().overlay_plane_id = overlay_plane_id;
394   return frame;
395 }
396
397 // static
398 scoped_refptr<VideoFrame> VideoFrame::CreateZeroInitializedFrame(
399     VideoPixelFormat format,
400     const gfx::Size& coded_size,
401     const gfx::Rect& visible_rect,
402     const gfx::Size& natural_size,
403     base::TimeDelta timestamp) {
404   return CreateFrameInternal(format, coded_size, visible_rect, natural_size,
405                              timestamp, true);
406 }
407
408 // static
409 #if defined(TIZEN_TBM_SUPPORT)
410 scoped_refptr<VideoFrame> VideoFrame::WrapTBMSurface(
411     const gfx::Size& size,
412     base::TimeDelta timestamp,
413     gfx::TbmBufferHandle handle) {
414   const VideoPixelFormat format = PIXEL_FORMAT_TBM_SURFACE;
415   const StorageType storage = STORAGE_TBM_SURFACE;
416   const gfx::Rect visible_rect = gfx::Rect(size);
417   if (!IsValidConfig(format, storage, size, visible_rect, size)) {
418     LOG(ERROR) << __FUNCTION__ << " WrapTBMSurface Invalid config."
419                << ConfigToString(format, storage, size, visible_rect, size);
420     return nullptr;
421   }
422
423   auto layout = VideoFrameLayout::Create(format, size);
424   if (!layout) {
425     LOG(ERROR) << "Invalid layout.";
426     return nullptr;
427   }
428
429   scoped_refptr<VideoFrame> frame(
430       new VideoFrame(*layout, storage, gfx::Rect(size), size, timestamp));
431   frame->buffer_handle_ = handle;
432   return frame;
433 }
434
435 #if BUILDFLAG(IS_TIZEN_TV)
436 scoped_refptr<VideoFrame> VideoFrame::WrapTBMInterProcessBuffer(
437     const gfx::Size& size,
438     base::TimeDelta timestamp,
439     gfx::TbmBufferHandle handle) {
440   const VideoPixelFormat format = PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER;
441 #if defined(TIZEN_VIDEO_HOLE)
442   const StorageType storage = STORAGE_HOLE;
443 #else
444   const StorageType storage = STORAGE_UNKNOWN;
445 #endif
446   const gfx::Rect visible_rect = gfx::Rect(size);
447   if (!IsValidConfig(format, storage, size, visible_rect, size)) {
448     DLOG(ERROR) << __FUNCTION__ << " WrapTBMInterProcessBuffer Invalid config."
449                 << ConfigToString(format, storage, size, visible_rect, size);
450     return nullptr;
451   }
452
453   auto layout = VideoFrameLayout::CreateWithStrides(
454       format, size, {handle.strides[0], handle.strides[1]});
455   if (!layout) {
456     DLOG(ERROR) << "Invalid layout.";
457     return nullptr;
458   }
459
460   scoped_refptr<VideoFrame> frame(
461       new VideoFrame(*layout, storage, gfx::Rect(size), size, timestamp));
462   frame->buffer_handle_ = handle;
463   return frame;
464 }
465 #endif
466 #endif
467
468 // static
469 scoped_refptr<VideoFrame> VideoFrame::WrapNativeTextures(
470     VideoPixelFormat format,
471     const gpu::MailboxHolder (&mailbox_holders)[kMaxPlanes],
472     ReleaseMailboxCB mailbox_holder_release_cb,
473     const gfx::Size& coded_size,
474     const gfx::Rect& visible_rect,
475     const gfx::Size& natural_size,
476     base::TimeDelta timestamp) {
477   if (format != PIXEL_FORMAT_ARGB && format != PIXEL_FORMAT_XRGB &&
478       format != PIXEL_FORMAT_NV12 && format != PIXEL_FORMAT_NV12A &&
479       format != PIXEL_FORMAT_I420 && format != PIXEL_FORMAT_ABGR &&
480       format != PIXEL_FORMAT_XBGR && format != PIXEL_FORMAT_XR30 &&
481       format != PIXEL_FORMAT_XB30 && format != PIXEL_FORMAT_P016LE &&
482       format != PIXEL_FORMAT_RGBAF16 && format != PIXEL_FORMAT_YV12 &&
483       format != PIXEL_FORMAT_BGRA) {
484     DLOG(ERROR) << "Unsupported pixel format: "
485                 << VideoPixelFormatToString(format);
486     return nullptr;
487   }
488   const StorageType storage = STORAGE_OPAQUE;
489   if (!IsValidConfig(format, storage, coded_size, visible_rect, natural_size)) {
490     DLOG(ERROR) << __func__ << " Invalid config."
491                 << ConfigToString(format, storage, coded_size, visible_rect,
492                                   natural_size);
493     return nullptr;
494   }
495
496   auto layout = VideoFrameLayout::Create(format, coded_size);
497   if (!layout) {
498     DLOG(ERROR) << "Invalid layout.";
499     return nullptr;
500   }
501
502   scoped_refptr<VideoFrame> frame =
503       new VideoFrame(*layout, storage, visible_rect, natural_size, timestamp);
504   memcpy(&frame->mailbox_holders_, mailbox_holders,
505          sizeof(frame->mailbox_holders_));
506   frame->mailbox_holders_and_gmb_release_cb_ =
507       WrapReleaseMailboxCB(std::move(mailbox_holder_release_cb));
508
509   // Wrapping native textures should... have textures. https://crbug.com/864145.
510   DCHECK(frame->HasTextures());
511   DCHECK_GT(frame->NumTextures(), 0u);
512
513   return frame;
514 }
515
516 // static
517 scoped_refptr<VideoFrame> VideoFrame::WrapExternalData(
518     VideoPixelFormat format,
519     const gfx::Size& coded_size,
520     const gfx::Rect& visible_rect,
521     const gfx::Size& natural_size,
522     const uint8_t* data,
523     size_t data_size,
524     base::TimeDelta timestamp,
525     size_t encoded_data_size) {
526   absl::optional<VideoFrameLayout> layout;
527   if (format == PIXEL_FORMAT_ENCODED) {
528     auto plane = media::ColorPlaneLayout(encoded_data_size, 0, data_size);
529     layout = media::VideoFrameLayout::CreateWithPlanes(format, coded_size,
530                                                        {std::move(plane)});
531   } else {
532     layout = GetDefaultLayout(format, coded_size);
533   }
534
535   if (!layout)
536     return nullptr;
537   return WrapExternalDataWithLayout(*layout, visible_rect, natural_size, data,
538                                     data_size, timestamp);
539 }
540
541 // static
542 scoped_refptr<VideoFrame> VideoFrame::WrapExternalDataWithLayout(
543     const VideoFrameLayout& layout,
544     const gfx::Rect& visible_rect,
545     const gfx::Size& natural_size,
546     const uint8_t* data,
547     size_t data_size,
548     base::TimeDelta timestamp) {
549   StorageType storage_type = STORAGE_UNOWNED_MEMORY;
550
551   if (!IsValidConfig(layout.format(), storage_type, layout.coded_size(),
552                      visible_rect, natural_size) ||
553       !layout.FitsInContiguousBufferOfSize(data_size)) {
554     DLOG(ERROR) << "Invalid config: "
555                 << ConfigToString(layout.format(), storage_type,
556                                   layout.coded_size(), visible_rect,
557                                   natural_size);
558     return nullptr;
559   }
560
561   scoped_refptr<VideoFrame> frame = new VideoFrame(
562       layout, storage_type, visible_rect, natural_size, timestamp);
563
564   for (size_t i = 0; i < layout.planes().size(); ++i) {
565     frame->data_[i] = data + layout.planes()[i].offset;
566   }
567
568   return frame;
569 }
570
571 // static
572 scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvData(
573     VideoPixelFormat format,
574     const gfx::Size& coded_size,
575     const gfx::Rect& visible_rect,
576     const gfx::Size& natural_size,
577     int32_t y_stride,
578     int32_t u_stride,
579     int32_t v_stride,
580     const uint8_t* y_data,
581     const uint8_t* u_data,
582     const uint8_t* v_data,
583     base::TimeDelta timestamp) {
584   auto layout = VideoFrameLayout::CreateWithStrides(
585       format, coded_size, {y_stride, u_stride, v_stride});
586   if (!layout) {
587     DLOG(ERROR) << "Invalid layout.";
588     return nullptr;
589   }
590
591   return WrapExternalYuvDataWithLayout(*layout, visible_rect, natural_size,
592                                        y_data, u_data, v_data, timestamp);
593 }
594
595 // static
596 scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvDataWithLayout(
597     const VideoFrameLayout& layout,
598     const gfx::Rect& visible_rect,
599     const gfx::Size& natural_size,
600     const uint8_t* y_data,
601     const uint8_t* u_data,
602     const uint8_t* v_data,
603     base::TimeDelta timestamp) {
604   const StorageType storage = STORAGE_UNOWNED_MEMORY;
605   const VideoPixelFormat format = layout.format();
606   if (!IsValidConfig(format, storage, layout.coded_size(), visible_rect,
607                      natural_size)) {
608     DLOG(ERROR) << __func__ << " Invalid config."
609                 << ConfigToString(format, storage, layout.coded_size(),
610                                   visible_rect, natural_size);
611     return nullptr;
612   }
613   if (!IsYuvPlanar(format)) {
614     DLOG(ERROR) << __func__ << " Format is not YUV. " << format;
615     return nullptr;
616   }
617
618   DCHECK_LE(NumPlanes(format), 3u);
619   scoped_refptr<VideoFrame> frame(
620       new VideoFrame(layout, storage, visible_rect, natural_size, timestamp));
621   frame->data_[kYPlane] = y_data;
622   frame->data_[kUPlane] = u_data;
623   frame->data_[kVPlane] = v_data;
624   return frame;
625 }
626
627 // static
628 scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvaData(
629     VideoPixelFormat format,
630     const gfx::Size& coded_size,
631     const gfx::Rect& visible_rect,
632     const gfx::Size& natural_size,
633     int32_t y_stride,
634     int32_t u_stride,
635     int32_t v_stride,
636     int32_t a_stride,
637     const uint8_t* y_data,
638     const uint8_t* u_data,
639     const uint8_t* v_data,
640     const uint8_t* a_data,
641     base::TimeDelta timestamp) {
642   const StorageType storage = STORAGE_UNOWNED_MEMORY;
643   if (!IsValidConfig(format, storage, coded_size, visible_rect, natural_size)) {
644     DLOG(ERROR) << __func__ << " Invalid config."
645                 << ConfigToString(format, storage, coded_size, visible_rect,
646                                   natural_size);
647     return nullptr;
648   }
649
650   if (NumPlanes(format) != 4) {
651     DLOG(ERROR) << "Expecting Y, U, V and A planes to be present for the video"
652                 << " format.";
653     return nullptr;
654   }
655
656   auto layout = VideoFrameLayout::CreateWithStrides(
657       format, coded_size, {y_stride, u_stride, v_stride, a_stride});
658   if (!layout) {
659     DLOG(ERROR) << "Invalid layout";
660     return nullptr;
661   }
662
663   scoped_refptr<VideoFrame> frame(
664       new VideoFrame(*layout, storage, visible_rect, natural_size, timestamp));
665   frame->data_[kYPlane] = y_data;
666   frame->data_[kUPlane] = u_data;
667   frame->data_[kVPlane] = v_data;
668   frame->data_[kAPlane] = a_data;
669   return frame;
670 }
671
672 // static
673 scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvData(
674     VideoPixelFormat format,
675     const gfx::Size& coded_size,
676     const gfx::Rect& visible_rect,
677     const gfx::Size& natural_size,
678     int32_t y_stride,
679     int32_t uv_stride,
680     const uint8_t* y_data,
681     const uint8_t* uv_data,
682     base::TimeDelta timestamp) {
683   const StorageType storage = STORAGE_UNOWNED_MEMORY;
684   if (!IsValidConfig(format, storage, coded_size, visible_rect, natural_size)) {
685     DLOG(ERROR) << __func__ << " Invalid config."
686                 << ConfigToString(format, storage, coded_size, visible_rect,
687                                   natural_size);
688     return nullptr;
689   }
690
691   if (NumPlanes(format) != 2) {
692     DLOG(ERROR) << "Expecting Y, UV planes to be present for the video format.";
693     return nullptr;
694   }
695
696   auto layout = VideoFrameLayout::CreateWithStrides(format, coded_size,
697                                                     {y_stride, uv_stride});
698   if (!layout) {
699     DLOG(ERROR) << "Invalid layout";
700     return nullptr;
701   }
702
703   scoped_refptr<VideoFrame> frame(
704       new VideoFrame(*layout, storage, visible_rect, natural_size, timestamp));
705   frame->data_[kYPlane] = y_data;
706   frame->data_[kUVPlane] = uv_data;
707
708   return frame;
709 }
710
711 // static
712 scoped_refptr<VideoFrame> VideoFrame::WrapExternalGpuMemoryBuffer(
713     const gfx::Rect& visible_rect,
714     const gfx::Size& natural_size,
715     std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer,
716     const gpu::MailboxHolder (&mailbox_holders)[kMaxPlanes],
717     ReleaseMailboxAndGpuMemoryBufferCB mailbox_holder_and_gmb_release_cb,
718     base::TimeDelta timestamp) {
719   const absl::optional<VideoPixelFormat> format =
720       GfxBufferFormatToVideoPixelFormat(gpu_memory_buffer->GetFormat());
721   if (!format)
722     return nullptr;
723   constexpr StorageType storage = STORAGE_GPU_MEMORY_BUFFER;
724   const gfx::Size& coded_size = gpu_memory_buffer->GetSize();
725   if (!IsValidConfig(*format, storage, coded_size, visible_rect,
726                      natural_size)) {
727     DLOG(ERROR) << __func__ << " Invalid config"
728                 << ConfigToString(*format, storage, coded_size, visible_rect,
729                                   natural_size);
730     return nullptr;
731   }
732
733   const size_t num_planes =
734       NumberOfPlanesForLinearBufferFormat(gpu_memory_buffer->GetFormat());
735   std::vector<ColorPlaneLayout> planes(num_planes);
736   for (size_t i = 0; i < num_planes; ++i)
737     planes[i].stride = gpu_memory_buffer->stride(i);
738   uint64_t modifier = gfx::NativePixmapHandle::kNoModifier;
739 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
740   if (gpu_memory_buffer->GetType() == gfx::NATIVE_PIXMAP) {
741     const auto gmb_handle = gpu_memory_buffer->CloneHandle();
742     if (gmb_handle.is_null() ||
743         gmb_handle.native_pixmap_handle.planes.empty()) {
744       DLOG(ERROR) << "Failed to clone the GpuMemoryBufferHandle";
745       return nullptr;
746     }
747     if (gmb_handle.native_pixmap_handle.planes.size() != num_planes) {
748       DLOG(ERROR) << "Invalid number of planes="
749                   << gmb_handle.native_pixmap_handle.planes.size()
750                   << ", expected num_planes=" << num_planes;
751       return nullptr;
752     }
753     for (size_t i = 0; i < num_planes; ++i) {
754       const auto& plane = gmb_handle.native_pixmap_handle.planes[i];
755       planes[i].stride = plane.stride;
756       planes[i].offset = plane.offset;
757       planes[i].size = plane.size;
758     }
759     modifier = gmb_handle.native_pixmap_handle.modifier;
760   }
761 #endif
762
763   const auto layout = VideoFrameLayout::CreateWithPlanes(
764       *format, coded_size, std::move(planes),
765       VideoFrameLayout::kBufferAddressAlignment, modifier);
766   if (!layout) {
767     DLOG(ERROR) << __func__ << " Invalid layout";
768     return nullptr;
769   }
770
771   scoped_refptr<VideoFrame> frame =
772       new VideoFrame(*layout, storage, visible_rect, natural_size, timestamp);
773   if (!frame) {
774     DLOG(ERROR) << __func__ << " Couldn't create VideoFrame instance";
775     return nullptr;
776   }
777   frame->gpu_memory_buffer_ = std::move(gpu_memory_buffer);
778   memcpy(&frame->mailbox_holders_, mailbox_holders,
779          sizeof(frame->mailbox_holders_));
780   frame->mailbox_holders_and_gmb_release_cb_ =
781       std::move(mailbox_holder_and_gmb_release_cb);
782   return frame;
783 }
784
785 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
786 // static
787 scoped_refptr<VideoFrame> VideoFrame::WrapExternalDmabufs(
788     const VideoFrameLayout& layout,
789     const gfx::Rect& visible_rect,
790     const gfx::Size& natural_size,
791     std::vector<base::ScopedFD> dmabuf_fds,
792     base::TimeDelta timestamp) {
793   const StorageType storage = STORAGE_DMABUFS;
794   const VideoPixelFormat format = layout.format();
795   const gfx::Size& coded_size = layout.coded_size();
796   if (!IsValidConfig(format, storage, coded_size, visible_rect, natural_size)) {
797     DLOG(ERROR) << __func__ << " Invalid config."
798                 << ConfigToString(format, storage, coded_size, visible_rect,
799                                   natural_size);
800     return nullptr;
801   }
802
803   if (dmabuf_fds.empty() || dmabuf_fds.size() > NumPlanes(format)) {
804     DLOG(ERROR) << __func__ << " Incorrect number of dmabuf fds provided, got: "
805                 << dmabuf_fds.size() << ", expected 1 to " << NumPlanes(format);
806     return nullptr;
807   }
808
809   gpu::MailboxHolder mailbox_holders[kMaxPlanes];
810   scoped_refptr<VideoFrame> frame =
811       new VideoFrame(layout, storage, visible_rect, natural_size, timestamp);
812   if (!frame) {
813     DLOG(ERROR) << __func__ << " Couldn't create VideoFrame instance.";
814     return nullptr;
815   }
816   memcpy(&frame->mailbox_holders_, mailbox_holders,
817          sizeof(frame->mailbox_holders_));
818   frame->mailbox_holders_and_gmb_release_cb_ =
819       ReleaseMailboxAndGpuMemoryBufferCB();
820   frame->dmabuf_fds_ =
821       base::MakeRefCounted<DmabufHolder>(std::move(dmabuf_fds));
822   DCHECK(frame->HasDmaBufs());
823
824   return frame;
825 }
826 #endif
827
828 #if BUILDFLAG(IS_APPLE)
829 // static
830 scoped_refptr<VideoFrame> VideoFrame::WrapUnacceleratedIOSurface(
831     gfx::GpuMemoryBufferHandle handle,
832     const gfx::Rect& visible_rect,
833     base::TimeDelta timestamp) {
834   if (handle.type != gfx::GpuMemoryBufferType::IO_SURFACE_BUFFER) {
835     DLOG(ERROR) << "Non-IOSurface handle.";
836     return nullptr;
837   }
838   gfx::ScopedIOSurface io_surface = handle.io_surface;
839   if (!io_surface) {
840     return nullptr;
841   }
842
843   // Only support NV12 IOSurfaces.
844   const OSType cv_pixel_format = IOSurfaceGetPixelFormat(io_surface.get());
845   if (cv_pixel_format != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) {
846     DLOG(ERROR) << "Invalid (non-NV12) pixel format.";
847     return nullptr;
848   }
849   const VideoPixelFormat pixel_format = PIXEL_FORMAT_NV12;
850
851   // Retrieve the layout parameters for |io_surface_|.
852   const size_t num_planes = IOSurfaceGetPlaneCount(io_surface.get());
853   const gfx::Size size(IOSurfaceGetWidth(io_surface.get()),
854                        IOSurfaceGetHeight(io_surface.get()));
855   std::vector<int32_t> strides;
856   for (size_t i = 0; i < num_planes; ++i)
857     strides.push_back(IOSurfaceGetBytesPerRowOfPlane(io_surface.get(), i));
858   absl::optional<VideoFrameLayout> layout =
859       media::VideoFrameLayout::CreateWithStrides(pixel_format, size, strides);
860   if (!layout) {
861     DLOG(ERROR) << "Invalid layout.";
862     return nullptr;
863   }
864
865   const StorageType storage_type = STORAGE_UNOWNED_MEMORY;
866   if (!IsValidConfig(pixel_format, storage_type, size, visible_rect, size)) {
867     DLOG(ERROR) << "Invalid config.";
868     return nullptr;
869   }
870
871   // Lock the IOSurface for CPU read access. After the VideoFrame is created,
872   // add a destruction callback to unlock the IOSurface.
873   kern_return_t lock_result =
874       IOSurfaceLock(io_surface.get(), kIOSurfaceLockReadOnly, nullptr);
875   if (lock_result != kIOReturnSuccess) {
876     DLOG(ERROR) << "Failed to lock IOSurface.";
877     return nullptr;
878   }
879   auto unlock_lambda =
880       [](base::apple::ScopedCFTypeRef<IOSurfaceRef> io_surface) {
881         IOSurfaceUnlock(io_surface.get(), kIOSurfaceLockReadOnly, nullptr);
882       };
883
884   scoped_refptr<VideoFrame> frame =
885       new VideoFrame(*layout, storage_type, visible_rect, size, timestamp);
886   for (size_t i = 0; i < num_planes; ++i) {
887     frame->data_[i] = reinterpret_cast<uint8_t*>(
888         IOSurfaceGetBaseAddressOfPlane(io_surface.get(), i));
889   }
890   frame->AddDestructionObserver(
891       base::BindOnce(unlock_lambda, std::move(io_surface)));
892   return frame;
893 }
894
895 // static
896 scoped_refptr<VideoFrame> VideoFrame::WrapCVPixelBuffer(
897     CVPixelBufferRef cv_pixel_buffer,
898     base::TimeDelta timestamp) {
899   DCHECK(cv_pixel_buffer);
900   DCHECK(CFGetTypeID(cv_pixel_buffer) == CVPixelBufferGetTypeID());
901
902   const OSType cv_format = CVPixelBufferGetPixelFormatType(cv_pixel_buffer);
903   VideoPixelFormat format;
904   // There are very few compatible CV pixel formats, so just check each.
905   if (cv_format == kCVPixelFormatType_420YpCbCr8Planar) {
906     format = PIXEL_FORMAT_I420;
907   } else if (cv_format == kCVPixelFormatType_444YpCbCr8) {
908     format = PIXEL_FORMAT_I444;
909   } else if (cv_format == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) {
910     format = PIXEL_FORMAT_NV12;
911   } else if (cv_format ==
912              kCVPixelFormatType_420YpCbCr8VideoRange_8A_TriPlanar) {
913     format = PIXEL_FORMAT_NV12A;
914   } else {
915     DLOG(ERROR) << "CVPixelBuffer format not supported: " << cv_format;
916     return nullptr;
917   }
918
919   const gfx::Size coded_size(CVImageBufferGetEncodedSize(cv_pixel_buffer));
920   const gfx::Rect visible_rect(CVImageBufferGetCleanRect(cv_pixel_buffer));
921   const gfx::Size natural_size(CVImageBufferGetDisplaySize(cv_pixel_buffer));
922   const StorageType storage = STORAGE_UNOWNED_MEMORY;
923
924   if (!IsValidConfig(format, storage, coded_size, visible_rect, natural_size)) {
925     DLOG(ERROR) << __func__ << " Invalid config."
926                 << ConfigToString(format, storage, coded_size, visible_rect,
927                                   natural_size);
928     return nullptr;
929   }
930
931   auto layout = VideoFrameLayout::Create(format, coded_size);
932   if (!layout) {
933     DLOG(ERROR) << "Invalid layout.";
934     return nullptr;
935   }
936
937   scoped_refptr<VideoFrame> frame(
938       new VideoFrame(*layout, storage, visible_rect, natural_size, timestamp));
939
940   frame->cv_pixel_buffer_.reset(cv_pixel_buffer, base::scoped_policy::RETAIN);
941   return frame;
942 }
943 #endif
944
945 // static
946 scoped_refptr<VideoFrame> VideoFrame::WrapVideoFrame(
947     scoped_refptr<VideoFrame> frame,
948     VideoPixelFormat format,
949     const gfx::Rect& visible_rect,
950     const gfx::Size& natural_size) {
951   DCHECK(frame->visible_rect().Contains(visible_rect));
952
953   if (!AreValidPixelFormatsForWrap(frame->format(), format)) {
954     DLOG(ERROR) << __func__ << " Invalid format conversion."
955                 << VideoPixelFormatToString(frame->format()) << " to "
956                 << VideoPixelFormatToString(format);
957     return nullptr;
958   }
959
960   if (!IsValidConfig(format, frame->storage_type(), frame->coded_size(),
961                      visible_rect, natural_size)) {
962     DLOG(ERROR) << __func__ << " Invalid config."
963                 << ConfigToString(format, frame->storage_type(),
964                                   frame->coded_size(), visible_rect,
965                                   natural_size);
966     return nullptr;
967   }
968
969   size_t new_plane_count = NumPlanes(format);
970   absl::optional<VideoFrameLayout> new_layout;
971   if (format == frame->format()) {
972     new_layout = frame->layout();
973   } else {
974     std::vector<ColorPlaneLayout> new_planes = frame->layout().planes();
975     if (new_plane_count > new_planes.size()) {
976       DLOG(ERROR) << " Wrapping frame has more planes than old one."
977                   << " old plane count: " << new_planes.size()
978                   << " new plane count: " << new_plane_count;
979       return nullptr;
980     }
981     new_planes.resize(new_plane_count);
982     new_layout = VideoFrameLayout::CreateWithPlanes(format, frame->coded_size(),
983                                                     new_planes);
984   }
985
986   if (!new_layout.has_value()) {
987     DLOG(ERROR) << " Can't create layout for the wrapping frame";
988     return nullptr;
989   }
990
991   scoped_refptr<VideoFrame> wrapping_frame(
992       new VideoFrame(new_layout.value(), frame->storage_type(), visible_rect,
993                      natural_size, frame->timestamp()));
994
995   // Copy all metadata to the wrapped frame->
996   wrapping_frame->metadata().MergeMetadataFrom(frame->metadata());
997   wrapping_frame->set_color_space(frame->ColorSpace());
998   wrapping_frame->set_hdr_metadata(frame->hdr_metadata());
999
1000   if (frame->IsMappable()) {
1001     for (size_t i = 0; i < new_plane_count; ++i) {
1002       wrapping_frame->data_[i] = frame->data_[i];
1003     }
1004   }
1005
1006 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
1007   DCHECK(frame->dmabuf_fds_);
1008   // If there are any |dmabuf_fds_| plugged in, we should refer them too.
1009   wrapping_frame->dmabuf_fds_ = frame->dmabuf_fds_;
1010 #endif
1011
1012   if (frame->storage_type() == STORAGE_SHMEM) {
1013     DCHECK(frame->shm_region_ && frame->shm_region_->IsValid());
1014     wrapping_frame->BackWithSharedMemory(frame->shm_region_);
1015   }
1016
1017   // Don't let a Matryoshka doll of frames occur. Do this here instead of above
1018   // since |frame| may have different metadata than |frame->wrapped_frame_|.
1019   //
1020   // We must still keep |frame| alive though since it may have destruction
1021   // observers which signal that the underlying resource is okay to reuse. E.g.,
1022   // VideoFramePool.
1023   if (frame->wrapped_frame_) {
1024     wrapping_frame->AddDestructionObserver(base::DoNothingWithBoundArgs(frame));
1025     frame = frame->wrapped_frame_;
1026   }
1027
1028 #if defined(TIZEN_TBM_SUPPORT)
1029   if (frame->format() == PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER ||
1030       frame->format() == PIXEL_FORMAT_TBM_SURFACE) {
1031     wrapping_frame->buffer_handle_ = frame->buffer_handle_;
1032   }
1033 #endif
1034
1035   wrapping_frame->wrapped_frame_ = std::move(frame);
1036   return wrapping_frame;
1037 }
1038
1039 // static
1040 scoped_refptr<VideoFrame> VideoFrame::CreateEOSFrame() {
1041   auto layout = VideoFrameLayout::Create(PIXEL_FORMAT_UNKNOWN, gfx::Size());
1042   if (!layout) {
1043     DLOG(ERROR) << "Invalid layout.";
1044     return nullptr;
1045   }
1046   scoped_refptr<VideoFrame> frame =
1047       new VideoFrame(*layout, STORAGE_UNKNOWN, gfx::Rect(), gfx::Size(),
1048                      kNoTimestamp, FrameControlType::kEos);
1049   frame->metadata().end_of_stream = true;
1050   return frame;
1051 }
1052
1053 // static
1054 scoped_refptr<VideoFrame> VideoFrame::CreateColorFrame(
1055     const gfx::Size& size,
1056     uint8_t y,
1057     uint8_t u,
1058     uint8_t v,
1059     base::TimeDelta timestamp) {
1060   scoped_refptr<VideoFrame> frame =
1061       CreateFrame(PIXEL_FORMAT_I420, size, gfx::Rect(size), size, timestamp);
1062   if (frame)
1063     FillYUV(frame.get(), y, u, v);
1064   return frame;
1065 }
1066
1067 // static
1068 scoped_refptr<VideoFrame> VideoFrame::CreateBlackFrame(const gfx::Size& size) {
1069   const uint8_t kBlackY = 0x00;
1070   const uint8_t kBlackUV = 0x80;
1071   const base::TimeDelta kZero;
1072   return CreateColorFrame(size, kBlackY, kBlackUV, kBlackUV, kZero);
1073 }
1074
1075 // static
1076 scoped_refptr<VideoFrame> VideoFrame::CreateTransparentFrame(
1077     const gfx::Size& size) {
1078   const uint8_t kBlackY = 0x00;
1079   const uint8_t kBlackUV = 0x00;
1080   const uint8_t kTransparentA = 0x00;
1081   const base::TimeDelta kZero;
1082   scoped_refptr<VideoFrame> frame =
1083       CreateFrame(PIXEL_FORMAT_I420A, size, gfx::Rect(size), size, kZero);
1084   if (frame)
1085     FillYUVA(frame.get(), kBlackY, kBlackUV, kBlackUV, kTransparentA);
1086   return frame;
1087 }
1088
1089 #if defined(TIZEN_VIDEO_HOLE)
1090 // This block and other blocks wrapped around #if defined(TIZEN_VIDEO_HOLE) is
1091 // not maintained by the general compositor team. Please contact
1092 // wonsik@chromium.org .
1093
1094 // static
1095 scoped_refptr<VideoFrame> VideoFrame::CreateHoleFrame(
1096     const gfx::Size& natural_size) {
1097   auto layout = VideoFrameLayout::Create(PIXEL_FORMAT_UNKNOWN, natural_size);
1098   scoped_refptr<VideoFrame> frame =
1099       new VideoFrame(*layout, StorageType::STORAGE_HOLE,
1100                      gfx::Rect(natural_size), natural_size, base::TimeDelta());
1101   return frame;
1102 }
1103 #endif  // defined(TIZEN_VIDEO_HOLE)
1104
1105 // static
1106 size_t VideoFrame::NumPlanes(VideoPixelFormat format) {
1107   return VideoFrameLayout::NumPlanes(format);
1108 }
1109
1110 // static
1111 size_t VideoFrame::AllocationSize(VideoPixelFormat format,
1112                                   const gfx::Size& coded_size) {
1113   size_t total = 0;
1114   for (size_t i = 0; i < NumPlanes(format); ++i)
1115     total += PlaneSize(format, i, coded_size).GetArea();
1116   return total;
1117 }
1118
1119 // static
1120 gfx::Size VideoFrame::PlaneSize(VideoPixelFormat format,
1121                                 size_t plane,
1122                                 const gfx::Size& coded_size) {
1123   gfx::Size size = PlaneSizeInSamples(format, plane, coded_size);
1124   size.set_width(size.width() * BytesPerElement(format, plane));
1125   return size;
1126 }
1127
1128 // static
1129 gfx::Size VideoFrame::PlaneSizeInSamples(VideoPixelFormat format,
1130                                          size_t plane,
1131                                          const gfx::Size& coded_size) {
1132   DCHECK(IsValidPlane(format, plane));
1133
1134   int width = coded_size.width();
1135   int height = coded_size.height();
1136   if (RequiresEvenSizeAllocation(format)) {
1137     // Align to multiple-of-two size overall. This ensures that non-subsampled
1138     // planes can be addressed by pixel with the same scaling as the subsampled
1139     // planes.
1140     width = base::bits::AlignUp(width, 2);
1141     height = base::bits::AlignUp(height, 2);
1142   }
1143
1144   const gfx::Size subsample = SampleSize(format, plane);
1145   DCHECK(width % subsample.width() == 0);
1146   DCHECK(height % subsample.height() == 0);
1147   return gfx::Size(width / subsample.width(), height / subsample.height());
1148 }
1149
1150 // static
1151 int VideoFrame::PlaneHorizontalBitsPerPixel(VideoPixelFormat format,
1152                                             size_t plane) {
1153   DCHECK(IsValidPlane(format, plane));
1154   const int bits_per_element = 8 * BytesPerElement(format, plane);
1155   const int horiz_pixels_per_element = SampleSize(format, plane).width();
1156   DCHECK_EQ(bits_per_element % horiz_pixels_per_element, 0);
1157   return bits_per_element / horiz_pixels_per_element;
1158 }
1159
1160 // static
1161 int VideoFrame::PlaneBitsPerPixel(VideoPixelFormat format, size_t plane) {
1162   DCHECK(IsValidPlane(format, plane));
1163   return PlaneHorizontalBitsPerPixel(format, plane) /
1164          SampleSize(format, plane).height();
1165 }
1166
1167 // static
1168 size_t VideoFrame::RowBytes(size_t plane, VideoPixelFormat format, int width) {
1169   DCHECK(IsValidPlane(format, plane));
1170   return BytesPerElement(format, plane) * Columns(plane, format, width);
1171 }
1172
1173 // static
1174 int VideoFrame::BytesPerElement(VideoPixelFormat format, size_t plane) {
1175   DCHECK(IsValidPlane(format, plane));
1176   switch (format) {
1177     case PIXEL_FORMAT_RGBAF16:
1178       return 8;
1179     case PIXEL_FORMAT_ARGB:
1180     case PIXEL_FORMAT_BGRA:
1181     case PIXEL_FORMAT_XRGB:
1182     case PIXEL_FORMAT_ABGR:
1183     case PIXEL_FORMAT_XBGR:
1184     case PIXEL_FORMAT_XR30:
1185     case PIXEL_FORMAT_XB30:
1186 #if BUILDFLAG(IS_TIZEN)
1187     case PIXEL_FORMAT_ENCODED:
1188 #endif
1189       return 4;
1190     case PIXEL_FORMAT_RGB24:
1191       return 3;
1192     case PIXEL_FORMAT_Y16:
1193     case PIXEL_FORMAT_UYVY:
1194     case PIXEL_FORMAT_YUY2:
1195     case PIXEL_FORMAT_YUV420P9:
1196     case PIXEL_FORMAT_YUV422P9:
1197     case PIXEL_FORMAT_YUV444P9:
1198     case PIXEL_FORMAT_YUV420P10:
1199     case PIXEL_FORMAT_YUV422P10:
1200     case PIXEL_FORMAT_YUV444P10:
1201     case PIXEL_FORMAT_YUV420P12:
1202     case PIXEL_FORMAT_YUV422P12:
1203     case PIXEL_FORMAT_YUV444P12:
1204     case PIXEL_FORMAT_YUV420AP10:
1205     case PIXEL_FORMAT_YUV422AP10:
1206     case PIXEL_FORMAT_YUV444AP10:
1207       return 2;
1208 #if defined(TIZEN_TBM_SUPPORT)
1209     case PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER:
1210 #endif
1211     case PIXEL_FORMAT_NV12:
1212     case PIXEL_FORMAT_NV21: {
1213       static const int bytes_per_element[] = {1, 2};
1214       DCHECK_LT(plane, std::size(bytes_per_element));
1215       return bytes_per_element[plane];
1216     }
1217     case PIXEL_FORMAT_NV12A: {
1218       static const int bytes_per_element[] = {1, 2, 1};
1219       DCHECK_LT(plane, std::size(bytes_per_element));
1220       return bytes_per_element[plane];
1221     }
1222     case PIXEL_FORMAT_P016LE: {
1223       static const int bytes_per_element[] = {1, 2};
1224       DCHECK_LT(plane, std::size(bytes_per_element));
1225       return bytes_per_element[plane] * 2;
1226     }
1227     case PIXEL_FORMAT_YV12:
1228     case PIXEL_FORMAT_I420:
1229     case PIXEL_FORMAT_I422:
1230     case PIXEL_FORMAT_I420A:
1231     case PIXEL_FORMAT_I444:
1232     case PIXEL_FORMAT_I422A:
1233     case PIXEL_FORMAT_I444A:
1234       return 1;
1235     case PIXEL_FORMAT_MJPEG:
1236       return 0;
1237 #if defined(TIZEN_TBM_SUPPORT)
1238     case PIXEL_FORMAT_TBM_SURFACE:
1239 #endif
1240     case PIXEL_FORMAT_UNKNOWN:
1241       break;
1242   }
1243   NOTREACHED_NORETURN();
1244 }
1245
1246 // static
1247 std::vector<int32_t> VideoFrame::ComputeStrides(VideoPixelFormat format,
1248                                                 const gfx::Size& coded_size) {
1249   std::vector<int32_t> strides;
1250   const size_t num_planes = NumPlanes(format);
1251   if (num_planes == 1) {
1252     strides.push_back(RowBytes(0, format, coded_size.width()));
1253   } else {
1254     for (size_t plane = 0; plane < num_planes; ++plane) {
1255       strides.push_back(base::bits::AlignUp(
1256           RowBytes(plane, format, coded_size.width()), kFrameAddressAlignment));
1257     }
1258   }
1259   return strides;
1260 }
1261
1262 // static
1263 size_t VideoFrame::Rows(size_t plane, VideoPixelFormat format, int height) {
1264   DCHECK(IsValidPlane(format, plane));
1265   const int sample_height = SampleSize(format, plane).height();
1266   return base::bits::AlignUp(height, sample_height) / sample_height;
1267 }
1268
1269 // static
1270 size_t VideoFrame::Columns(size_t plane, VideoPixelFormat format, int width) {
1271   DCHECK(IsValidPlane(format, plane));
1272   const int sample_width = SampleSize(format, plane).width();
1273   return base::bits::AlignUp(width, sample_width) / sample_width;
1274 }
1275
1276 // static
1277 void VideoFrame::HashFrameForTesting(base::MD5Context* context,
1278                                      const VideoFrame& frame) {
1279   DCHECK(context);
1280   for (size_t plane = 0; plane < NumPlanes(frame.format()); ++plane) {
1281     for (int row = 0; row < frame.rows(plane); ++row) {
1282       base::MD5Update(context, base::StringPiece(reinterpret_cast<const char*>(
1283                                                      frame.data(plane) +
1284                                                      frame.stride(plane) * row),
1285                                                  frame.row_bytes(plane)));
1286     }
1287   }
1288 }
1289
1290 void VideoFrame::BackWithSharedMemory(
1291     const base::ReadOnlySharedMemoryRegion* region) {
1292   DCHECK(!shm_region_);
1293   DCHECK(!owned_shm_region_.IsValid());
1294   // Either we should be backing a frame created with WrapExternal*, or we are
1295   // wrapping an existing STORAGE_SHMEM, in which case the storage type has
1296   // already been set to STORAGE_SHMEM.
1297   DCHECK(storage_type_ == STORAGE_UNOWNED_MEMORY ||
1298          storage_type_ == STORAGE_SHMEM);
1299   DCHECK(region && region->IsValid());
1300   storage_type_ = STORAGE_SHMEM;
1301   shm_region_ = region;
1302 }
1303
1304 void VideoFrame::BackWithOwnedSharedMemory(
1305     base::ReadOnlySharedMemoryRegion region,
1306     base::ReadOnlySharedMemoryMapping mapping) {
1307   DCHECK(!shm_region_);
1308   DCHECK(!owned_shm_region_.IsValid());
1309   // We should be backing a frame created with WrapExternal*. We cannot be
1310   // wrapping an existing STORAGE_SHMEM, as the region is unowned in that case.
1311   DCHECK(storage_type_ == STORAGE_UNOWNED_MEMORY);
1312   storage_type_ = STORAGE_SHMEM;
1313   owned_shm_region_ = std::move(region);
1314   shm_region_ = &owned_shm_region_;
1315   owned_shm_mapping_ = std::move(mapping);
1316 }
1317
1318 bool VideoFrame::IsMappable() const {
1319   return IsStorageTypeMappable(storage_type_);
1320 }
1321
1322 bool VideoFrame::HasTextures() const {
1323   return wrapped_frame_ ? wrapped_frame_->HasTextures()
1324                         : !mailbox_holders_[0].mailbox.IsZero();
1325 }
1326
1327 size_t VideoFrame::NumTextures() const {
1328   if (wrapped_frame_)
1329     return wrapped_frame_->NumTextures();
1330
1331   if (!HasTextures())
1332     return 0;
1333
1334   size_t i = 0;
1335   for (; i < NumPlanes(format()); ++i) {
1336     const auto& mailbox = mailbox_holders_[i].mailbox;
1337     if (mailbox.IsZero())
1338       return i;
1339   }
1340   return i;
1341 }
1342
1343 bool VideoFrame::HasGpuMemoryBuffer() const {
1344   return wrapped_frame_ ? wrapped_frame_->HasGpuMemoryBuffer()
1345                         : !!gpu_memory_buffer_;
1346 }
1347
1348 gfx::GpuMemoryBuffer* VideoFrame::GetGpuMemoryBuffer() const {
1349   return wrapped_frame_ ? wrapped_frame_->GetGpuMemoryBuffer()
1350                         : gpu_memory_buffer_.get();
1351 }
1352
1353 bool VideoFrame::IsSameAllocation(VideoPixelFormat format,
1354                                   const gfx::Size& coded_size,
1355                                   const gfx::Rect& visible_rect,
1356                                   const gfx::Size& natural_size) const {
1357   // CreateFrameInternal() changes coded_size to new_coded_size. Match that
1358   // behavior here.
1359   const gfx::Size new_coded_size = DetermineAlignedSize(format, coded_size);
1360   return this->format() == format && this->coded_size() == new_coded_size &&
1361          visible_rect_ == visible_rect && natural_size_ == natural_size;
1362 }
1363
1364 gfx::ColorSpace VideoFrame::ColorSpace() const {
1365   return color_space_;
1366 }
1367
1368 bool VideoFrame::RequiresExternalSampler() const {
1369   const bool is_multiplanar_pixel_format = format() == PIXEL_FORMAT_NV12 ||
1370                                            format() == PIXEL_FORMAT_YV12 ||
1371                                            format() == PIXEL_FORMAT_P016LE;
1372
1373   // With SharedImageFormats NumTextures() is always 1. Use
1374   // SharedImageFormatType to check for NumTextures for legacy formats and
1375   // kSharedImageFormatExternalSampler for SharedImageFormats. Note that
1376   // kSharedImageFormatExternalSampler is set only for multiplanar formats.
1377   const bool requires_external_sampler =
1378       shared_image_format_type() ==
1379           SharedImageFormatType::kSharedImageFormatExternalSampler ||
1380       (is_multiplanar_pixel_format &&
1381        (NumTextures() == 1 &&
1382         shared_image_format_type() == SharedImageFormatType::kLegacy));
1383
1384   // The texture target can be 0 for Fuchsia.
1385   DCHECK(!requires_external_sampler ||
1386          (is_multiplanar_pixel_format &&
1387           (mailbox_holder(0).texture_target == GL_TEXTURE_EXTERNAL_OES ||
1388            mailbox_holder(0).texture_target == 0u)));
1389   return requires_external_sampler;
1390 }
1391
1392 int VideoFrame::row_bytes(size_t plane) const {
1393   return RowBytes(plane, format(), coded_size().width());
1394 }
1395
1396 int VideoFrame::rows(size_t plane) const {
1397   return Rows(plane, format(), coded_size().height());
1398 }
1399
1400 int VideoFrame::columns(size_t plane) const {
1401   return Columns(plane, format(), coded_size().width());
1402 }
1403
1404 template <typename T>
1405 T VideoFrame::GetVisibleDataInternal(T data, size_t plane) const {
1406   DCHECK(IsValidPlane(format(), plane));
1407   DCHECK(IsMappable());
1408   if (UNLIKELY(!data)) {
1409     return nullptr;
1410   }
1411
1412   // Calculate an offset that is properly aligned for all planes.
1413   const gfx::Size alignment = CommonAlignment(format());
1414   const gfx::Point offset(
1415       base::bits::AlignDown(visible_rect_.x(), alignment.width()),
1416       base::bits::AlignDown(visible_rect_.y(), alignment.height()));
1417
1418   const gfx::Size subsample = SampleSize(format(), plane);
1419   DCHECK(offset.x() % subsample.width() == 0);
1420   DCHECK(offset.y() % subsample.height() == 0);
1421
1422 #if defined(TIZEN_TBM_SUPPORT)
1423   const VideoPixelFormat fmt = format();
1424   if (PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER == fmt) {
1425     if (!bufmgr_)
1426       bufmgr_ = tbm_bufmgr_init(-1);
1427     {
1428       base::AutoLock autolock(tbm_map_lock_);
1429       if (!vp_[plane]) {
1430         bo_[plane] = tbm_bo_import(bufmgr_, buffer_handle_.key[plane]);
1431         bo_handle_[plane] =
1432             tbm_bo_map(bo_[plane], TBM_DEVICE_CPU, TBM_OPTION_READ);
1433
1434         vp_[plane] =
1435             (uint8_t*)bo_handle_[plane].ptr +
1436             stride(plane) * (offset.y() / subsample.height()) +  // Row offset.
1437             BytesPerElement(format(), plane) *  // Column offset.
1438                 (offset.x() / subsample.width());
1439       }
1440     }
1441     return vp_[plane];
1442   }
1443 #endif
1444   return data +
1445          stride(plane) * (offset.y() / subsample.height()) +  // Row offset.
1446          BytesPerElement(format(), plane) *                   // Column offset.
1447              (offset.x() / subsample.width());
1448 }
1449
1450 const uint8_t* VideoFrame::visible_data(size_t plane) const {
1451   return GetVisibleDataInternal(data(plane), plane);
1452 }
1453
1454 uint8_t* VideoFrame::GetWritableVisibleData(size_t plane) {
1455   // TODO(crbug.com/1435549): Also CHECK that the storage type isn't
1456   // STORAGE_UNOWNED_MEMORY once non-compliant usages are fixed.
1457   CHECK_NE(storage_type_, STORAGE_SHMEM);
1458   return GetVisibleDataInternal(writable_data(plane), plane);
1459 }
1460
1461 const gpu::MailboxHolder& VideoFrame::mailbox_holder(
1462     size_t texture_index) const {
1463 #if defined(TIZEN_TBM_SUPPORT)
1464   DCHECK(IsTBMBackend() || HasTextures());
1465 #else
1466   DCHECK(HasTextures());
1467 #endif
1468   DCHECK(IsValidPlane(format(), texture_index));
1469   return wrapped_frame_ ? wrapped_frame_->mailbox_holder(texture_index)
1470                         : mailbox_holders_[texture_index];
1471 }
1472
1473 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
1474 const std::vector<base::ScopedFD>& VideoFrame::DmabufFds() const {
1475   DCHECK_EQ(storage_type_, STORAGE_DMABUFS);
1476
1477   return dmabuf_fds_->fds();
1478 }
1479
1480 bool VideoFrame::HasDmaBufs() const {
1481   return dmabuf_fds_->size() > 0;
1482 }
1483
1484 bool VideoFrame::IsSameDmaBufsAs(const VideoFrame& frame) const {
1485   return storage_type_ == STORAGE_DMABUFS &&
1486          frame.storage_type_ == STORAGE_DMABUFS &&
1487          &DmabufFds() == &frame.DmabufFds();
1488 }
1489 #endif
1490
1491 #if BUILDFLAG(IS_APPLE)
1492 CVPixelBufferRef VideoFrame::CvPixelBuffer() const {
1493   return cv_pixel_buffer_.get();
1494 }
1495 #endif
1496
1497 void VideoFrame::SetReleaseMailboxCB(ReleaseMailboxCB release_mailbox_cb) {
1498   DCHECK(release_mailbox_cb);
1499   DCHECK(!mailbox_holders_and_gmb_release_cb_);
1500   // We don't relay SetReleaseMailboxCB to |wrapped_frame_| because the method
1501   // is not thread safe.  This method should only be called by the owner of
1502   // |wrapped_frame_| directly.
1503   DCHECK(!wrapped_frame_);
1504   mailbox_holders_and_gmb_release_cb_ =
1505       WrapReleaseMailboxCB(std::move(release_mailbox_cb));
1506 }
1507
1508 void VideoFrame::SetReleaseMailboxAndGpuMemoryBufferCB(
1509     ReleaseMailboxAndGpuMemoryBufferCB release_mailbox_cb) {
1510   // See remarks in SetReleaseMailboxCB.
1511   DCHECK(release_mailbox_cb);
1512   DCHECK(!mailbox_holders_and_gmb_release_cb_);
1513   DCHECK(!wrapped_frame_);
1514   mailbox_holders_and_gmb_release_cb_ = std::move(release_mailbox_cb);
1515 }
1516
1517 bool VideoFrame::HasReleaseMailboxCB() const {
1518   return wrapped_frame_ ? wrapped_frame_->HasReleaseMailboxCB()
1519                         : !!mailbox_holders_and_gmb_release_cb_;
1520 }
1521
1522 void VideoFrame::AddDestructionObserver(base::OnceClosure callback) {
1523   DCHECK(!callback.is_null());
1524   base::AutoLock lock(done_callbacks_lock_);
1525   done_callbacks_.push_back(std::move(callback));
1526 }
1527
1528 gpu::SyncToken VideoFrame::UpdateReleaseSyncToken(SyncTokenClient* client) {
1529 #if defined(TIZEN_TBM_SUPPORT)
1530   DCHECK(IsTBMBackend() || HasTextures());
1531 #else
1532   DCHECK(HasTextures());
1533 #endif
1534   if (wrapped_frame_) {
1535     return wrapped_frame_->UpdateReleaseSyncToken(client);
1536   }
1537   base::AutoLock locker(release_sync_token_lock_);
1538   // Must wait on the previous sync point before inserting a new sync point so
1539   // that |mailbox_holders_and_gmb_release_cb_| guarantees the previous sync
1540   // point occurred when it waits on |release_sync_token_|.
1541   if (release_sync_token_.HasData())
1542     client->WaitSyncToken(release_sync_token_);
1543   client->GenerateSyncToken(&release_sync_token_);
1544   return release_sync_token_;
1545 }
1546
1547 gpu::SyncToken VideoFrame::UpdateMailboxHolderSyncToken(
1548     size_t plane,
1549     SyncTokenClient* client) {
1550   DCHECK(HasOneRef());
1551   DCHECK(HasTextures());
1552   DCHECK(!wrapped_frame_);
1553   DCHECK_LT(plane, kMaxPlanes);
1554
1555   // No lock is required due to the HasOneRef() check.
1556   auto& token = mailbox_holders_[plane].sync_token;
1557   if (token.HasData())
1558     client->WaitSyncToken(token);
1559   client->GenerateSyncToken(&token);
1560   return token;
1561 }
1562
1563 std::string VideoFrame::AsHumanReadableString() const {
1564   if (metadata().end_of_stream)
1565     return "end of stream";
1566
1567   std::ostringstream s;
1568   s << ConfigToString(format(), storage_type_, coded_size(), visible_rect_,
1569                       natural_size_)
1570     << " timestamp:" << timestamp_.InMicroseconds();
1571   if (HasTextures())
1572     s << " textures: " << NumTextures();
1573   return s.str();
1574 }
1575
1576 size_t VideoFrame::BitDepth() const {
1577   return media::BitDepth(format());
1578 }
1579
1580 VideoFrame::VideoFrame(const VideoFrameLayout& layout,
1581                        StorageType storage_type,
1582                        const gfx::Rect& visible_rect,
1583                        const gfx::Size& natural_size,
1584                        base::TimeDelta timestamp,
1585                        FrameControlType frame_control_type)
1586     : layout_(layout),
1587       storage_type_(storage_type),
1588       visible_rect_(Intersection(visible_rect, gfx::Rect(layout.coded_size()))),
1589       natural_size_(natural_size),
1590 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
1591       dmabuf_fds_(base::MakeRefCounted<DmabufHolder>()),
1592 #endif
1593 #if defined(TIZEN_TBM_SUPPORT)
1594       texture_id_(0),
1595       gl_(nullptr),
1596       image_id_(0),
1597 #endif
1598       timestamp_(timestamp),
1599       unique_id_(GetNextID()) {
1600   DCHECK(IsValidConfigInternal(format(), frame_control_type, coded_size(),
1601                                visible_rect_, natural_size_));
1602   DCHECK(visible_rect_ == visible_rect)
1603       << "visible_rect " << visible_rect.ToString() << " exceeds coded_size "
1604       << coded_size().ToString();
1605   memset(&mailbox_holders_, 0, sizeof(mailbox_holders_));
1606   memset(&data_, 0, sizeof(data_));
1607 #if defined(TIZEN_TBM_SUPPORT)
1608   memset(bo_handle_, 0, sizeof(tbm_bo_handle) * TBM_BO_NUM_MAX);
1609 #endif
1610 }
1611
1612 VideoFrame::~VideoFrame() {
1613   if (mailbox_holders_and_gmb_release_cb_) {
1614     gpu::SyncToken release_sync_token;
1615     {
1616       // To ensure that changes to |release_sync_token_| are visible on this
1617       // thread (imply a memory barrier).
1618       base::AutoLock locker(release_sync_token_lock_);
1619       release_sync_token = release_sync_token_;
1620     }
1621     std::move(mailbox_holders_and_gmb_release_cb_)
1622         .Run(release_sync_token, std::move(gpu_memory_buffer_));
1623   }
1624
1625   std::vector<base::OnceClosure> done_callbacks;
1626   {
1627     base::AutoLock lock(done_callbacks_lock_);
1628     done_callbacks = std::move(done_callbacks_);
1629   }
1630   for (auto& callback : done_callbacks)
1631     std::move(callback).Run();
1632
1633 #if defined(TIZEN_TBM_SUPPORT)
1634   for (int i = 0; i < TBM_BO_NUM_MAX; i++) {
1635     if (bo_handle_[i].ptr) {
1636       if (!tbm_bo_unmap(bo_[i]))
1637         LOG(WARNING) << "unmap bo failed!";
1638       tbm_bo_unref(bo_[i]);
1639       bo_handle_[i].ptr = nullptr;
1640     }
1641   }
1642 #endif
1643 }
1644
1645 // static
1646 std::string VideoFrame::ConfigToString(const VideoPixelFormat format,
1647                                        const StorageType storage_type,
1648                                        const gfx::Size& coded_size,
1649                                        const gfx::Rect& visible_rect,
1650                                        const gfx::Size& natural_size) {
1651   return base::StringPrintf(
1652       "format:%s storage_type:%s coded_size:%s visible_rect:%s natural_size:%s",
1653       VideoPixelFormatToString(format).c_str(),
1654       StorageTypeToString(storage_type).c_str(), coded_size.ToString().c_str(),
1655       visible_rect.ToString().c_str(), natural_size.ToString().c_str());
1656 }
1657
1658 // static
1659 gfx::Size VideoFrame::DetermineAlignedSize(VideoPixelFormat format,
1660                                            const gfx::Size& dimensions) {
1661   const gfx::Size alignment = CommonAlignment(format);
1662   const gfx::Size adjusted =
1663       gfx::Size(base::bits::AlignUp(dimensions.width(), alignment.width()),
1664                 base::bits::AlignUp(dimensions.height(), alignment.height()));
1665   DCHECK((adjusted.width() % alignment.width() == 0) &&
1666          (adjusted.height() % alignment.height() == 0));
1667   return adjusted;
1668 }
1669
1670 // static
1671 bool VideoFrame::IsValidSize(const gfx::Size& coded_size,
1672                              const gfx::Rect& visible_rect,
1673                              const gfx::Size& natural_size) {
1674   return IsValidCodedSize(coded_size) && IsValidCodedSize(natural_size) &&
1675          !(visible_rect.x() < 0 || visible_rect.y() < 0 ||
1676            visible_rect.right() > coded_size.width() ||
1677            visible_rect.bottom() > coded_size.height());
1678 }
1679
1680 // static
1681 bool VideoFrame::IsValidCodedSize(const gfx::Size& size) {
1682   const int size_area = size.GetCheckedArea().ValueOrDefault(INT_MAX);
1683   static_assert(limits::kMaxCanvas < INT_MAX, "");
1684   return size_area <= limits::kMaxCanvas &&
1685          size.width() <= limits::kMaxDimension &&
1686          size.height() <= limits::kMaxDimension;
1687 }
1688
1689 // static
1690 bool VideoFrame::IsValidConfigInternal(VideoPixelFormat format,
1691                                        FrameControlType frame_control_type,
1692                                        const gfx::Size& coded_size,
1693                                        const gfx::Rect& visible_rect,
1694                                        const gfx::Size& natural_size) {
1695   // Check maximum limits for all formats.
1696   if (!IsValidSize(coded_size, visible_rect, natural_size)) {
1697     return false;
1698   }
1699
1700   switch (frame_control_type) {
1701     case FrameControlType::kNone:
1702       // Check that software-allocated buffer formats are not empty.
1703       return !coded_size.IsEmpty() && !visible_rect.IsEmpty() &&
1704              !natural_size.IsEmpty();
1705     case FrameControlType::kEos:
1706       DCHECK_EQ(format, PIXEL_FORMAT_UNKNOWN);
1707       return coded_size.IsEmpty() && visible_rect.IsEmpty() &&
1708              natural_size.IsEmpty();
1709     case FrameControlType::kVideoHole:
1710       DCHECK_EQ(format, PIXEL_FORMAT_UNKNOWN);
1711       return !coded_size.IsEmpty() && !visible_rect.IsEmpty() &&
1712              !natural_size.IsEmpty();
1713   }
1714 }
1715
1716 // static
1717 absl::optional<VideoFrameLayout>
1718 VideoFrame::CreateFullySpecifiedLayoutWithStrides(VideoPixelFormat format,
1719                                                   const gfx::Size& coded_size) {
1720   const gfx::Size new_coded_size = DetermineAlignedSize(format, coded_size);
1721   auto layout = VideoFrameLayout::CreateWithStrides(
1722       format, new_coded_size, ComputeStrides(format, new_coded_size));
1723   if (!layout) {
1724     return {};
1725   }
1726   // This whole method would be in `VideoFrameLayout::CreateWithStrides()`
1727   // instead of here, except that we know how to calculate the plane sizes.
1728   // This should be refactored.
1729   auto plane_sizes = CalculatePlaneSize(*layout);
1730   // Fill in the offsets as well, since WrapExternalDataWithLayout() uses them
1731   // to figure out where the data is.
1732   size_t offset = 0u;
1733   const size_t num_planes = plane_sizes.size();
1734   std::vector<ColorPlaneLayout> new_planes;
1735   new_planes.reserve(num_planes);
1736   for (size_t plane = 0; plane < plane_sizes.size(); plane++) {
1737     new_planes.emplace_back(layout->planes()[plane].stride, offset,
1738                             plane_sizes[plane]);
1739     offset += plane_sizes[plane];
1740   }
1741   return VideoFrameLayout::CreateWithPlanes(format, new_coded_size,
1742                                             std::move(new_planes));
1743 }
1744
1745 // static
1746 scoped_refptr<VideoFrame> VideoFrame::CreateFrameInternal(
1747     VideoPixelFormat format,
1748     const gfx::Size& coded_size,
1749     const gfx::Rect& visible_rect,
1750     const gfx::Size& natural_size,
1751     base::TimeDelta timestamp,
1752     bool zero_initialize_memory) {
1753   // Since we're creating a new frame (and allocating memory for it
1754   // ourselves), we can pad the requested |coded_size| if necessary if the
1755   // request does not line up on sample boundaries. See discussion at
1756   // http://crrev.com/1240833003
1757   const gfx::Size new_coded_size = DetermineAlignedSize(format, coded_size);
1758   auto layout = VideoFrameLayout::CreateWithStrides(
1759       format, new_coded_size, ComputeStrides(format, new_coded_size));
1760   if (!layout) {
1761     DLOG(ERROR) << "Invalid layout.";
1762     return nullptr;
1763   }
1764
1765   return CreateFrameWithLayout(*layout, visible_rect, natural_size, timestamp,
1766                                zero_initialize_memory);
1767 }
1768
1769 scoped_refptr<VideoFrame> VideoFrame::CreateFrameWithLayout(
1770     const VideoFrameLayout& layout,
1771     const gfx::Rect& visible_rect,
1772     const gfx::Size& natural_size,
1773     base::TimeDelta timestamp,
1774     bool zero_initialize_memory) {
1775   const StorageType storage = STORAGE_OWNED_MEMORY;
1776   if (!IsValidConfig(layout.format(), storage, layout.coded_size(),
1777                      visible_rect, natural_size)) {
1778     DLOG(ERROR) << __func__ << " Invalid config."
1779                 << ConfigToString(layout.format(), storage, layout.coded_size(),
1780                                   visible_rect, natural_size);
1781     return nullptr;
1782   }
1783
1784   scoped_refptr<VideoFrame> frame(new VideoFrame(
1785       std::move(layout), storage, visible_rect, natural_size, timestamp));
1786   return frame->AllocateMemory(zero_initialize_memory) ? frame : nullptr;
1787 }
1788
1789 // static
1790 gfx::Size VideoFrame::CommonAlignment(VideoPixelFormat format) {
1791   int max_sample_width = 0;
1792   int max_sample_height = 0;
1793   for (size_t plane = 0; plane < NumPlanes(format); ++plane) {
1794     const gfx::Size sample_size = SampleSize(format, plane);
1795     max_sample_width = std::max(max_sample_width, sample_size.width());
1796     max_sample_height = std::max(max_sample_height, sample_size.height());
1797   }
1798   return gfx::Size(max_sample_width, max_sample_height);
1799 }
1800
1801 bool VideoFrame::AllocateMemory(bool zero_initialize_memory) {
1802   DCHECK_EQ(storage_type_, STORAGE_OWNED_MEMORY);
1803   static_assert(0 == kYPlane, "y plane data must be index 0");
1804
1805   std::vector<size_t> plane_size = CalculatePlaneSize();
1806   const size_t buffer_size =
1807       std::accumulate(plane_size.begin(), plane_size.end(), 0u);
1808   const size_t allocation_size =
1809       buffer_size + (layout_.buffer_addr_align() - 1);
1810
1811   uint8_t* data = nullptr;
1812   if (zero_initialize_memory) {
1813     if (!base::UncheckedCalloc(1, allocation_size,
1814                                reinterpret_cast<void**>(&data)) ||
1815         !data) {
1816       return false;
1817     }
1818   } else {
1819     if (!base::UncheckedMalloc(allocation_size,
1820                                reinterpret_cast<void**>(&data)) ||
1821         !data) {
1822       return false;
1823     }
1824   }
1825   private_data_.reset(data);
1826
1827   data = base::bits::AlignUp(data, layout_.buffer_addr_align());
1828   DCHECK_LE(data + buffer_size, private_data_.get() + allocation_size);
1829
1830   // Note that if layout.buffer_sizes is specified, color planes' layout is
1831   // the same as buffers'. See CalculatePlaneSize() for detail.
1832   for (size_t plane = 0, offset = 0; plane < NumPlanes(format()); ++plane) {
1833     data_[plane] = data + offset;
1834     offset += plane_size[plane];
1835   }
1836
1837   return true;
1838 }
1839
1840 bool VideoFrame::IsValidSharedMemoryFrame() const {
1841   if (storage_type_ == STORAGE_SHMEM)
1842     return shm_region_ && shm_region_->IsValid();
1843   return false;
1844 }
1845
1846 // static
1847 std::vector<size_t> VideoFrame::CalculatePlaneSize(
1848     const VideoFrameLayout& layout) {
1849   // We have two cases for plane size mapping:
1850   // 1) If plane size is specified: use planes' size.
1851   // 2) VideoFrameLayout::size is unassigned: use legacy calculation formula.
1852
1853   const auto format = layout.format();
1854   const size_t num_planes = NumPlanes(format);
1855   const auto& planes = layout.planes();
1856   std::vector<size_t> plane_size(num_planes);
1857   bool plane_size_assigned = true;
1858   DCHECK_EQ(planes.size(), num_planes);
1859   for (size_t i = 0; i < num_planes; ++i) {
1860     plane_size[i] = planes[i].size;
1861     plane_size_assigned &= plane_size[i] != 0;
1862   }
1863
1864   if (plane_size_assigned)
1865     return plane_size;
1866
1867   // Reset plane size.
1868   std::fill(plane_size.begin(), plane_size.end(), 0u);
1869   for (size_t plane = 0; plane < num_planes; ++plane) {
1870     // These values were chosen to mirror ffmpeg's get_video_buffer().
1871     // TODO(dalecurtis): This should be configurable; eventually ffmpeg wants
1872     // us to use av_cpu_max_align(), but... for now, they just hard-code 32.
1873     const size_t height = base::bits::AlignUp(
1874         static_cast<size_t>(Rows(plane, format, layout.coded_size().height())),
1875         kFrameAddressAlignment);
1876     const size_t width = std::abs(layout.planes()[plane].stride);
1877     plane_size[plane] = width * height;
1878   }
1879
1880   if (num_planes > 1) {
1881     // The extra line of UV being allocated is because h264 chroma MC
1882     // overreads by one line in some cases, see libavcodec/utils.c:
1883     // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
1884     // put_h264_chroma_mc4_ssse3().
1885     DCHECK(IsValidPlane(format, kUPlane));
1886     DCHECK(kUPlane < num_planes);
1887     plane_size.back() +=
1888         std::abs(layout.planes()[kUPlane].stride) + kFrameSizePadding;
1889   }
1890   return plane_size;
1891 }
1892
1893 #if defined(TIZEN_TBM_SUPPORT)
1894 void ReleaseTbmTexture(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
1895                        gpu::gles2::GLES2Interface* gl,
1896                        uint32_t texture,
1897                        uint32_t image,
1898                        scoped_refptr<viz::ContextProvider> context_provider,
1899                        const gpu::SyncToken& release_sync_point) {
1900 #if defined(USE_TTRACE)
1901   TTRACE(TTRACE_TAG_WEB, "ReleaseTbmTexture");
1902 #endif
1903   DCHECK(task_runner->BelongsToCurrentThread());
1904   const uint32_t target = GL_TEXTURE_EXTERNAL_OES;
1905   LOG(INFO) << "VideoFrame > --ReleaseTbmTexture >"
1906             << ", img:" << image << ", txt:" << texture;
1907   if (release_sync_point.HasData())
1908     gl->WaitSyncTokenCHROMIUM(release_sync_point.GetConstData());
1909   if (image) {
1910     gl->BindTexture(target, texture);
1911     gl->ReleaseTexImage2DCHROMIUM(target, image);
1912     gl->DestroyTizenImageCHROMIUM(image);
1913   }
1914   gl->DeleteTextures(1, &texture);
1915 }
1916
1917 void VideoFrame::ReleaseTbm() {
1918   if (mailbox_holders_and_gmb_release_cb_) {
1919     gpu::SyncToken release_sync_token;
1920     {
1921       // To ensure that changes to |release_sync_token_| are visible on this
1922       // thread (imply a memory barrier).
1923       base::AutoLock locker(release_sync_token_lock_);
1924       release_sync_token = release_sync_token_;
1925     }
1926     std::move(mailbox_holders_and_gmb_release_cb_)
1927         .Run(release_sync_token, std::move(gpu_memory_buffer_));
1928   }
1929 }
1930
1931 unsigned VideoFrame::CreateTbmTextureIfNeeded(gpu::gles2::GLES2Interface* gl) {
1932 #if defined(USE_TTRACE)
1933   TTRACE(TTRACE_TAG_WEB, "VideoFrameCompositor::CreateTbmTextureIfNeeded");
1934 #endif
1935   base::AutoLock autolock(tbm_lock_);
1936   if (!gl || texture_id_)
1937     return (gl_ == gl) ? texture_id_ : 0;
1938
1939   gl_ = gl;
1940   unsigned image = gl->CreateTizenImageCHROMIUM(
1941       buffer_handle_, visible_rect().width(), visible_rect().height(), GL_RGBA);
1942   gl->GenTextures(1, &texture_id_);
1943   gl->BindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
1944   gl->TexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1945   gl->TexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1946   gl->TexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S,
1947                     GL_CLAMP_TO_EDGE);
1948   gl->TexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T,
1949                     GL_CLAMP_TO_EDGE);
1950   gl->BindTexImage2DCHROMIUM(GL_TEXTURE_EXTERNAL_OES, image);
1951
1952   LOG(INFO) << "CreateTbmTextureIfNeeded img:" << image
1953             << ", txt:" << texture_id_;
1954
1955   gpu::Mailbox mailbox;
1956   gl->ProduceTextureDirectCHROMIUM(texture_id_, mailbox.name);
1957   gl->ShallowFlushCHROMIUM();
1958   gpu::SyncToken sync_token;
1959   gl->GenSyncTokenCHROMIUM(sync_token.GetData());
1960   mailbox_holders_[kARGBPlane] =
1961       gpu::MailboxHolder(mailbox, sync_token, GL_TEXTURE_EXTERNAL_OES);
1962
1963   SetReleaseMailboxCB(base::BindOnce(ReleaseTbmTexture,
1964                                      base::ThreadTaskRunnerHandle::Get(), gl,
1965                                      texture_id_, image, context_provider_));
1966   return texture_id_;
1967 }
1968 #endif
1969
1970 std::vector<size_t> VideoFrame::CalculatePlaneSize() const {
1971   return CalculatePlaneSize(layout_);
1972 }
1973
1974 }  // namespace media