21 #include <sys/ioctl.h>
25 #include "libavutil/opt.h"
26 #ifdef USING_V4L2_REQUEST
27 #include "libavcodec/v4l2_request.h"
33 #define LOC QString("V4L2_M2M: ")
58 bool decodeonly =
Decoder ==
"v4l2-dec";
63 if (!
Decoder.startsWith(
"v4l2"))
91 if (!standard.contains(mythprofile))
94 if (!requests.contains(mythprofile))
105 if ((*Codec)->id == AV_CODEC_ID_H264)
107 if ((*Context)->profile == FF_PROFILE_H264_HIGH_10 ||
108 (*Context)->profile == FF_PROFILE_H264_HIGH_10_INTRA)
117 (*Context)->pix_fmt = AV_PIX_FMT_DRM_PRIME;
122 success, failure,
"v4l2m2m",
123 decodeonly ? (*Context)->pix_fmt : AV_PIX_FMT_DRM_PRIME);
158 DirectRendering =
false;
164 DirectRendering =
false;
193 if (!(Context && Codec))
196 if (!(Codec->priv_class && Context->priv_data))
202 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Setting number of capture buffers to 6");
203 av_opt_set_int(Context->priv_data,
"num_capture_buffers", 6, 0);
215 if (!Context || !AvFrame || !
Frame)
221 const auto * supported =
Frame->m_renderFormats;
222 auto found =
std::find(supported->cbegin(), supported->cend(),
type);
224 if (found == supported->end())
228 if ((
Frame->m_type !=
type) || (
Frame->m_width != AvFrame->width) || (
Frame->m_height != AvFrame->height))
234 for (
uint plane = 0; plane < count; ++plane)
237 AvFrame->data[plane], AvFrame->linesize[plane],
245 #ifndef V4L2_PIX_FMT_HEVC
246 #define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C')
249 #ifndef V4L2_PIX_FMT_VP9
250 #define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0')
253 #ifndef V4L2_PIX_FMT_NV12_COL128
254 #define V4L2_PIX_FMT_NV12_COL128 v4l2_fourcc('N', 'C', '1', '2')
257 #ifndef V4L2_PIX_FMT_NV12_10_COL128
258 #define V4L2_PIX_FMT_NV12_10_COL128 v4l2_fourcc('N', 'C', '3', '0')
263 static const std::vector<V4L2Mapping> s_map
276 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
277 static QMutex lock(QMutex::Recursive);
279 static QRecursiveMutex lock;
281 static bool s_initialised =
false;
284 QMutexLocker locker(&lock);
287 s_initialised =
true;
293 static const std::vector<uint32_t> s_formats
295 V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV420M,
296 V4L2_PIX_FMT_YVU420M, V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV12M,
303 const QString root(
"/dev/");
305 QStringList namefilters;
306 namefilters.append(
"video*");
307 auto devices = dir.entryList(namefilters, QDir::Files |QDir::System);
308 for (
const QString& device : qAsConst(devices))
312 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Device: %1 Driver: '%2' Capabilities: 0x%3")
317 bool mplanar = ((caps & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE)) != 0U) &&
318 ((caps & V4L2_CAP_STREAMING) != 0U);
319 bool mplanarm2m = (caps & V4L2_CAP_VIDEO_M2M_MPLANE) != 0U;
320 bool splanar = ((caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT)) != 0U) &&
321 ((caps & V4L2_CAP_STREAMING) != 0U);
322 bool splanarm2m = (caps & V4L2_CAP_VIDEO_M2M) != 0U;
324 if (!(mplanar || mplanarm2m || splanar || splanarm2m))
327 v4l2_buf_type capturetype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
328 v4l2_buf_type outputtype = V4L2_BUF_TYPE_VIDEO_OUTPUT;
330 if (mplanar || mplanarm2m)
332 capturetype = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
333 outputtype = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
340 for (
const auto &
profile : Profiles)
343 uint32_t v4l2pixfmt =
profile.first;
344 auto mythprofile =
profile.second;
345 struct v4l2_fmtdesc fdesc {};
346 memset(&fdesc, 0,
sizeof(fdesc));
349 fdesc.type = outputtype;
352 int res = ioctl(v4l2dev.
FD(), VIDIOC_ENUM_FMT, &fdesc);
355 if (fdesc.pixelformat == v4l2pixfmt)
362 QStringList pixformats;
363 bool foundfmt =
false;
365 memset(&fdesc, 0,
sizeof(fdesc));
366 fdesc.type = capturetype;
369 int res = ioctl(v4l2dev.
FD(), VIDIOC_ENUM_FMT, &fdesc);
372 pixformats.append(
fourcc_str(
static_cast<int>(fdesc.pixelformat)));
373 if (
std::find(s_formats.cbegin(), s_formats.cend(), fdesc.pixelformat) != s_formats.cend())
375 if (!result.contains(mythprofile))
376 result.append(mythprofile);
385 if (pixformats.isEmpty())
386 pixformats.append(
"None");
387 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Codec '%1' has no supported formats (Supported: %2)")
400 if (!profiles.isEmpty())
403 Decoders.append(
"V4L2:");
409 if (!requests.isEmpty())
412 Decoders.append(
"V4L2 Request:");
421 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
422 static QMutex lock(QMutex::Recursive);
424 static QRecursiveMutex lock;
426 QMutexLocker locker(&lock);
427 static bool s_checked =
false;
428 static bool s_available =
false;
430 if (s_checked && !Reinit)
436 if (standard.isEmpty() && request.isEmpty())
438 LOG(VB_GENERAL, LOG_INFO,
LOC +
"No V4L2 decoders found");
442 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Supported/available V4L2 decoders:");
445 for (
auto profile : qAsConst(standard))
447 for (
auto profile : qAsConst(request))
452 #ifndef V4L2_PIX_FMT_MPEG2_SLICE
453 #define V4L2_PIX_FMT_MPEG2_SLICE v4l2_fourcc('M', 'G', '2', 'S')
456 #ifndef V4L2_PIX_FMT_H264_SLICE
457 #define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4')
460 #ifndef V4L2_PIX_FMT_VP8_FRAME
461 #define V4L2_PIX_FMT_VP8_FRAME v4l2_fourcc('V', 'P', '8', 'F')
464 #ifndef V4L2_PIX_FMT_VP9_FRAME
465 #define V4L2_PIX_FMT_VP9_FRAME v4l2_fourcc('V', 'P', '9', 'F')
468 #ifndef V4L2_PIX_FMT_HEVC_SLICE
469 #define V4L2_PIX_FMT_HEVC_SLICE v4l2_fourcc('S', '2', '6', '5')
474 static const std::vector<V4L2Mapping> s_map
483 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
484 static QMutex lock(QMutex::Recursive);
486 static QRecursiveMutex lock;
488 static bool s_initialised =
false;
491 QMutexLocker locker(&lock);
494 s_initialised =
true;
500 while (*PixFmt != AV_PIX_FMT_NONE)
502 if (*PixFmt == AV_PIX_FMT_DRM_PRIME)
505 "V4L2 request context creation") >= 0)
507 return AV_PIX_FMT_DRM_PRIME;
512 return AV_PIX_FMT_NONE;
527 if (av_hwdevice_ctx_init(hwdeviceref) < 0)
529 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to initialise device context");
530 av_buffer_unref(&hwdeviceref);
534 Context->hw_device_ctx = hwdeviceref;
540 if (!Context || !AvFrame || !
Frame)
543 if (
Frame->m_type !=
FMT_DRMPRIME ||
static_cast<AVPixelFormat
>(AvFrame->format) != AV_PIX_FMT_DRM_PRIME)
545 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Not a DRM PRIME buffer");
549 Frame->m_width = AvFrame->width;
550 Frame->m_height = AvFrame->height;
551 Frame->m_pixFmt = Context->pix_fmt;
552 Frame->m_swPixFmt = Context->sw_pix_fmt;
553 Frame->m_directRendering =
true;
554 AvFrame->opaque =
Frame;
555 AvFrame->reordered_opaque = Context->reordered_opaque;
560 Frame->m_priv[0] =
reinterpret_cast<unsigned char*
>(av_buffer_ref(AvFrame->buf[0]));