chromium/media/gpu/v4l2/v4l2_utils.h

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_GPU_V4L2_V4L2_UTILS_H_
#define MEDIA_GPU_V4L2_V4L2_UTILS_H_

#include <linux/videodev2.h>
#include <sys/mman.h>

#include <optional>
#include <string>

#include "base/files/scoped_file.h"
#include "base/functional/callback.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "media/base/supported_video_decoder_config.h"
#include "media/base/svc_scalability_mode.h"
#include "media/base/video_codecs.h"
#include "mojo/public/cpp/platform/platform_handle.h"

#ifndef V4L2_PIX_FMT_QC08C
#define V4L2_PIX_FMT_QC08C \
  v4l2_fourcc('Q', '0', '8', 'C') /* Qualcomm 8-bit compressed */
#endif

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

namespace gfx {
class Size;
}
namespace media {
class VideoFrameLayout;

using IoctlAsCallback = base::RepeatingCallback<int(int, void*)>;

// Ideally this should be a decltype(mmap) (void *mmap(void *addr, size_t
// length, int prot, int flags, int fd, off_t offset)), but the types of e.g.
// V4L2Device::Mmap are wrong.
// TODO(b/279980150): correct types and argument order and use decltype.
using MmapAsCallback =
    base::RepeatingCallback<void*(void*, unsigned int, int, int, unsigned int)>;

// This is the callback invoked after successfully allocating a secure buffer.
// Invocation of this is guaranteed to pass a valid FD w/ the corresponding
// secure handle.
using SecureBufferAllocatedCB =
    base::OnceCallback<void(base::ScopedFD fd, uint64_t secure_handle)>;

using AllocateSecureBufferAsCallback =
    base::RepeatingCallback<void(uint32_t size,
                                 SecureBufferAllocatedCB callback)>;

// Numerical value of ioctl() OK return value;
constexpr int kIoctlOk = 0;

// These values are logged to UMA. Entries should not be renumbered and numeric
// values should never be reused. Please keep in sync with
// "MediaIoctlRequests" in src/tools/metrics/histograms/enums.xml.
enum class MediaIoctlRequests {
  kMediaIocDeviceInfo = 0,
  kMediaIocRequestAlloc = 1,
  kMediaRequestIocQueue = 2,
  kMediaRequestIocReinit = 3,
  kMaxValue = kMediaRequestIocReinit,
};

// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused. Please keep in sync with
// "VidiocIoctlRequests" in src/tools/metrics/histograms/enums.xml.
enum class VidiocIoctlRequests {
  kVidiocGFmt = 0,
  kVidiocSFmt = 1,
  kVidiocGSelection = 2,
  kVidiocExpbuf = 3,
  kVidiocReqbufs = 4,
  kVidiocQuerybuf = 5,
  kVidiocQbuf = 6,
  kVidiocDqbuf = 7,
  kVidiocStreamon = 8,
  kVidiocStreamoff = 9,
  kVidiocSExtCtrls = 10,
  kMaxValue = kVidiocSExtCtrls,
};

// Records Media.V4L2VideoDecoder.MediaIoctlError UMA when errors happen with
// media controller API ioctl requests.
void RecordMediaIoctlUMA(MediaIoctlRequests function);

// Records Vidioc.V4L2VideoDecoder.VidiocIoctlError UMA when errors happen with
// V4L2 API ioctl requests.
void RecordVidiocIoctlErrorUMA(VidiocIoctlRequests function);

// Returns a human readable description of |memory|.
const char* V4L2MemoryToString(v4l2_memory memory);

// Returns a human readable description of |format|.
std::string V4L2FormatToString(const struct v4l2_format& format);

// Returns a human readable description of |buffer|
std::string V4L2BufferToString(const struct v4l2_buffer& buffer);

// Translates |v4l2_codec| (a Control ID, e.g. V4L2_CID_MPEG_VIDEO_VP8_PROFILE)
// and |v4l2_profile| (e.g. V4L2_MPEG_VIDEO_VP8_PROFILE_0) to a
// media::VideoCodecProfile, if those are supported by Chrome. It returns
// VIDEO_CODEC_PROFILE_UNKNOWN otherwise.
VideoCodecProfile V4L2ProfileToVideoCodecProfile(uint32_t v4l2_codec,
                                                 uint32_t v4l2_profile);

// Returns number of planes of |pix_fmt|, or 1, if this is unknown.
size_t GetNumPlanesOfV4L2PixFmt(uint32_t pix_fmt);

// Composes VideoFrameLayout based on v4l2_format.
// If error occurs, it returns std::nullopt.
std::optional<VideoFrameLayout> V4L2FormatToVideoFrameLayout(
    const struct v4l2_format& format);

// Query the driver to see what scalability modes are supported for the driver.
std::vector<SVCScalabilityMode> GetSupportedScalabilityModesForV4L2Codec(
    const IoctlAsCallback& ioctl_cb,
    VideoCodecProfile media_profile);

// Enumerates the supported VideoCodecProfiles for a given device (accessed via
// |ioctl_cb|) and for |codec_as_pix_fmt| (e.g. V4L2_PIX_FMT_VP9). Returns an
// empty vector if |codec_as_pix_fmt| is not supported by Chrome, or the
// associated profiles cannot be enumerated or they are all unsupported
// themselves. Notably, if the device driver doesn't support enumeration of a
// supported |codec_as_pix_fmt| (i.e. VIDIOC_QUERYCTRL), a default list of
// profiles is returned (this happens for example for VP8 on Hana MTK8173, or
// for HEVC on Trogdor QC SC7180).
std::vector<VideoCodecProfile> EnumerateSupportedProfilesForV4L2Codec(
    const IoctlAsCallback& ioctl_cb,
    uint32_t codec_as_pix_fmt);

// Enumerates all supported pixel formats for a given device (accessed via
// |ioctl_cb|) and for |buf_type|; these will be the supported video codecs
// (e.g. V4L2_PIX_FMT_VP9) for V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE.
std::vector<uint32_t> EnumerateSupportedPixFmts(const IoctlAsCallback& ioctl_cb,
                                                v4l2_buf_type buf_type);

// Gets minimum and maximum resolution for fourcc |pixelformat|. If the driver
// doesn't support enumeration, default values are returned instead.
void GetSupportedResolution(const IoctlAsCallback& ioctl_cb,
                            uint32_t pixelformat,
                            gfx::Size* min_resolution,
                            gfx::Size* max_resolution);

// Translates a media::VideoCodecProfile to a supported pixel format
// (e.g. V4L2_PIX_FMT_VP9) if those are supported by Chrome. It returns
// V4L2_PIX_FMT_INVALID otherwise.
uint32_t VideoCodecProfileToV4L2PixFmt(VideoCodecProfile profile,
                                       bool slice_based);

// Translates a POSIX |timeval| to Chrome's base::TimeDelta.
base::TimeDelta TimeValToTimeDelta(const struct timeval& timeval);

// Translates a Chrome |time_delta| to a POSIX struct timeval.
struct timeval TimeDeltaToTimeVal(base::TimeDelta time_delta);

// Return a set of all the codecs supported by the hardware as well as
// their capabilities
std::optional<SupportedVideoDecoderConfigs> GetSupportedV4L2DecoderConfigs();

// Queries the driver to see if it supports stateful decoding.
bool IsV4L2DecoderStateful();

// Returns a readable description of |ctrls|.
std::string V4L2ControlsToString(const struct v4l2_ext_controls* ctrls);

}  // namespace media

#endif  // MEDIA_GPU_V4L2_V4L2_UTILS_H_