MythTV master
mythnvdeccontext.cpp
Go to the documentation of this file.
1// C++ headers
2#include <algorithm>
3
4// MythTV
8
9#include "avformatdecoder.h"
11#include "mythplayerui.h"
12#include "mythvideoout.h"
14
15extern "C" {
16#include "libavutil/log.h"
17#define FFNV_LOG_FUNC(logctx, msg, ...) av_log(logctx, AV_LOG_ERROR, msg, __VA_ARGS__)
18#define FFNV_DEBUG_LOG_FUNC(logctx, msg, ...) av_log(logctx, AV_LOG_DEBUG, msg, __VA_ARGS__)
19#include <ffnvcodec/dynlink_loader.h>
20}
21
22extern "C" {
23#include "libavutil/hwcontext_cuda.h"
24#include "libavutil/opt.h"
25}
26
27#define LOC QString("NVDEC: ")
28
29
31 : MythCodecContext(Parent, CodecID)
32{
33}
34
36{
37 av_buffer_unref(&m_framesContext);
38}
39
46 const AVCodec **Codec,
47 const QString &Decoder,
48 AVStream *Stream,
49 uint StreamType)
50{
51 bool decodeonly = Decoder == "nvdec-dec";
52 auto success = static_cast<MythCodecID>((decodeonly ? kCodec_MPEG1_NVDEC_DEC : kCodec_MPEG1_NVDEC) + (StreamType - 1));
53 auto failure = static_cast<MythCodecID>(kCodec_MPEG1 + (StreamType - 1));
54
55 // no brainers
56 if (!Decoder.startsWith("nvdec") || qEnvironmentVariableIsSet("NO_NVDEC") || !HaveNVDEC() || IsUnsupportedProfile(*Context))
57 return failure;
58
59 if (!decodeonly)
60 if (!FrameTypeIsSupported(*Context, FMT_NVDEC))
61 return failure;
62
63 QString codecstr = avcodec_get_name((*Context)->codec_id);
64 QString profile = avcodec_profile_name((*Context)->codec_id, (*Context)->profile);
65 QString pixfmt = av_get_pix_fmt_name((*Context)->pix_fmt);
66
67 cudaVideoCodec cudacodec = cudaVideoCodec_NumCodecs;
68 switch ((*Context)->codec_id)
69 {
70 case AV_CODEC_ID_MPEG1VIDEO: cudacodec = cudaVideoCodec_MPEG1; break;
71 case AV_CODEC_ID_MPEG2VIDEO: cudacodec = cudaVideoCodec_MPEG2; break;
72 case AV_CODEC_ID_MPEG4: cudacodec = cudaVideoCodec_MPEG4; break;
73 case AV_CODEC_ID_VC1: cudacodec = cudaVideoCodec_VC1; break;
74 case AV_CODEC_ID_H264: cudacodec = cudaVideoCodec_H264; break;
75 case AV_CODEC_ID_HEVC: cudacodec = cudaVideoCodec_HEVC; break;
76 case AV_CODEC_ID_VP8: cudacodec = cudaVideoCodec_VP8; break;
77 case AV_CODEC_ID_VP9: cudacodec = cudaVideoCodec_VP9; break;
78 default: break;
79 }
80
81 cudaVideoChromaFormat cudaformat = cudaVideoChromaFormat_Monochrome;
83 uint depth = static_cast<uint>(MythVideoFrame::ColorDepth(type) - 8);
84 QString desc = QString("'%1 %2 %3 Depth:%4 %5x%6'")
85 .arg(codecstr, profile, pixfmt).arg(depth + 8)
86 .arg((*Context)->width).arg((*Context)->height);
87
88 // N.B. on stream changes format is set to CUDA/NVDEC. This may break if the new
89 // stream has an unsupported chroma but the decoder should fail gracefully - just later.
91 cudaformat = cudaVideoChromaFormat_420;
93 cudaformat = cudaVideoChromaFormat_422;
95 cudaformat = cudaVideoChromaFormat_444;
96
97 if ((cudacodec == cudaVideoCodec_NumCodecs) || (cudaformat == cudaVideoChromaFormat_Monochrome))
98 {
99 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "Unknown codec or format");
100 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("NVDEC does NOT support %1").arg(desc));
101 return failure;
102 }
103
104 // iterate over known decoder capabilities
105 const auto & profiles = MythNVDECContext::GetProfiles();
106 auto capcheck = [&](const MythNVDECCaps& Cap)
107 { return Cap.Supports(cudacodec, cudaformat, depth, (*Context)->width, (*Context)->height); };
108 if (!std::ranges::any_of(profiles, capcheck))
109 {
110 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + "No matching profile support");
111 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("NVDEC does NOT support %1").arg(desc));
112 return failure;
113 }
114
115 auto *decoder = dynamic_cast<AvFormatDecoder*>(reinterpret_cast<DecoderBase*>((*Context)->opaque));
116 // and finally try and retrieve the actual FFmpeg decoder
117 QString name = QString((*Codec)->name) + "_cuvid";
118 if (name == "mpeg2video_cuvid")
119 name = "mpeg2_cuvid";
120 for (int i = 0; ; i++)
121 {
122 const AVCodecHWConfig *config = avcodec_get_hw_config(*Codec, i);
123 if (!config)
124 break;
125
126 if ((config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) &&
127 (config->device_type == AV_HWDEVICE_TYPE_CUDA))
128 {
129 const AVCodec *codec = avcodec_find_decoder_by_name(name.toLocal8Bit().constData());
130 if (codec)
131 {
132 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("NVDEC supports decoding %1").arg(desc));
133 *Codec = codec;
134 decoder->CodecMap()->FreeCodecContext(Stream);
135 *Context = decoder->CodecMap()->GetCodecContext(Stream, *Codec);
136 return success;
137 }
138 break;
139 }
140 }
141
142 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to find decoder '%1'").arg(name));
143 return failure;
144}
145
146int MythNVDECContext::InitialiseDecoder(AVCodecContext *Context)
147{
148 if (!gCoreContext->IsUIThread() || !Context)
149 return -1;
150
151 // We need a player to release the interop. As we are using direct rendering
152 // it must be a MythPlayerUI instance
153 auto * player = GetPlayerUI(Context);
154 if (!player)
155 return -1;
156
157 // Retrieve OpenGL render context
158 auto * render = dynamic_cast<MythRenderOpenGL*>(player->GetRender());
159 if (!render)
160 return -1;
161 OpenGLLocker locker(render);
162
163 // Create interop (and CUDA context)
164 auto * interop = MythNVDECInterop::CreateNVDEC(player, render);
165 if (!interop)
166 return -1;
167 if (!interop->IsValid())
168 {
169 interop->DecrRef();
170 return -1;
171 }
172
173 // Allocate the device context
174 AVBufferRef* hwdeviceref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_CUDA);
175 if (!hwdeviceref)
176 {
177 interop->DecrRef();
178 return -1;
179 }
180
181 // Set release method, interop and CUDA context
182 auto* hwdevicecontext = reinterpret_cast<AVHWDeviceContext*>(hwdeviceref->data);
183 hwdevicecontext->free = &MythCodecContext::DeviceContextFinished;
184 hwdevicecontext->user_opaque = interop;
185 auto *devicehwctx = reinterpret_cast<AVCUDADeviceContext*>(hwdevicecontext->hwctx);
186 devicehwctx->cuda_ctx = interop->GetCUDAContext();
187 devicehwctx->stream = nullptr;
188
189 if (av_hwdevice_ctx_init(hwdeviceref) < 0)
190 {
191 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to init CUDA hw device");
192 av_buffer_unref(&hwdeviceref);
193 return -1;
194 }
195
196 Context->hw_device_ctx = hwdeviceref;
197 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Created CUDA device context");
198 return 0;
199}
200
201void MythNVDECContext::InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
202{
204 {
205 Context->get_format = MythNVDECContext::GetFormat;
206 DirectRendering = false;
207 return;
208 }
209
210 MythCodecContext::InitVideoCodec(Context, SelectedStream, DirectRendering);
211}
212
213int MythNVDECContext::HwDecoderInit(AVCodecContext *Context)
214{
216 {
218 "Create NVDEC decoder");
219 }
221 {
222 AVBufferRef *context = MythCodecContext::CreateDevice(AV_HWDEVICE_TYPE_CUDA, nullptr,
223 gCoreContext->GetSetting("NVDECDevice"));
224 if (context)
225 {
226 Context->hw_device_ctx = context;
227 return 0;
228 }
229 }
230 return -1;
231}
232
239void MythNVDECContext::SetDeinterlacing(AVCodecContext *Context,
240 MythVideoProfile *Profile, bool DoubleRate)
241{
242 if (!Context)
243 return;
244
245 // Don't enable for anything that cannot be interlaced
246 // We could use frame rate here but initial frame rate detection is not always accurate
247 // and we lose little by enabling deinterlacing. NVDEC will not deinterlace a
248 // progressive stream and any CUDA capable video card has memory to spare
249 // (assuming it even sets up deinterlacing for a progressive stream)
250 if (Context->height == 720) // 720P
251 return;
252
253 MythDeintType deinterlacer = DEINT_NONE;
254 MythDeintType singlepref = DEINT_NONE;
255 MythDeintType doublepref = DEINT_NONE;
256 if (Profile)
257 {
259 if (DoubleRate)
261 }
262
263 // Deinterlacers are not filtered (as we have no frame) - so mask appropriately
264 MythDeintType singledeint = singlepref & (DEINT_BASIC | DEINT_MEDIUM | DEINT_HIGH);
265 MythDeintType doubledeint = doublepref & (DEINT_BASIC | DEINT_MEDIUM | DEINT_HIGH);
266
267 // With decode only/copy back, we can deinterlace here or the frames can use
268 // either CPU or shader deints. So only accept a driver deinterlacer preference.
269
270 // When direct rendering, there is no CPU option but shaders can be used.
271 // Assume driver deints are higher quality so accept a driver preference or CPU
272 // if shader is not preferred
273 bool other = false;
275 {
276 if (DoubleRate)
277 {
278 if (doubledeint)
279 {
280 if (doublepref & DEINT_DRIVER)
281 deinterlacer = doubledeint;
282 else if (doublepref & (DEINT_CPU | DEINT_SHADER))
283 other = true;
284 }
285 else
286 {
287 DoubleRate = false;
288 }
289 }
290
291 if (!deinterlacer && !other && (singlepref & DEINT_DRIVER))
292 deinterlacer = singledeint;
293 }
294 else if (codec_is_nvdec(m_codecID))
295 {
296 if (DoubleRate)
297 {
298 if (doubledeint)
299 {
300 if (doublepref & (DEINT_DRIVER | DEINT_CPU))
301 deinterlacer = doubledeint;
302 else if (doublepref & DEINT_SHADER)
303 other = true;
304 }
305 else
306 {
307 DoubleRate = false;
308 }
309 }
310
311 if (!deinterlacer && !other && singledeint)
312 {
313 if (singlepref & (DEINT_DRIVER | DEINT_CPU))
314 {
315 deinterlacer = singledeint;
316 }
317 else if (singlepref & DEINT_SHADER)
318 {
319 }
320 }
321 }
322
323 if (deinterlacer == DEINT_NONE)
324 return;
325
326 QString mode = "adaptive";
327 if (DEINT_BASIC == deinterlacer)
328 mode = "bob";
329 int result = av_opt_set(Context->priv_data, "deint", mode.toLocal8Bit().constData(), 0);
330 if (result == 0)
331 {
332 if (av_opt_set_int(Context->priv_data, "drop_second_field", static_cast<int>(!DoubleRate), 0) == 0)
333 {
334 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Setup decoder deinterlacer '%1'")
335 .arg(MythVideoFrame::DeinterlacerName(deinterlacer | DEINT_DRIVER, DoubleRate, FMT_NVDEC)));
336 m_deinterlacer = deinterlacer;
337 m_deinterlacer2x = DoubleRate;
338 }
339 }
340}
341
342void MythNVDECContext::PostProcessFrame(AVCodecContext* /*Context*/, MythVideoFrame *Frame)
343{
344 // Remove interlacing flags and set deinterlacer if necessary
345 if (Frame && m_deinterlacer)
346 {
347 Frame->m_interlaced = false;
348 Frame->m_interlacedReverse = false;
349 Frame->m_topFieldFirst = false;
350 Frame->m_deinterlaceInuse = m_deinterlacer | DEINT_DRIVER;
351 Frame->m_deinterlaceInuse2x = m_deinterlacer2x;
352 Frame->m_alreadyDeinterlaced = true;
353 }
354}
355
357{
359}
360
361bool MythNVDECContext::IsDeinterlacing(bool &DoubleRate, bool /*unused*/)
362{
364 {
365 DoubleRate = m_deinterlacer2x;
366 return true;
367 }
368 DoubleRate = false;
369 return false;
370}
371
372enum AVPixelFormat MythNVDECContext::GetFormat(AVCodecContext* Context, const AVPixelFormat *PixFmt)
373{
374 while (*PixFmt != AV_PIX_FMT_NONE)
375 {
376 if (*PixFmt == AV_PIX_FMT_CUDA)
377 {
378 auto * decoder = reinterpret_cast<AvFormatDecoder*>(Context->opaque);
379 if (decoder)
380 {
381 auto * me = dynamic_cast<MythNVDECContext*>(decoder->GetMythCodecContext());
382 if (me)
383 me->InitFramesContext(Context);
384 }
385 return AV_PIX_FMT_CUDA;
386 }
387 PixFmt++;
388 }
389 return AV_PIX_FMT_NONE;
390}
391
392bool MythNVDECContext::RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame)
393{
394 if (AvFrame->format != AV_PIX_FMT_CUDA)
395 return false;
397 return RetrieveHWFrame(Frame, AvFrame);
399 return GetBuffer(Context, Frame, AvFrame, 0);
400 return false;
401}
402
408bool MythNVDECContext::GetBuffer(struct AVCodecContext *Context, MythVideoFrame *Frame,
409 AVFrame *AvFrame, int /*Flags*/)
410{
411 if ((AvFrame->format != AV_PIX_FMT_CUDA) || !AvFrame->data[0])
412 {
413 LOG(VB_GENERAL, LOG_ERR, LOC + "Not a valid CUDA hw frame");
414 return false;
415 }
416
417 if (!Context || !Frame)
418 return false;
419
420 auto *decoder = static_cast<AvFormatDecoder*>(Context->opaque);
421
422 for (int i = 0; i < 3; i++)
423 {
424 Frame->m_pitches[i] = AvFrame->linesize[i];
425 Frame->m_offsets[i] = AvFrame->data[i] ? (static_cast<int>(AvFrame->data[i] - AvFrame->data[0])) : 0;
426 Frame->m_priv[i] = nullptr;
427 }
428
429 Frame->m_width = AvFrame->width;
430 Frame->m_height = AvFrame->height;
431 Frame->m_pixFmt = Context->pix_fmt;
432 Frame->m_directRendering = true;
433
434 AvFrame->opaque = Frame;
435
436 // set the pixel format - normally NV12 but P010 for 10bit etc. Set here rather than guessing later.
437 if (AvFrame->hw_frames_ctx)
438 {
439 auto *context = reinterpret_cast<AVHWFramesContext*>(AvFrame->hw_frames_ctx->data);
440 if (context)
441 Frame->m_swPixFmt = context->sw_format;
442 }
443
444 // NVDEC 'fixes' 10/12/16bit colour values
445 Frame->m_colorshifted = true;
446
447 // Frame->data[0] holds CUdeviceptr for the frame data - offsets calculated above
448 Frame->m_buffer = AvFrame->data[0];
449
450 // Retain the buffer so it is not released before we display it
451 Frame->m_priv[0] = reinterpret_cast<unsigned char*>(av_buffer_ref(AvFrame->buf[0]));
452
453 // We need the CUDA device context in the interop class and it also holds the reference
454 // to the interop class itself
455 Frame->m_priv[1] = reinterpret_cast<unsigned char*>(av_buffer_ref(Context->hw_device_ctx));
456
457 // Set the release method
458 AvFrame->buf[1] = av_buffer_create(reinterpret_cast<uint8_t*>(Frame), 0,
460 return true;
461}
462
463MythNVDECContext::MythNVDECCaps::MythNVDECCaps(cudaVideoCodec Codec, uint Depth, cudaVideoChromaFormat Format,
464 QSize Minimum, QSize Maximum, uint MacroBlocks)
465 : m_codec(Codec),
466 m_depth(Depth),
467 m_format(Format),
468 m_minimum(Minimum),
469 m_maximum(Maximum),
470 m_macroBlocks(MacroBlocks)
471{
472 auto ToMythProfile = [](cudaVideoCodec CudaCodec)
473 {
474 switch (CudaCodec)
475 {
476 case cudaVideoCodec_MPEG1: return MythCodecContext::MPEG1;
477 case cudaVideoCodec_MPEG2: return MythCodecContext::MPEG2;
478 case cudaVideoCodec_MPEG4: return MythCodecContext::MPEG4;
479 case cudaVideoCodec_VC1: return MythCodecContext::VC1;
480 case cudaVideoCodec_H264: return MythCodecContext::H264;
481 case cudaVideoCodec_HEVC: return MythCodecContext::HEVC;
482 case cudaVideoCodec_VP8: return MythCodecContext::VP8;
483 case cudaVideoCodec_VP9: return MythCodecContext::VP9;
484 default: break;
485 }
487 };
488
489 auto ToMythFormat = [](cudaVideoChromaFormat CudaFormat)
490 {
491 switch (CudaFormat)
492 {
493 case cudaVideoChromaFormat_420: return FMT_YV12;
494 case cudaVideoChromaFormat_422: return FMT_YUV422P;
495 case cudaVideoChromaFormat_444: return FMT_YUV444P;
496 default: break;
497 }
498 return FMT_NONE;
499 };
500 m_profile = ToMythProfile(m_codec);
501 m_type = ToMythFormat(m_format);
502}
503
504bool MythNVDECContext::MythNVDECCaps::Supports(cudaVideoCodec Codec, cudaVideoChromaFormat Format,
505 uint Depth, int Width, int Height) const
506{
507 uint mblocks = static_cast<uint>((Width * Height) / 256);
508
509 LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
510 QString("Trying to match: Codec %1 Format %2 Depth %3 Width %4 Height %5 MBs %6")
511 .arg(Codec).arg(Format).arg(Depth).arg(Width).arg(Height).arg(mblocks));
512 LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
513 QString("to this profile: Codec %1 Format %2 Depth %3 Width %4<->%5 Height %6<->%7 MBs %8")
514 .arg(m_codec).arg(m_format).arg(m_depth)
515 .arg(m_minimum.width()).arg(m_maximum.width())
516 .arg(m_minimum.height()).arg(m_maximum.height()).arg(m_macroBlocks));
517
518 bool result = (Codec == m_codec) && (Format == m_format) && (Depth == m_depth) &&
519 (m_maximum.width() >= Width) && (m_maximum.height() >= Height) &&
520 (m_minimum.width() <= Width) && (m_minimum.height() <= Height) &&
521 (m_macroBlocks >= mblocks);
522
523 LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("%1 Match").arg(result ? "" : "NO"));
524 return result;
525}
526
527bool MythNVDECContext::HaveNVDEC(bool Reinit /*=false*/)
528{
529 static QRecursiveMutex lock;
530 QMutexLocker locker(&lock);
531 static bool s_checked = false;
532 static bool s_available = false;
533 if (!s_checked || Reinit)
534 {
536 {
537 const std::vector<MythNVDECCaps>& profiles = MythNVDECContext::GetProfiles();
538 if (profiles.empty())
539 {
540 LOG(VB_GENERAL, LOG_INFO, LOC + "No NVDEC decoders found");
541 }
542 else
543 {
544 s_available = true;
545 LOG(VB_GENERAL, LOG_INFO, LOC + "Supported/available NVDEC decoders:");
546 for (const auto& profile : profiles)
547 {
548 QString desc = MythCodecContext::GetProfileDescription(profile.m_profile,profile.m_maximum,
549 profile.m_type, profile.m_depth + 8);
550 LOG(VB_GENERAL, LOG_INFO, LOC + desc + QString(" MBs: %1").arg(profile.m_macroBlocks));
551 }
552 }
553 }
554 else
555 {
556 LOG(VB_GENERAL, LOG_WARNING, LOC + "HaveNVDEC must be initialised from the main thread");
557 }
558 }
559 s_checked = true;
560 return s_available;
561}
562
563
564void MythNVDECContext::GetDecoderList(QStringList &Decoders)
565{
566 const std::vector<MythNVDECCaps>& profiles = MythNVDECContext::GetProfiles();
567 if (profiles.empty())
568 return;
569 Decoders.append("NVDEC:");
570 for (const auto& profile : profiles)
571 {
572 if (!(profile.m_depth % 2)) // Ignore 9/11bit etc
573 Decoders.append(MythCodecContext::GetProfileDescription(profile.m_profile, profile.m_maximum,
574 profile.m_type, profile.m_depth + 8));
575 }
576}
577
578const std::vector<MythNVDECContext::MythNVDECCaps> &MythNVDECContext::GetProfiles(void)
579{
580 static QRecursiveMutex lock;
581 static bool s_initialised = false;
582 static std::vector<MythNVDECContext::MythNVDECCaps> s_profiles;
583
584 QMutexLocker locker(&lock);
585 if (s_initialised)
586 return s_profiles;
587 s_initialised = true;
588
590 CUcontext context = nullptr;
591 CudaFunctions *cuda = nullptr;
592 if (MythNVDECInterop::CreateCUDAContext(opengl, cuda, context))
593 {
594 OpenGLLocker gllocker(opengl);
595 CuvidFunctions *cuvid = nullptr;
596 CUcontext dummy = nullptr;
597 cuda->cuCtxPushCurrent(context);
598
599 if (cuvid_load_functions(&cuvid, nullptr) == 0)
600 {
601 // basic check passed
602 if (!cuvid->cuvidGetDecoderCaps)
603 LOG(VB_GENERAL, LOG_WARNING, LOC + "Old driver - cannot check decoder capabilities");
604
605 // now iterate over codecs, depths and formats to check support
606 for (int codec = cudaVideoCodec_MPEG1; codec < cudaVideoCodec_NumCodecs; ++codec)
607 {
608 auto cudacodec = static_cast<cudaVideoCodec>(codec);
609 if (cudacodec == cudaVideoCodec_JPEG)
610 continue;
611 for (int format = cudaVideoChromaFormat_420; format < cudaVideoChromaFormat_444; ++format)
612 {
613 auto cudaformat = static_cast<cudaVideoChromaFormat>(format);
614 for (uint depth = 0; depth < 9; ++depth)
615 {
616 CUVIDDECODECAPS caps;
617 caps.eCodecType = cudacodec;
618 caps.eChromaFormat = cudaformat;
619 caps.nBitDepthMinus8 = depth;
620 // N.B. cuvidGetDecoderCaps was not available on older drivers
621 if (cuvid->cuvidGetDecoderCaps && (cuvid->cuvidGetDecoderCaps(&caps) == CUDA_SUCCESS) &&
622 caps.bIsSupported)
623 {
624 s_profiles.emplace_back(
625 cudacodec, depth, cudaformat,
626 QSize(caps.nMinWidth, caps.nMinHeight),
627 QSize(static_cast<int>(caps.nMaxWidth), static_cast<int>(caps.nMaxHeight)),
628 caps.nMaxMBCount);
629 }
630 else if (!cuvid->cuvidGetDecoderCaps)
631 {
632 // dummy - just support everything:)
633 s_profiles.emplace_back(cudacodec, depth, cudaformat,
634 QSize(32, 32), QSize(8192, 8192),
635 (8192 * 8192) / 256);
636 }
637 }
638 }
639 }
640 cuvid_free_functions(&cuvid);
641 }
642 cuda->cuCtxPopCurrent(&dummy);
643 }
644 MythNVDECInterop::CleanupContext(opengl, cuda, context);
645
646 return s_profiles;
647}
648
649void MythNVDECContext::InitFramesContext(AVCodecContext *Context)
650{
651 if (!Context)
652 return;
653
654 if (m_framesContext)
655 {
656 auto *frames = reinterpret_cast<AVHWFramesContext*>(m_framesContext->data);
657 if ((frames->sw_format == Context->sw_pix_fmt) && (frames->width == Context->coded_width) &&
658 (frames->height == Context->coded_height))
659 {
660 Context->hw_frames_ctx = av_buffer_ref(m_framesContext);
661 return;
662 }
663 }
664
665 // If this is a 'spontaneous' callback from FFmpeg (i.e. not on a stream change)
666 // then we must release any direct render buffers.
668 m_parent->GetPlayer()->DiscardVideoFrames(true, true);
669
670 av_buffer_unref(&m_framesContext);
671
672 AVBufferRef* framesref = av_hwframe_ctx_alloc(Context->hw_device_ctx);
673 auto *frames = reinterpret_cast<AVHWFramesContext*>(framesref->data);
675 frames->user_opaque = nullptr;
676 frames->sw_format = Context->sw_pix_fmt;
677 frames->format = AV_PIX_FMT_CUDA;
678 frames->width = Context->coded_width;
679 frames->height = Context->coded_height;
680 if (av_hwframe_ctx_init(framesref) < 0)
681 {
682 av_buffer_unref(&framesref);
683 }
684 else
685 {
686 Context->hw_frames_ctx = framesref;
687 m_framesContext = av_buffer_ref(framesref);
689 }
690}
AVFrame AVFrame
A decoder for media files.
MythPlayer * GetPlayer()
Definition: decoderbase.h:152
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
Definition: mythavutil.cpp:75
static void DeviceContextFinished(AVHWDeviceContext *Context)
static bool IsUnsupportedProfile(AVCodecContext *Context)
Most hardware decoders do not support these codecs/profiles.
static bool FrameTypeIsSupported(AVCodecContext *Context, VideoFrameType Format)
static void ReleaseBuffer(void *Opaque, uint8_t *Data)
virtual bool RetrieveHWFrame(MythVideoFrame *Frame, AVFrame *AvFrame)
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.
virtual void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
static void FramesContextFinished(AVHWFramesContext *Context)
static void NewHardwareFramesContext(void)
Track the number of concurrent frames contexts.
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
static MythPlayerUI * GetPlayerUI(AVCodecContext *Context)
DecoderBase * m_parent
MythCodecID m_codecID
QString GetSetting(const QString &key, const QString &defaultval="")
cudaVideoChromaFormat m_format
MythCodecContext::CodecProfile m_profile
MythNVDECCaps(cudaVideoCodec Codec, uint Depth, cudaVideoChromaFormat Format, QSize Minimum, QSize Maximum, uint MacroBlocks)
bool Supports(cudaVideoCodec Codec, cudaVideoChromaFormat Format, uint Depth, int Width, int Height) const
bool IsDeinterlacing(bool &DoubleRate, bool StreamChange=false) override
MythDeintType m_deinterlacer
static int InitialiseDecoder(AVCodecContext *Context)
static enum AVPixelFormat GetFormat(AVCodecContext *Context, const AVPixelFormat *PixFmt)
static void GetDecoderList(QStringList &Decoders)
static bool GetBuffer(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int Flags)
Convert AVFrame data to MythFrame.
void PostProcessFrame(AVCodecContext *Context, MythVideoFrame *Frame) override
static MythCodecID GetSupportedCodec(AVCodecContext **CodecContext, const AVCodec **Codec, const QString &Decoder, AVStream *Stream, uint StreamType)
Determine whether NVDEC decoding is supported for this codec.
~MythNVDECContext() override
bool RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame) override
AVBufferRef * m_framesContext
void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering) override
int HwDecoderInit(AVCodecContext *Context) override
MythNVDECContext(DecoderBase *Parent, MythCodecID CodecID)
void SetDeinterlacing(AVCodecContext *Context, MythVideoProfile *Profile, bool DoubleRate) override
Enable NVDEC/CUDA deinterlacing if necessary.
void InitFramesContext(AVCodecContext *Context)
static bool HaveNVDEC(bool Reinit=false)
bool DecoderWillResetOnFlush(void) override
static const std::vector< MythNVDECCaps > & GetProfiles(void)
static bool CreateCUDAContext(MythRenderOpenGL *GLContext, CudaFunctions *&CudaFuncs, CUcontext &CudaContext)
static MythNVDECInterop * CreateNVDEC(MythPlayerUI *Player, MythRenderOpenGL *Context)
static void CleanupContext(MythRenderOpenGL *GLContext, CudaFunctions *&CudaFuncs, CUcontext &CudaContext)
void DiscardVideoFrames(bool KeyFrame, bool Flushed)
Places frames in the available frames queue.
Definition: mythplayer.cpp:642
static MythRenderOpenGL * GetOpenGLRender(void)
static bool FormatIs422(VideoFrameType Type)
Definition: mythframe.h:443
static QString DeinterlacerName(MythDeintType Deint, bool DoubleRate, VideoFrameType Format=FMT_NONE)
Definition: mythframe.cpp:466
static bool FormatIs444(VideoFrameType Type)
Definition: mythframe.h:449
static bool FormatIs420(VideoFrameType Type)
Definition: mythframe.h:437
static MythDeintType ParseDeinterlacer(const QString &Deinterlacer)
Definition: mythframe.cpp:548
static int ColorDepth(int Format)
Definition: mythframe.h:398
QString GetDoubleRatePreferences() const
QString GetSingleRatePreferences() const
unsigned int uint
Definition: compat.h:60
MythCodecID
Definition: mythcodecid.h:14
@ kCodec_MPEG1_NVDEC
Definition: mythcodecid.h:152
@ kCodec_MPEG1_NVDEC_DEC
Definition: mythcodecid.h:168
@ kCodec_MPEG1
Definition: mythcodecid.h:24
static bool codec_is_nvdec(MythCodecID id)
Definition: mythcodecid.h:344
static bool codec_is_nvdec_dec(MythCodecID id)
Definition: mythcodecid.h:347
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythDeintType
Definition: mythframe.h:67
@ DEINT_HIGH
Definition: mythframe.h:71
@ DEINT_DRIVER
Definition: mythframe.h:74
@ DEINT_MEDIUM
Definition: mythframe.h:70
@ DEINT_BASIC
Definition: mythframe.h:69
@ DEINT_NONE
Definition: mythframe.h:68
@ DEINT_SHADER
Definition: mythframe.h:73
@ DEINT_CPU
Definition: mythframe.h:72
VideoFrameType
Definition: mythframe.h:20
@ FMT_YUV444P
Definition: mythframe.h:43
@ FMT_YV12
Definition: mythframe.h:23
@ FMT_NONE
Definition: mythframe.h:21
@ FMT_NVDEC
Definition: mythframe.h:62
@ FMT_YUV422P
Definition: mythframe.h:36
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
#define LOC