12 #include "libavutil/opt.h"
15 #define LOC QString("NVDEC: ")
34 const AVCodec **Codec,
39 bool decodeonly =
Decoder ==
"nvdec-dec";
51 QString codecstr = avcodec_get_name((*Context)->codec_id);
52 QString
profile = avcodec_profile_name((*Context)->codec_id, (*Context)->profile);
53 QString pixfmt = av_get_pix_fmt_name((*Context)->pix_fmt);
55 cudaVideoCodec cudacodec = cudaVideoCodec_NumCodecs;
56 switch ((*Context)->codec_id)
58 case AV_CODEC_ID_MPEG1VIDEO: cudacodec = cudaVideoCodec_MPEG1;
break;
59 case AV_CODEC_ID_MPEG2VIDEO: cudacodec = cudaVideoCodec_MPEG2;
break;
60 case AV_CODEC_ID_MPEG4: cudacodec = cudaVideoCodec_MPEG4;
break;
61 case AV_CODEC_ID_VC1: cudacodec = cudaVideoCodec_VC1;
break;
62 case AV_CODEC_ID_H264: cudacodec = cudaVideoCodec_H264;
break;
63 case AV_CODEC_ID_HEVC: cudacodec = cudaVideoCodec_HEVC;
break;
64 case AV_CODEC_ID_VP8: cudacodec = cudaVideoCodec_VP8;
break;
65 case AV_CODEC_ID_VP9: cudacodec = cudaVideoCodec_VP9;
break;
69 cudaVideoChromaFormat cudaformat = cudaVideoChromaFormat_Monochrome;
72 QString desc = QString(
"'%1 %2 %3 Depth:%4 %5x%6'")
73 .arg(codecstr,
profile, pixfmt).arg(depth + 8)
74 .arg((*Context)->width).arg((*Context)->height);
79 cudaformat = cudaVideoChromaFormat_420;
81 cudaformat = cudaVideoChromaFormat_422;
83 cudaformat = cudaVideoChromaFormat_444;
85 if ((cudacodec == cudaVideoCodec_NumCodecs) || (cudaformat == cudaVideoChromaFormat_Monochrome))
87 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"Unknown codec or format");
88 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"NVDEC does NOT support %1").arg(desc));
95 {
return Cap.Supports(cudacodec, cudaformat, depth, (*Context)->width, (*Context)->height); };
96 if (!std::any_of(profiles.cbegin(), profiles.cend(), capcheck))
98 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"No matching profile support");
99 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"NVDEC does NOT support %1").arg(desc));
105 QString name = QString((*Codec)->name) +
"_cuvid";
106 if (name ==
"mpeg2video_cuvid")
107 name =
"mpeg2_cuvid";
108 for (
int i = 0; ; i++)
110 const AVCodecHWConfig *config = avcodec_get_hw_config(*Codec, i);
114 if ((config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) &&
115 (config->device_type == AV_HWDEVICE_TYPE_CUDA))
117 const AVCodec *codec = avcodec_find_decoder_by_name(name.toLocal8Bit());
120 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"NVDEC supports decoding %1").arg(desc));
122 decoder->CodecMap()->FreeCodecContext(Stream);
123 *Context = decoder->CodecMap()->GetCodecContext(Stream, *Codec);
130 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to find decoder '%1'").arg(name));
155 if (!interop->IsValid())
162 AVBufferRef* hwdeviceref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_CUDA);
170 auto* hwdevicecontext =
reinterpret_cast<AVHWDeviceContext*
>(hwdeviceref->data);
172 hwdevicecontext->user_opaque = interop;
173 auto *devicehwctx =
reinterpret_cast<AVCUDADeviceContext*
>(hwdevicecontext->hwctx);
174 devicehwctx->cuda_ctx = interop->GetCUDAContext();
175 devicehwctx->stream =
nullptr;
177 if (av_hwdevice_ctx_init(hwdeviceref) < 0)
179 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to init CUDA hw device");
180 av_buffer_unref(&hwdeviceref);
184 Context->hw_device_ctx = hwdeviceref;
185 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Created CUDA device context");
194 DirectRendering =
false;
206 "Create NVDEC decoder");
214 Context->hw_device_ctx = context;
238 if (Context->height == 720)
269 deinterlacer = doubledeint;
279 if (!deinterlacer && !other && (singlepref &
DEINT_DRIVER))
280 deinterlacer = singledeint;
289 deinterlacer = doubledeint;
299 if (!deinterlacer && !other && singledeint)
302 deinterlacer = singledeint;
311 QString mode =
"adaptive";
314 int result = av_opt_set(Context->priv_data,
"deint", mode.toLocal8Bit(), 0);
317 if (av_opt_set_int(Context->priv_data,
"drop_second_field",
static_cast<int>(!DoubleRate), 0) == 0)
319 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Setup decoder deinterlacer '%1'")
332 Frame->m_interlaced = 0;
333 Frame->m_interlacedReverse =
false;
334 Frame->m_topFieldFirst =
false;
337 Frame->m_alreadyDeinterlaced =
true;
359 while (*PixFmt != AV_PIX_FMT_NONE)
361 if (*PixFmt == AV_PIX_FMT_CUDA)
366 auto * me =
dynamic_cast<MythNVDECContext*
>(decoder->GetMythCodecContext());
370 return AV_PIX_FMT_CUDA;
374 return AV_PIX_FMT_NONE;
379 if (AvFrame->format != AV_PIX_FMT_CUDA)
396 if ((AvFrame->format != AV_PIX_FMT_CUDA) || !AvFrame->data[0])
398 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Not a valid CUDA hw frame");
402 if (!Context || !
Frame)
407 for (
int i = 0; i < 3; i++)
409 Frame->m_pitches[i] = AvFrame->linesize[i];
410 Frame->m_offsets[i] = AvFrame->data[i] ? (
static_cast<int>(AvFrame->data[i] - AvFrame->data[0])) : 0;
411 Frame->m_priv[i] =
nullptr;
414 Frame->m_width = AvFrame->width;
415 Frame->m_height = AvFrame->height;
416 Frame->m_pixFmt = Context->pix_fmt;
417 Frame->m_directRendering =
true;
419 AvFrame->opaque =
Frame;
420 AvFrame->reordered_opaque = Context->reordered_opaque;
423 if (AvFrame->hw_frames_ctx)
425 auto *context =
reinterpret_cast<AVHWFramesContext*
>(AvFrame->hw_frames_ctx->data);
427 Frame->m_swPixFmt = context->sw_format;
431 Frame->m_colorshifted =
true;
434 Frame->m_buffer = AvFrame->data[0];
437 Frame->m_priv[0] =
reinterpret_cast<unsigned char*
>(av_buffer_ref(AvFrame->buf[0]));
441 Frame->m_priv[1] =
reinterpret_cast<unsigned char*
>(av_buffer_ref(Context->hw_device_ctx));
444 AvFrame->buf[1] = av_buffer_create(
reinterpret_cast<uint8_t*
>(
Frame), 0,
450 QSize Minimum, QSize Maximum,
uint MacroBlocks)
456 m_macroBlocks(MacroBlocks)
458 auto ToMythProfile = [](cudaVideoCodec CudaCodec)
475 auto ToMythFormat = [](cudaVideoChromaFormat CudaFormat)
479 case cudaVideoChromaFormat_420:
return FMT_YV12;
480 case cudaVideoChromaFormat_422:
return FMT_YUV422P;
481 case cudaVideoChromaFormat_444:
return FMT_YUV444P;
491 uint Depth,
int Width,
int Height)
const
493 uint mblocks =
static_cast<uint>((Width * Height) / 256);
495 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
496 QString(
"Trying to match: Codec %1 Format %2 Depth %3 Width %4 Height %5 MBs %6")
497 .arg(Codec).arg(
Format).arg(Depth).arg(Width).arg(Height).arg(mblocks));
498 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
499 QString(
"to this profile: Codec %1 Format %2 Depth %3 Width %4<->%5 Height %6<->%7 MBs %8")
500 .arg(m_codec).arg(m_format).arg(m_depth)
501 .arg(m_minimum.width()).arg(m_maximum.width())
502 .arg(m_minimum.height()).arg(m_maximum.height()).arg(m_macroBlocks));
504 bool result = (Codec == m_codec) && (
Format == m_format) && (Depth == m_depth) &&
505 (m_maximum.width() >= Width) && (m_maximum.height() >= Height) &&
506 (m_minimum.width() <= Width) && (m_minimum.height() <= Height) &&
507 (m_macroBlocks >= mblocks);
509 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"%1 Match").arg(result ?
"" :
"NO"));
515 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
516 static QMutex lock(QMutex::Recursive);
518 static QRecursiveMutex lock;
520 QMutexLocker locker(&lock);
521 static bool s_checked =
false;
522 static bool s_available =
false;
523 if (!s_checked || Reinit)
528 if (profiles.empty())
530 LOG(VB_GENERAL, LOG_INFO,
LOC +
"No NVDEC decoders found");
535 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Supported/available NVDEC decoders:");
536 for (
const auto&
profile : profiles)
540 LOG(VB_GENERAL, LOG_INFO,
LOC + desc + QString(
" MBs: %1").arg(
profile.m_macroBlocks));
546 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"HaveNVDEC must be initialised from the main thread");
557 if (profiles.empty())
559 Decoders.append(
"NVDEC:");
560 for (
const auto&
profile : profiles)
570 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
571 static QMutex lock(QMutex::Recursive);
573 static QRecursiveMutex lock;
575 static bool s_initialised =
false;
576 static std::vector<MythNVDECContext::MythNVDECCaps> s_profiles;
578 QMutexLocker locker(&lock);
581 s_initialised =
true;
584 CUcontext context =
nullptr;
585 CudaFunctions *cuda =
nullptr;
589 CuvidFunctions *cuvid =
nullptr;
590 CUcontext dummy =
nullptr;
591 cuda->cuCtxPushCurrent(context);
593 if (cuvid_load_functions(&cuvid,
nullptr) == 0)
596 if (!cuvid->cuvidGetDecoderCaps)
597 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Old driver - cannot check decoder capabilities");
600 for (
int codec = cudaVideoCodec_MPEG1; codec < cudaVideoCodec_NumCodecs; ++codec)
602 auto cudacodec =
static_cast<cudaVideoCodec
>(codec);
603 if (cudacodec == cudaVideoCodec_JPEG)
605 for (
int format = cudaVideoChromaFormat_420; format < cudaVideoChromaFormat_444; ++format)
607 auto cudaformat =
static_cast<cudaVideoChromaFormat
>(format);
608 for (
uint depth = 0; depth < 9; ++depth)
610 CUVIDDECODECAPS caps;
611 caps.eCodecType = cudacodec;
612 caps.eChromaFormat = cudaformat;
613 caps.nBitDepthMinus8 = depth;
615 if (cuvid->cuvidGetDecoderCaps && (cuvid->cuvidGetDecoderCaps(&caps) == CUDA_SUCCESS) &&
618 s_profiles.emplace_back(
619 cudacodec, depth, cudaformat,
620 QSize(caps.nMinWidth, caps.nMinHeight),
621 QSize(
static_cast<int>(caps.nMaxWidth),
static_cast<int>(caps.nMaxHeight)),
624 else if (!cuvid->cuvidGetDecoderCaps)
627 s_profiles.emplace_back(cudacodec, depth, cudaformat,
628 QSize(32, 32), QSize(8192, 8192),
629 (8192 * 8192) / 256);
634 cuvid_free_functions(&cuvid);
636 cuda->cuCtxPopCurrent(&dummy);
650 auto *frames =
reinterpret_cast<AVHWFramesContext*
>(
m_framesContext->data);
651 if ((frames->sw_format == Context->sw_pix_fmt) && (frames->width == Context->coded_width) &&
652 (frames->height == Context->coded_height))
666 AVBufferRef* framesref = av_hwframe_ctx_alloc(Context->hw_device_ctx);
667 auto *frames =
reinterpret_cast<AVHWFramesContext*
>(framesref->data);
669 frames->user_opaque =
nullptr;
670 frames->sw_format = Context->sw_pix_fmt;
671 frames->format = AV_PIX_FMT_CUDA;
672 frames->width = Context->coded_width;
673 frames->height = Context->coded_height;
674 if (av_hwframe_ctx_init(framesref) < 0)
676 av_buffer_unref(&framesref);
680 Context->hw_frames_ctx = framesref;