File: dmabuf_utils.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (136 lines) | stat: -rw-r--r-- 5,125 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/chromeos_camera/dmabuf_utils.h"

#include <unistd.h>

#include <utility>

#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/time/time.h"
#include "media/base/color_plane_layout.h"
#include "media/base/video_frame.h"
#include "media/base/video_frame_layout.h"
#include "media/gpu/buffer_validation.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "ui/gfx/geometry/rect.h"

namespace chromeos_camera {

bool VerifyMjpegBufferHandle(const gfx::GpuMemoryBufferHandle& gmb_handle) {
  if (gmb_handle.native_pixmap_handle().planes[0].offset != 0u) {
    DLOG(ERROR) << "Invalid DMA buf plane offset";
    return false;
  }
  // For MJPEG, we expect the byte size to be at least as large as the stride
  // (see b/142105578).
  if (base::strict_cast<uint64_t>(
          gmb_handle.native_pixmap_handle().planes[0].stride) >
      gmb_handle.native_pixmap_handle().planes[0].size) {
    DLOG(ERROR) << "Invalid DMA buf plane stride or size";
    return false;
  }
  const auto dma_buf_fd = gmb_handle.native_pixmap_handle().planes[0].fd.get();
  const off_t data_size = lseek(dma_buf_fd, /*offset=*/0, SEEK_END);
  if (data_size == static_cast<off_t>(-1)) {
    PLOG(ERROR) << "Failed to get the size of the dma-buf";
    return false;
  }
  if (lseek(dma_buf_fd, /*offset=*/0, SEEK_SET) == static_cast<off_t>(-1)) {
    PLOG(ERROR) << "Failed to reset the file offset of the dma-buf";
    return false;
  }
  if (!base::IsValueInRangeForNumericType<uint64_t>(data_size) ||
      base::checked_cast<uint64_t>(data_size) <
          gmb_handle.native_pixmap_handle().planes[0].size) {
    DLOG(ERROR) << "Invalid DMA buf plane size";
    return false;
  }
  return true;
}

scoped_refptr<media::VideoFrame> ConstructVideoFrame(
    std::vector<mojom::DmaBufPlanePtr> dma_buf_planes,
    media::VideoPixelFormat pixel_format,
    const gfx::Size& coded_size,
    uint64_t modifier) {
  const size_t num_planes = media::VideoFrame::NumPlanes(pixel_format);
  if (num_planes != dma_buf_planes.size()) {
    DLOG(ERROR) << "The number of DMA buf planes does not match the format";
    return nullptr;
  }
  if (coded_size.IsEmpty()) {
    DLOG(ERROR) << "Invalid coded size: " << coded_size.width() << ", "
                << coded_size.height();
    return nullptr;
  }
  const gfx::Rect visible_rect(coded_size);

  gfx::NativePixmapHandle native_pixmap_handle;
  native_pixmap_handle.planes.resize(num_planes);
  native_pixmap_handle.modifier = modifier;
  for (size_t i = 0; i < num_planes; ++i) {
    mojo::PlatformHandle handle =
        mojo::UnwrapPlatformHandle(std::move(dma_buf_planes[i]->fd_handle));
    if (!handle.is_valid()) {
      DLOG(ERROR) << "Invalid DMA buf file descriptor";
      return nullptr;
    }
    if (dma_buf_planes[i]->stride <= 0) {
      DLOG(ERROR) << "Invalid DMA buf stride";
      return nullptr;
    }
    native_pixmap_handle.planes[i].stride =
        base::checked_cast<uint32_t>(dma_buf_planes[i]->stride);
    native_pixmap_handle.planes[i].offset =
        base::strict_cast<uint64_t>(dma_buf_planes[i]->offset);
    native_pixmap_handle.planes[i].size =
        base::strict_cast<uint64_t>(dma_buf_planes[i]->size);
    native_pixmap_handle.planes[i].fd = handle.TakeFD();
  }
  // TODO(dcheng): It's a bit silly to move this into a GpuMemoryBufferHandle
  // just so it can be verified, only to extract it again after this.
  gfx::GpuMemoryBufferHandle gmb_handle(std::move(native_pixmap_handle));
  if (pixel_format == media::PIXEL_FORMAT_MJPEG) {
    if (!VerifyMjpegBufferHandle(gmb_handle)) {
      return nullptr;
    }
  } else {
    if (!media::VerifyGpuMemoryBufferHandle(pixel_format, coded_size,
                                            gmb_handle)) {
      return nullptr;
    }
  }

  native_pixmap_handle = std::move(gmb_handle).native_pixmap_handle();
  std::vector<base::ScopedFD> dma_buf_fds(num_planes);
  std::vector<media::ColorPlaneLayout> planes(num_planes);
  for (size_t i = 0; i < num_planes; ++i) {
    dma_buf_fds[i] = std::move(native_pixmap_handle.planes[i].fd);
    planes[i] = media::ColorPlaneLayout(
        dma_buf_planes[i]->stride,
        base::strict_cast<size_t>(dma_buf_planes[i]->offset),
        base::strict_cast<size_t>(dma_buf_planes[i]->size));
  }
  const std::optional<media::VideoFrameLayout> layout =
      media::VideoFrameLayout::CreateWithPlanes(
          pixel_format, coded_size, std::move(planes),
          media::VideoFrameLayout::kBufferAddressAlignment, modifier);
  if (!layout) {
    DLOG(ERROR) << "Failed to create video frame layout";
    return nullptr;
  }

  return media::VideoFrame::WrapExternalDmabufs(
      *layout,                 // layout
      visible_rect,            // visible_rect
      coded_size,              // natural_size
      std::move(dma_buf_fds),  // dmabuf_fds
      base::TimeDelta());      // timestamp
}

}  // namespace chromeos_camera