28 #include "libavutil/opt.h"
31 #define LOC QString("V4L2_M2M: ")
51 const AVCodec **Codec,
56 bool decodeonly =
Decoder ==
"v4l2-dec";
61 if (!
Decoder.startsWith(
"v4l2"))
89 if (!standard.contains(mythprofile))
92 if (!requests.contains(mythprofile))
103 if ((*Codec)->id == AV_CODEC_ID_H264)
105 if ((*Context)->profile == FF_PROFILE_H264_HIGH_10 ||
106 (*Context)->profile == FF_PROFILE_H264_HIGH_10_INTRA)
115 (*Context)->pix_fmt = AV_PIX_FMT_DRM_PRIME;
120 success, failure,
"v4l2m2m",
121 decodeonly ? (*Context)->pix_fmt : AV_PIX_FMT_DRM_PRIME);
156 DirectRendering =
false;
162 DirectRendering =
false;
191 if (!(Context && Codec))
194 if (!(Codec->priv_class && Context->priv_data))
200 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Setting number of capture buffers to 6");
201 av_opt_set_int(Context->priv_data,
"num_capture_buffers", 6, 0);
213 if (!Context || !AvFrame || !
Frame)
219 const auto * supported =
Frame->m_renderFormats;
220 auto found =
std::find(supported->cbegin(), supported->cend(),
type);
222 if (found == supported->end())
226 if ((
Frame->m_type !=
type) || (
Frame->m_width != AvFrame->width) || (
Frame->m_height != AvFrame->height))
232 for (
uint plane = 0; plane < count; ++plane)
235 AvFrame->data[plane], AvFrame->linesize[plane],
243 #ifndef V4L2_PIX_FMT_HEVC
244 #define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C')
247 #ifndef V4L2_PIX_FMT_VP9
248 #define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0')
251 #ifndef V4L2_PIX_FMT_NV12_COL128
252 #define V4L2_PIX_FMT_NV12_COL128 v4l2_fourcc('N', 'C', '1', '2')
255 #ifndef V4L2_PIX_FMT_NV12_10_COL128
256 #define V4L2_PIX_FMT_NV12_10_COL128 v4l2_fourcc('N', 'C', '3', '0')
261 static const std::vector<V4L2Mapping> s_map
274 static QRecursiveMutex lock;
275 static bool s_initialised =
false;
278 QMutexLocker locker(&lock);
281 s_initialised =
true;
287 static const std::vector<uint32_t> s_formats
289 V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV420M,
290 V4L2_PIX_FMT_YVU420M, V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_NV12M,
297 const QString root(
"/dev/");
299 QStringList namefilters;
300 namefilters.append(
"video*");
301 auto devices = dir.entryList(namefilters, QDir::Files |QDir::System);
302 for (
const QString& device : std::as_const(devices))
306 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Device: %1 Driver: '%2' Capabilities: 0x%3")
311 bool mplanar = ((caps & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE)) != 0U) &&
312 ((caps & V4L2_CAP_STREAMING) != 0U);
313 bool mplanarm2m = (caps & V4L2_CAP_VIDEO_M2M_MPLANE) != 0U;
314 bool splanar = ((caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT)) != 0U) &&
315 ((caps & V4L2_CAP_STREAMING) != 0U);
316 bool splanarm2m = (caps & V4L2_CAP_VIDEO_M2M) != 0U;
318 if (!(mplanar || mplanarm2m || splanar || splanarm2m))
321 v4l2_buf_type capturetype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
322 v4l2_buf_type outputtype = V4L2_BUF_TYPE_VIDEO_OUTPUT;
324 if (mplanar || mplanarm2m)
326 capturetype = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
327 outputtype = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
333 for (
const auto &
profile : Profiles)
336 uint32_t v4l2pixfmt =
profile.first;
337 auto mythprofile =
profile.second;
338 struct v4l2_fmtdesc fdesc {};
339 memset(&fdesc, 0,
sizeof(fdesc));
342 fdesc.type = outputtype;
345 int res = ioctl(v4l2dev.
FD(), VIDIOC_ENUM_FMT, &fdesc);
348 if (fdesc.pixelformat == v4l2pixfmt)
355 QStringList pixformats;
356 bool foundfmt =
false;
358 memset(&fdesc, 0,
sizeof(fdesc));
359 fdesc.type = capturetype;
362 int res = ioctl(v4l2dev.
FD(), VIDIOC_ENUM_FMT, &fdesc);
365 pixformats.append(
fourcc_str(
static_cast<int>(fdesc.pixelformat)));
366 if (
std::find(s_formats.cbegin(), s_formats.cend(), fdesc.pixelformat) != s_formats.cend())
368 if (!result.contains(mythprofile))
369 result.append(mythprofile);
378 if (pixformats.isEmpty())
379 pixformats.append(
"None");
380 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Codec '%1' has no supported formats (Supported: %2)")
393 if (!profiles.isEmpty())
396 Decoders.append(
"V4L2:");
402 if (!requests.isEmpty())
405 Decoders.append(
"V4L2 Request:");
414 static QRecursiveMutex lock;
415 QMutexLocker locker(&lock);
416 static bool s_checked =
false;
417 static bool s_available =
false;
419 if (s_checked && !Reinit)
425 if (standard.isEmpty() && request.isEmpty())
427 LOG(VB_GENERAL, LOG_INFO,
LOC +
"No V4L2 decoders found");
431 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Supported/available V4L2 decoders:");
434 for (
auto profile : std::as_const(standard))
436 for (
auto profile : std::as_const(request))
441 #ifndef V4L2_PIX_FMT_MPEG2_SLICE
442 #define V4L2_PIX_FMT_MPEG2_SLICE v4l2_fourcc('M', 'G', '2', 'S')
445 #ifndef V4L2_PIX_FMT_H264_SLICE
446 #define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4')
449 #ifndef V4L2_PIX_FMT_VP8_FRAME
450 #define V4L2_PIX_FMT_VP8_FRAME v4l2_fourcc('V', 'P', '8', 'F')
453 #ifndef V4L2_PIX_FMT_VP9_FRAME
454 #define V4L2_PIX_FMT_VP9_FRAME v4l2_fourcc('V', 'P', '9', 'F')
457 #ifndef V4L2_PIX_FMT_HEVC_SLICE
458 #define V4L2_PIX_FMT_HEVC_SLICE v4l2_fourcc('S', '2', '6', '5')
463 static const std::vector<V4L2Mapping> s_map
472 static QRecursiveMutex lock;
473 static bool s_initialised =
false;
476 QMutexLocker locker(&lock);
479 s_initialised =
true;
485 while (*PixFmt != AV_PIX_FMT_NONE)
487 if (*PixFmt == AV_PIX_FMT_DRM_PRIME)
490 "V4L2 request context creation") >= 0)
492 return AV_PIX_FMT_DRM_PRIME;
497 return AV_PIX_FMT_NONE;
511 Context->hw_device_ctx = hwdeviceref;