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
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286

media / gpu / v4l2 / v4l2_device.h [blame]

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This file defines the V4L2Device interface which is used by the
// V4L2DecodeAccelerator class to delegate/pass the device specific
// handling of any of the functionalities.

#ifndef MEDIA_GPU_V4L2_V4L2_DEVICE_H_
#define MEDIA_GPU_V4L2_V4L2_DEVICE_H_

#include <linux/videodev2.h>
#include <stddef.h>
#include <stdint.h>

#include <optional>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/containers/small_map.h"
#include "base/files/scoped_file.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "build/build_config.h"
#include "media/base/video_codecs.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
#include "media/base/video_frame_layout.h"
#include "media/gpu/chromeos/fourcc.h"
#include "media/gpu/media_gpu_export.h"
#include "media/gpu/v4l2/v4l2_device_poller.h"
#include "media/gpu/v4l2/v4l2_queue.h"
#include "media/gpu/v4l2/v4l2_utils.h"
#include "media/video/video_decode_accelerator.h"
#include "media/video/video_encode_accelerator.h"
#include "ui/gfx/geometry/size.h"

// This has not been accepted upstream.
#ifndef V4L2_PIX_FMT_AV1
#define V4L2_PIX_FMT_AV1 v4l2_fourcc('A', 'V', '0', '1') /* AV1 */
#endif
// This has been upstreamed and backported for ChromeOS, but has not been
// picked up by the Chromium sysroots.
#ifndef V4L2_PIX_FMT_AV1_FRAME
#define V4L2_PIX_FMT_AV1_FRAME                        \
  v4l2_fourcc('A', 'V', '1', 'F') /* AV1 parsed frame \
                                   */
#endif

#ifndef V4L2_PIX_FMT_MT2T
#define V4L2_PIX_FMT_MT2T v4l2_fourcc('M', 'T', '2', 'T')
#endif
#ifndef V4L2_PIX_FMT_QC10C
#define V4L2_PIX_FMT_QC10C \
  v4l2_fourcc('Q', '1', '0', 'C') /* Qualcomm 10-bit compressed */
#endif

#define V4L2_PIX_FMT_INVALID v4l2_fourcc('0', '0', '0', '0')

namespace media {

class V4L2Queue;
class V4L2RequestRef;
class V4L2RequestsQueue;

struct V4L2ExtCtrl;

class MEDIA_GPU_EXPORT V4L2Device
    : public base::RefCountedThreadSafe<V4L2Device> {
 public:
  // Utility format conversion functions
  // Calculates the largest plane's allocation size requested by a V4L2 device.
  static gfx::Size AllocatedSizeFromV4L2Format(
      const struct v4l2_format& format);

  // Convert required H264 profile and level to V4L2 enums.
  static int32_t VideoCodecProfileToV4L2H264Profile(VideoCodecProfile profile);
  static int32_t H264LevelIdcToV4L2H264Level(uint8_t level_idc);

  enum class Type {
    kDecoder,
    kEncoder,
    kImageProcessor,
    kJpegDecoder,
    kJpegEncoder,
  };

  V4L2Device();

  // Open a V4L2 device of |type| for use with |v4l2_pixfmt|.
  // Return true on success.
  // The device will be closed in the destructor.
  [[nodiscard]] bool Open(Type type, uint32_t v4l2_pixfmt);

  // Returns whether Open() has been succeeded.
  bool IsValid();

  // Returns the driver name.
  std::string GetDriverName();

  // Returns the V4L2Queue corresponding to the requested |type|, or nullptr
  // if the requested queue type is not supported.
  scoped_refptr<V4L2Queue> GetQueue(enum v4l2_buf_type type);

  // Parameters and return value are the same as for the standard ioctl() system
  // call.
  [[nodiscard]] int Ioctl(int request, void* arg);

  // This method sleeps until either:
  // - SetDevicePollInterrupt() is called (on another thread),
  // - |poll_device| is true, and there is new data to be read from the device,
  //   or an event from the device has arrived; in the latter case
  //   |*event_pending| will be set to true.
  // Returns false on error, true otherwise.
  // This method should be called from a separate thread.
  bool Poll(bool poll_device, bool* event_pending);

  // These methods are used to interrupt the thread sleeping on Poll() and force
  // it to return regardless of device state, which is usually when the client
  // is no longer interested in what happens with the device (on cleanup,
  // client state change, etc.). When SetDevicePollInterrupt() is called, Poll()
  // will return immediately, and any subsequent calls to it will also do so
  // until ClearDevicePollInterrupt() is called.
  bool SetDevicePollInterrupt();
  bool ClearDevicePollInterrupt();

  // Wrappers for standard mmap/munmap system calls.
  void* Mmap(void* addr,
             unsigned int len,
             int prot,
             int flags,
             unsigned int offset);
  void Munmap(void* addr, unsigned int len);

  // Return true if the given V4L2 pixfmt can be used in CreateEGLImage()
  // for the current platform.
  bool CanCreateEGLImageFrom(const Fourcc fourcc) const;

  // Returns the preferred V4L2 input formats for |type| or empty if none.
  std::vector<uint32_t> PreferredInputFormat(Type type) const;

  // Get the supported bitrate control modes. This function should be called
  // when V4L2Device opens an encoder driver node.
  VideoEncodeAccelerator::SupportedRateControlMode
  GetSupportedRateControlMode();

  // NOTE: The below methods to query capabilities have a side effect of
  // closing the previously-open device, if any, and should not be called after
  // Open().
  // TODO(b/150431552): fix this.

  // Return V4L2 pixelformats supported by the available image processor
  // devices for |buf_type|.
  std::vector<uint32_t> GetSupportedImageProcessorPixelformats(
      v4l2_buf_type buf_type);

  // Return supported profiles for decoder, including only profiles for given
  // fourcc |pixelformats|.
  VideoDecodeAccelerator::SupportedProfiles GetSupportedDecodeProfiles(
      const std::vector<uint32_t>& pixelformats);

  // Return supported profiles for encoder.
  VideoEncodeAccelerator::SupportedProfiles GetSupportedEncodeProfiles();

  // Return true if image processing is supported, false otherwise.
  bool IsImageProcessingSupported();

  // Return true if JPEG codec is supported, false otherwise.
  bool IsJpegDecodingSupported();
  bool IsJpegEncodingSupported();

  // Start polling on this V4L2Device. |event_callback| will be posted to
  // the caller's sequence if a buffer is ready to be dequeued and/or a V4L2
  // event has been posted. |error_callback| will be posted to the client's
  // sequence if a polling error has occurred.
  [[nodiscard]] bool StartPolling(
      V4L2DevicePoller::EventCallback event_callback,
      base::RepeatingClosure error_callback);
  // Stop polling this V4L2Device if polling was active. No new events will
  // be posted after this method has returned.
  [[nodiscard]] bool StopPolling();
  // Schedule a polling event if polling is enabled. This method is intended
  // to be called from V4L2Queue, clients should not need to call it directly.
  void SchedulePoll();

  // Attempt to dequeue a V4L2 event and return it.
  std::optional<struct v4l2_event> DequeueEvent();

  // Returns requests queue to get free requests. A null pointer is returned if
  // the queue creation failed or if requests are not supported.
  V4L2RequestsQueue* GetRequestsQueue();

  // Check whether the V4L2 control with specified |ctrl_id| is supported.
  bool IsCtrlExposed(uint32_t ctrl_id);
  // Set the specified list of |ctrls| for the specified |ctrl_class|, returns
  // whether the operation succeeded. If |request_ref| is not nullptr, the
  // controls are applied to the request instead of globally for the device.
  bool SetExtCtrls(uint32_t ctrl_class,
                   std::vector<V4L2ExtCtrl> ctrls,
                   V4L2RequestRef* request_ref = nullptr);

  // Get the value of a single control, or std::nullopt of the control is not
  // exposed by the device.
  std::optional<struct v4l2_ext_control> GetCtrl(uint32_t ctrl_id);

  // Set periodic keyframe placement (group of pictures length)
  bool SetGOPLength(uint32_t gop_length);

  void set_secure_allocate_cb(
      AllocateSecureBufferAsCallback secure_allocate_cb) {
    secure_allocate_cb_ = secure_allocate_cb;
  }
  AllocateSecureBufferAsCallback get_secure_allocate_cb() {
    return secure_allocate_cb_;
  }

 private:
  friend class base::RefCountedThreadSafe<V4L2Device>;
  // Vector of video device node paths and corresponding pixelformats supported
  // by each device node.
  using Devices = std::vector<std::pair<std::string, std::vector<uint32_t>>>;

  ~V4L2Device();

  VideoDecodeAccelerator::SupportedProfiles EnumerateSupportedDecodeProfiles(
      const std::vector<uint32_t>& pixelformats);

  VideoEncodeAccelerator::SupportedProfiles EnumerateSupportedEncodeProfiles();

  // Open device node for |path|.
  bool OpenDevicePath(const std::string& path);

  // Close the currently open device.
  void CloseDevice();

  // Enumerate all V4L2 devices on the system for |type| and store the results
  // under devices_by_type_[type].
  void EnumerateDevicesForType(V4L2Device::Type type);

  // Return device information for all devices of |type| available in the
  // system. Enumerates and queries devices on first run and caches the results
  // for subsequent calls.
  const Devices& GetDevicesForType(V4L2Device::Type type);

  // Return device node path for device of |type| supporting |pixfmt|, or
  // an empty string if the given combination is not supported by the system.
  std::string GetDevicePathFor(V4L2Device::Type type, uint32_t pixfmt);

  // Callback that is called upon a queue's destruction, to cleanup its pointer
  // in queues_.
  void OnQueueDestroyed(v4l2_buf_type buf_type);

  // Used if EnablePolling() is called to signal the user that an event
  // happened or a buffer is ready to be dequeued.
  std::unique_ptr<V4L2DevicePoller> device_poller_;

  // Indicates whether the request queue creation has been tried once.
  bool requests_queue_creation_called_ = false;

  // The request queue stores all requests allocated to be used.
  std::unique_ptr<V4L2RequestsQueue> requests_queue_;

  // Stores information for all devices available on the system
  // for each device Type.
  std::map<V4L2Device::Type, Devices> devices_by_type_;

  // The actual device fd.
  base::ScopedFD device_fd_;

  // eventfd fd to signal device poll thread when its poll() should be
  // interrupted.
  base::ScopedFD device_poll_interrupt_fd_;

  // Associates a v4l2_buf_type to its queue.
  base::flat_map<enum v4l2_buf_type, V4L2Queue*> queues_;

  // Callback to use for allocating secure buffers.
  AllocateSecureBufferAsCallback secure_allocate_cb_;

  SEQUENCE_CHECKER(client_sequence_checker_);
};

}  //  namespace media

#endif  // MEDIA_GPU_V4L2_V4L2_DEVICE_H_