12 #include "libavutil/log.h"
13 #define FFNV_LOG_FUNC(logctx, msg, ...) av_log(logctx, AV_LOG_ERROR, msg, __VA_ARGS__)
14 #define FFNV_DEBUG_LOG_FUNC(logctx, msg, ...) av_log(logctx, AV_LOG_DEBUG, msg, __VA_ARGS__)
15 #include <ffnvcodec/dynlink_loader.h>
19 #include "libavutil/hwcontext_cuda.h"
20 #include "libavutil/opt.h"
23 #define LOC QString("NVDEC: ")
42 const AVCodec **Codec,
47 bool decodeonly =
Decoder ==
"nvdec-dec";
59 QString codecstr = avcodec_get_name((*Context)->codec_id);
60 QString
profile = avcodec_profile_name((*Context)->codec_id, (*Context)->profile);
61 QString pixfmt = av_get_pix_fmt_name((*Context)->pix_fmt);
63 cudaVideoCodec cudacodec = cudaVideoCodec_NumCodecs;
64 switch ((*Context)->codec_id)
66 case AV_CODEC_ID_MPEG1VIDEO: cudacodec = cudaVideoCodec_MPEG1;
break;
67 case AV_CODEC_ID_MPEG2VIDEO: cudacodec = cudaVideoCodec_MPEG2;
break;
68 case AV_CODEC_ID_MPEG4: cudacodec = cudaVideoCodec_MPEG4;
break;
69 case AV_CODEC_ID_VC1: cudacodec = cudaVideoCodec_VC1;
break;
70 case AV_CODEC_ID_H264: cudacodec = cudaVideoCodec_H264;
break;
71 case AV_CODEC_ID_HEVC: cudacodec = cudaVideoCodec_HEVC;
break;
72 case AV_CODEC_ID_VP8: cudacodec = cudaVideoCodec_VP8;
break;
73 case AV_CODEC_ID_VP9: cudacodec = cudaVideoCodec_VP9;
break;
77 cudaVideoChromaFormat cudaformat = cudaVideoChromaFormat_Monochrome;
80 QString desc = QString(
"'%1 %2 %3 Depth:%4 %5x%6'")
81 .arg(codecstr,
profile, pixfmt).arg(depth + 8)
82 .arg((*Context)->width).arg((*Context)->height);
87 cudaformat = cudaVideoChromaFormat_420;
89 cudaformat = cudaVideoChromaFormat_422;
91 cudaformat = cudaVideoChromaFormat_444;
93 if ((cudacodec == cudaVideoCodec_NumCodecs) || (cudaformat == cudaVideoChromaFormat_Monochrome))
95 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"Unknown codec or format");
96 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"NVDEC does NOT support %1").arg(desc));
103 {
return Cap.Supports(cudacodec, cudaformat, depth, (*Context)->width, (*Context)->height); };
104 if (!std::any_of(profiles.cbegin(), profiles.cend(), capcheck))
106 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
"No matching profile support");
107 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"NVDEC does NOT support %1").arg(desc));
113 QString name = QString((*Codec)->name) +
"_cuvid";
114 if (name ==
"mpeg2video_cuvid")
115 name =
"mpeg2_cuvid";
116 for (
int i = 0; ; i++)
118 const AVCodecHWConfig *config = avcodec_get_hw_config(*Codec, i);
122 if ((config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) &&
123 (config->device_type == AV_HWDEVICE_TYPE_CUDA))
125 const AVCodec *codec = avcodec_find_decoder_by_name(name.toLocal8Bit());
128 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"NVDEC supports decoding %1").arg(desc));
130 decoder->CodecMap()->FreeCodecContext(Stream);
131 *Context = decoder->CodecMap()->GetCodecContext(Stream, *Codec);
138 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to find decoder '%1'").arg(name));
163 if (!interop->IsValid())
170 AVBufferRef* hwdeviceref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_CUDA);
178 auto* hwdevicecontext =
reinterpret_cast<AVHWDeviceContext*
>(hwdeviceref->data);
180 hwdevicecontext->user_opaque = interop;
181 auto *devicehwctx =
reinterpret_cast<AVCUDADeviceContext*
>(hwdevicecontext->hwctx);
182 devicehwctx->cuda_ctx = interop->GetCUDAContext();
183 devicehwctx->stream =
nullptr;
185 if (av_hwdevice_ctx_init(hwdeviceref) < 0)
187 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to init CUDA hw device");
188 av_buffer_unref(&hwdeviceref);
192 Context->hw_device_ctx = hwdeviceref;
193 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Created CUDA device context");
202 DirectRendering =
false;
214 "Create NVDEC decoder");
222 Context->hw_device_ctx = context;
246 if (Context->height == 720)
277 deinterlacer = doubledeint;
287 if (!deinterlacer && !other && (singlepref &
DEINT_DRIVER))
288 deinterlacer = singledeint;
297 deinterlacer = doubledeint;
307 if (!deinterlacer && !other && singledeint)
310 deinterlacer = singledeint;
319 QString mode =
"adaptive";
322 int result = av_opt_set(Context->priv_data,
"deint", mode.toLocal8Bit(), 0);
325 if (av_opt_set_int(Context->priv_data,
"drop_second_field",
static_cast<int>(!DoubleRate), 0) == 0)
327 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Setup decoder deinterlacer '%1'")
340 Frame->m_interlaced =
false;
341 Frame->m_interlacedReverse =
false;
342 Frame->m_topFieldFirst =
false;
345 Frame->m_alreadyDeinterlaced =
true;
367 while (*PixFmt != AV_PIX_FMT_NONE)
369 if (*PixFmt == AV_PIX_FMT_CUDA)
374 auto * me =
dynamic_cast<MythNVDECContext*
>(decoder->GetMythCodecContext());
378 return AV_PIX_FMT_CUDA;
382 return AV_PIX_FMT_NONE;
387 if (AvFrame->format != AV_PIX_FMT_CUDA)
404 if ((AvFrame->format != AV_PIX_FMT_CUDA) || !AvFrame->data[0])
406 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Not a valid CUDA hw frame");
410 if (!Context || !
Frame)
415 for (
int i = 0; i < 3; i++)
417 Frame->m_pitches[i] = AvFrame->linesize[i];
418 Frame->m_offsets[i] = AvFrame->data[i] ? (
static_cast<int>(AvFrame->data[i] - AvFrame->data[0])) : 0;
419 Frame->m_priv[i] =
nullptr;
422 Frame->m_width = AvFrame->width;
423 Frame->m_height = AvFrame->height;
424 Frame->m_pixFmt = Context->pix_fmt;
425 Frame->m_directRendering =
true;
427 AvFrame->opaque =
Frame;
430 if (AvFrame->hw_frames_ctx)
432 auto *context =
reinterpret_cast<AVHWFramesContext*
>(AvFrame->hw_frames_ctx->data);
434 Frame->m_swPixFmt = context->sw_format;
438 Frame->m_colorshifted =
true;
441 Frame->m_buffer = AvFrame->data[0];
444 Frame->m_priv[0] =
reinterpret_cast<unsigned char*
>(av_buffer_ref(AvFrame->buf[0]));
448 Frame->m_priv[1] =
reinterpret_cast<unsigned char*
>(av_buffer_ref(Context->hw_device_ctx));
451 AvFrame->buf[1] = av_buffer_create(
reinterpret_cast<uint8_t*
>(
Frame), 0,
457 QSize Minimum, QSize Maximum,
uint MacroBlocks)
463 m_macroBlocks(MacroBlocks)
465 auto ToMythProfile = [](cudaVideoCodec CudaCodec)
482 auto ToMythFormat = [](cudaVideoChromaFormat CudaFormat)
486 case cudaVideoChromaFormat_420:
return FMT_YV12;
487 case cudaVideoChromaFormat_422:
return FMT_YUV422P;
488 case cudaVideoChromaFormat_444:
return FMT_YUV444P;
498 uint Depth,
int Width,
int Height)
const
500 uint mblocks =
static_cast<uint>((Width * Height) / 256);
502 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
503 QString(
"Trying to match: Codec %1 Format %2 Depth %3 Width %4 Height %5 MBs %6")
504 .arg(Codec).arg(
Format).arg(Depth).arg(Width).arg(Height).arg(mblocks));
505 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC +
506 QString(
"to this profile: Codec %1 Format %2 Depth %3 Width %4<->%5 Height %6<->%7 MBs %8")
507 .arg(m_codec).arg(m_format).arg(m_depth)
508 .arg(m_minimum.width()).arg(m_maximum.width())
509 .arg(m_minimum.height()).arg(m_maximum.height()).arg(m_macroBlocks));
511 bool result = (Codec == m_codec) && (
Format == m_format) && (Depth == m_depth) &&
512 (m_maximum.width() >= Width) && (m_maximum.height() >= Height) &&
513 (m_minimum.width() <= Width) && (m_minimum.height() <= Height) &&
514 (m_macroBlocks >= mblocks);
516 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"%1 Match").arg(result ?
"" :
"NO"));
522 static QRecursiveMutex lock;
523 QMutexLocker locker(&lock);
524 static bool s_checked =
false;
525 static bool s_available =
false;
526 if (!s_checked || Reinit)
531 if (profiles.empty())
533 LOG(VB_GENERAL, LOG_INFO,
LOC +
"No NVDEC decoders found");
538 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Supported/available NVDEC decoders:");
539 for (
const auto&
profile : profiles)
543 LOG(VB_GENERAL, LOG_INFO,
LOC + desc + QString(
" MBs: %1").arg(
profile.m_macroBlocks));
549 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"HaveNVDEC must be initialised from the main thread");
560 if (profiles.empty())
562 Decoders.append(
"NVDEC:");
563 for (
const auto&
profile : profiles)
573 static QRecursiveMutex lock;
574 static bool s_initialised =
false;
575 static std::vector<MythNVDECContext::MythNVDECCaps> s_profiles;
577 QMutexLocker locker(&lock);
580 s_initialised =
true;
583 CUcontext context =
nullptr;
584 CudaFunctions *cuda =
nullptr;
588 CuvidFunctions *cuvid =
nullptr;
589 CUcontext dummy =
nullptr;
590 cuda->cuCtxPushCurrent(context);
592 if (cuvid_load_functions(&cuvid,
nullptr) == 0)
595 if (!cuvid->cuvidGetDecoderCaps)
596 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Old driver - cannot check decoder capabilities");
599 for (
int codec = cudaVideoCodec_MPEG1; codec < cudaVideoCodec_NumCodecs; ++codec)
601 auto cudacodec =
static_cast<cudaVideoCodec
>(codec);
602 if (cudacodec == cudaVideoCodec_JPEG)
604 for (
int format = cudaVideoChromaFormat_420; format < cudaVideoChromaFormat_444; ++format)
606 auto cudaformat =
static_cast<cudaVideoChromaFormat
>(format);
607 for (
uint depth = 0; depth < 9; ++depth)
609 CUVIDDECODECAPS caps;
610 caps.eCodecType = cudacodec;
611 caps.eChromaFormat = cudaformat;
612 caps.nBitDepthMinus8 = depth;
614 if (cuvid->cuvidGetDecoderCaps && (cuvid->cuvidGetDecoderCaps(&caps) == CUDA_SUCCESS) &&
617 s_profiles.emplace_back(
618 cudacodec, depth, cudaformat,
619 QSize(caps.nMinWidth, caps.nMinHeight),
620 QSize(
static_cast<int>(caps.nMaxWidth),
static_cast<int>(caps.nMaxHeight)),
623 else if (!cuvid->cuvidGetDecoderCaps)
626 s_profiles.emplace_back(cudacodec, depth, cudaformat,
627 QSize(32, 32), QSize(8192, 8192),
628 (8192 * 8192) / 256);
633 cuvid_free_functions(&cuvid);
635 cuda->cuCtxPopCurrent(&dummy);
649 auto *frames =
reinterpret_cast<AVHWFramesContext*
>(
m_framesContext->data);
650 if ((frames->sw_format == Context->sw_pix_fmt) && (frames->width == Context->coded_width) &&
651 (frames->height == Context->coded_height))
665 AVBufferRef* framesref = av_hwframe_ctx_alloc(Context->hw_device_ctx);
666 auto *frames =
reinterpret_cast<AVHWFramesContext*
>(framesref->data);
668 frames->user_opaque =
nullptr;
669 frames->sw_format = Context->sw_pix_fmt;
670 frames->format = AV_PIX_FMT_CUDA;
671 frames->width = Context->coded_width;
672 frames->height = Context->coded_height;
673 if (av_hwframe_ctx_init(framesref) < 0)
675 av_buffer_unref(&framesref);
679 Context->hw_frames_ctx = framesref;