9#include "libmythbase/mythconfig.h"
30#include "libavcodec/defs.h"
31#include "libavutil/opt.h"
34#define LOC QString("V4L2_M2M: ")
54 const AVCodec **Codec,
59 bool decodeonly =
Decoder ==
"v4l2-dec";
64 if (!
Decoder.startsWith(
"v4l2"))
92 if (!standard.contains(mythprofile))
95 if (!requests.contains(mythprofile))
106 if ((*Codec)->id == AV_CODEC_ID_H264)
108 if ((*Context)->profile == AV_PROFILE_H264_HIGH_10 ||
109 (*Context)->profile == AV_PROFILE_H264_HIGH_10_INTRA)
118 (*Context)->pix_fmt = AV_PIX_FMT_DRM_PRIME;
123 success, failure,
"v4l2m2m",
124 decodeonly ? (*Context)->pix_fmt : AV_PIX_FMT_DRM_PRIME);
159 DirectRendering =
false;
165 DirectRendering =
false;
194 if (!(Context && Codec))
197 if (!(Codec->priv_class && Context->priv_data))
203 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Setting number of capture buffers to 6");
204 av_opt_set_int(Context->priv_data,
"num_capture_buffers", 6, 0);
216 if (!Context || !AvFrame || !
Frame)
222 const auto * supported =
Frame->m_renderFormats;
224#ifdef __cpp_lib_ranges_contains
225 if (!std::ranges::contains(*supported,
type))
228 if (found == supported->end())
233 if ((
Frame->m_type !=
type) || (
Frame->m_width != AvFrame->width) || (
Frame->m_height != AvFrame->height))
239 for (
uint plane = 0; plane < count; ++plane)
242 AvFrame->data[plane], AvFrame->linesize[plane],
250#ifndef V4L2_PIX_FMT_HEVC
251#define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C')
254#ifndef V4L2_PIX_FMT_VP9
255#define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0')
258#ifndef V4L2_PIX_FMT_NV12_COL128
259#define V4L2_PIX_FMT_NV12_COL128 v4l2_fourcc('N', 'C', '1', '2')
262#ifndef V4L2_PIX_FMT_NV12_10_COL128
263#define V4L2_PIX_FMT_NV12_10_COL128 v4l2_fourcc('N', 'C', '3', '0')
268 static const std::vector<V4L2Mapping> s_map
281 static QRecursiveMutex lock;
282 static bool s_initialised =
false;
285 QMutexLocker locker(&lock);
288 s_initialised =
true;
294 static const std::vector<uint32_t> s_formats
296 V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV420M,
297 V4L2_PIX_FMT_YVU420M, V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV12M,
304 const QString root(
"/dev/");
306 QStringList pixformats;
307 QStringList namefilters;
308 namefilters.append(
"video*");
309 auto devices = dir.entryList(namefilters, QDir::Files |QDir::System);
310 for (
const QString& device : std::as_const(devices))
314 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Device: %1 Driver: '%2' Capabilities: 0x%3")
319 bool mplanar = ((caps & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE)) != 0U) &&
320 ((caps & V4L2_CAP_STREAMING) != 0U);
321 bool mplanarm2m = (caps & V4L2_CAP_VIDEO_M2M_MPLANE) != 0U;
322 bool splanar = ((caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT)) != 0U) &&
323 ((caps & V4L2_CAP_STREAMING) != 0U);
324 bool splanarm2m = (caps & V4L2_CAP_VIDEO_M2M) != 0U;
326 if (!(mplanar || mplanarm2m || splanar || splanarm2m))
329 v4l2_buf_type capturetype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
330 v4l2_buf_type outputtype = V4L2_BUF_TYPE_VIDEO_OUTPUT;
332 if (mplanar || mplanarm2m)
334 capturetype = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
335 outputtype = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
341 for (
const auto &
profile : Profiles)
344 uint32_t v4l2pixfmt =
profile.first;
345 auto mythprofile =
profile.second;
346 struct v4l2_fmtdesc fdesc {};
347 memset(&fdesc, 0,
sizeof(fdesc));
350 fdesc.type = outputtype;
353 int res = ioctl(v4l2dev.
FD(), VIDIOC_ENUM_FMT, &fdesc);
356 if (fdesc.pixelformat == v4l2pixfmt)
364 bool foundfmt =
false;
366 memset(&fdesc, 0,
sizeof(fdesc));
367 fdesc.type = capturetype;
370 int res = ioctl(v4l2dev.
FD(), VIDIOC_ENUM_FMT, &fdesc);
373 pixformats.append(
fourcc_str(
static_cast<int>(fdesc.pixelformat)));
374#ifdef __cpp_lib_ranges_contains
375 if (std::ranges::contains(s_formats, fdesc.pixelformat))
380 if (!result.contains(mythprofile))
381 result.append(mythprofile);
390 if (pixformats.isEmpty())
391 pixformats.append(
"None");
392 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Codec '%1' has no supported formats (Supported: %2)")
405 if (!profiles.isEmpty())
408 Decoders.append(
"V4L2:");
414 if (!requests.isEmpty())
417 Decoders.append(
"V4L2 Request:");
426 static QRecursiveMutex lock;
427 QMutexLocker locker(&lock);
428 static bool s_checked =
false;
429 static bool s_available =
false;
431 if (s_checked && !Reinit)
437 if (standard.isEmpty() && request.isEmpty())
439 LOG(VB_GENERAL, LOG_INFO,
LOC +
"No V4L2 decoders found");
443 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Supported/available V4L2 decoders:");
446 for (
auto profile : std::as_const(standard))
448 for (
auto profile : std::as_const(request))
453#ifndef V4L2_PIX_FMT_MPEG2_SLICE
454#define V4L2_PIX_FMT_MPEG2_SLICE v4l2_fourcc('M', 'G', '2', 'S')
457#ifndef V4L2_PIX_FMT_H264_SLICE
458#define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4')
461#ifndef V4L2_PIX_FMT_VP8_FRAME
462#define V4L2_PIX_FMT_VP8_FRAME v4l2_fourcc('V', 'P', '8', 'F')
465#ifndef V4L2_PIX_FMT_VP9_FRAME
466#define V4L2_PIX_FMT_VP9_FRAME v4l2_fourcc('V', 'P', '9', 'F')
469#ifndef V4L2_PIX_FMT_HEVC_SLICE
470#define V4L2_PIX_FMT_HEVC_SLICE v4l2_fourcc('S', '2', '6', '5')
475 static const std::vector<V4L2Mapping> s_map
484 static QRecursiveMutex lock;
485 static bool s_initialised =
false;
488 QMutexLocker locker(&lock);
491 s_initialised =
true;
497 while (*PixFmt != AV_PIX_FMT_NONE)
499 if (*PixFmt == AV_PIX_FMT_DRM_PRIME)
502 "V4L2 request context creation") >= 0)
504 return AV_PIX_FMT_DRM_PRIME;
509 return AV_PIX_FMT_NONE;
523 Context->hw_device_ctx = hwdeviceref;
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
static bool FrameTypeIsSupported(AVCodecContext *Context, VideoFrameType Format)
static AVBufferRef * CreateDevice(AVHWDeviceType Type, MythInteropGPU *Interop, const QString &Device=QString())
static int InitialiseDecoder2(AVCodecContext *Context, CreateHWDecoder Callback, const QString &Debug)
Initialise a hardware decoder that is NOT expected to use AVHWFramesContext.
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
A generic context handler for codecs that return AV_PIX_FMT_DRM_PRIME frames.
void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering) override
bool GetDRMBuffer(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int)
static MythCodecID GetPrimeCodec(AVCodecContext **Context, const AVCodec **Codec, AVStream *Stream, MythCodecID Successs, MythCodecID Failure, const QString &CodecName, AVPixelFormat Format)
int HwDecoderInit(AVCodecContext *Context) override
bool RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame) override
static bool CheckCodecSize(int Width, int Height, MythCodecContext::CodecProfile Profile)
static MythCodecID GetSupportedCodec(AVCodecContext **Context, const AVCodec **Codec, const QString &Decoder, AVStream *Stream, uint StreamType)
static int InitialiseV4L2RequestContext(AVCodecContext *Context)
void SetDecoderOptions(AVCodecContext *Context, const AVCodec *Codec) override
Reduce the number of capture buffers.
static const V4L2Profiles & GetRequestProfiles()
static V4L2Profiles GetProfiles(const std::vector< V4L2Mapping > &Profiles)
static enum AVPixelFormat GetV4L2RequestFormat(AVCodecContext *Context, const AVPixelFormat *PixFmt)
static bool HaveV4L2Codecs(bool Reinit=false)
static void GetDecoderList(QStringList &Decoders)
bool RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame) override
void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering) override
static const V4L2Profiles & GetStandardProfiles()
bool DecoderWillResetOnFlush() override
static bool GetBuffer(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int)
Retrieve a frame from CPU memory.
MythV4L2M2MContext(DecoderBase *Parent, MythCodecID CodecID)
int HwDecoderInit(AVCodecContext *Context) override
static uint GetNumPlanes(VideoFrameType Type)
static int GetPitchForPlane(VideoFrameType Type, int Width, uint Plane)
static int GetHeightForPlane(VideoFrameType Type, int Height, uint Plane)
static void CopyPlane(uint8_t *To, int ToPitch, const uint8_t *From, int FromPitch, int PlaneWidth, int PlaneHeight)
QString GetDriverName(void) const
QString GetDeviceName(void) const
uint32_t GetCapabilities(void) const
static bool ReinitBuffer(MythVideoFrame *Frame, VideoFrameType Type, MythCodecID CodecID, int Width, int Height)
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
static const char * fourcc_str(int i)
static bool codec_is_v4l2_dec(MythCodecID id)
static bool codec_is_v4l2(MythCodecID id)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
#define V4L2_PIX_FMT_VP8_FRAME
#define V4L2_PIX_FMT_H264_SLICE
#define V4L2_PIX_FMT_HEVC_SLICE
#define V4L2_PIX_FMT_VP9_FRAME
#define V4L2_PIX_FMT_NV12_COL128
#define V4L2_PIX_FMT_MPEG2_SLICE
#define V4L2_PIX_FMT_NV12_10_COL128
#define V4L2_PIX_FMT_HEVC
QList< MythCodecContext::CodecProfile > V4L2Profiles