26#include "libmythbase/mythconfig.h"
44#if CONFIG_VIDEOTOOLBOX
65#include "libavcodec/defs.h"
66#include "libavutil/pixdesc.h"
69#define LOC QString("MythCodecContext: ")
95#if CONFIG_VIDEOTOOLBOX
123 QStringList decoders;
143#if CONFIG_VIDEOTOOLBOX
153 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Must be called from UI thread");
159 LOG(VB_GENERAL, LOG_INFO,
LOC +
"No window: Ignoring hardware decoders");
204 Opts.
decoders->append(
"mediacodec");
206 Opts.
decoders->append(
"mediacodec-dec");
210#if CONFIG_VIDEOTOOLBOX
253 [[maybe_unused]] AVStream *Stream,
254 AVCodecContext **Context,
255 const AVCodec **Codec)
270#if CONFIG_VIDEOTOOLBOX
310 bool SelectedStream,
bool &DirectRendering)
312 const AVCodec *codec1 = Context->codec;
313 if (codec1 && codec1->capabilities & AV_CODEC_CAP_DR1)
320 DirectRendering =
false;
321 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
322 QString(
"Using software scaling to convert pixel format %1 for "
323 "codec %2").arg(av_get_pix_fmt_name(Context->pix_fmt),
324 avcodec_get_name(Context->codec_id)));
332 MythVideoFrame *videoframe = avfd->GetPlayer()->GetNextVideoFrame();
335 for (
int i = 0; i < 4; i++)
337 Frame->data[i] =
nullptr;
338 Frame->linesize[i] = 0;
340 Frame->opaque = videoframe;
341 videoframe->
m_pixFmt = Context->pix_fmt;
343 int ret = avcodec_default_get_buffer2(Context,
Frame, Flags);
348 if (
Frame->hw_frames_ctx)
350 auto *context =
reinterpret_cast<AVHWFramesContext*
>(
Frame->hw_frames_ctx->data);
365 videoframe->
m_priv[0] =
reinterpret_cast<unsigned char*
>(av_buffer_ref(
Frame->buf[0]));
369 videoframe->
m_priv[1] =
reinterpret_cast<unsigned char*
>(av_buffer_ref(
Frame->hw_frames_ctx));
372 Frame->buf[1] = av_buffer_create(
reinterpret_cast<uint8_t*
>(videoframe), 0,
382 if (!AvFrame || !Context || !
Frame)
387 Frame->m_pixFmt = Context->pix_fmt;
388 Frame->m_directRendering =
true;
389 Frame->m_colorshifted =
true;
391 AvFrame->opaque =
Frame;
394 if (AvFrame->hw_frames_ctx)
396 auto *context =
reinterpret_cast<AVHWFramesContext*
>(AvFrame->hw_frames_ctx->data);
398 Frame->m_swPixFmt = context->sw_format;
402 Frame->m_buffer = AvFrame->data[3];
406 Frame->m_priv[0] =
reinterpret_cast<unsigned char*
>(av_buffer_ref(AvFrame->buf[0]));
409 auto *devicectx =
reinterpret_cast<AVHWDeviceContext*
>(Context->hw_device_ctx->data);
410 Frame->m_priv[1] =
reinterpret_cast<unsigned char*
>(devicectx->user_opaque);
413 AvFrame->buf[1] = av_buffer_create(
reinterpret_cast<uint8_t*
>(
Frame), 0,
422 if (decoder && decoder->GetPlayer())
423 decoder->GetPlayer()->DeLimboFrame(frame);
437 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"Error: %1 concurrent hardware frames contexts").arg(count));
443 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"%1 frames context finished")
444 .arg(av_hwdevice_get_type_name(Context->device_ctx->type)));
445 auto * interop =
reinterpret_cast<MythInteropGPU*
>(Context->user_opaque);
452 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"%1 device context finished")
453 .arg(av_hwdevice_get_type_name(Context->type)));
454 auto * interop =
reinterpret_cast<MythInteropGPU*
>(Context->user_opaque);
458 void *io_user_opaque = interop->GetDefaultUserOpaque();
462 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Calling default device context free");
463 Context->user_opaque = io_user_opaque;
477 auto destroy = [](
void *Wait,
void *Interop2,
void* )
479 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Destroy interop callback");
480 auto *wait =
reinterpret_cast<QWaitCondition*
>(Wait);
490 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Cannot destroy interop - no player");
494 destroy, Interop,
nullptr);
499 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Create decoder callback");
500 auto *wait =
reinterpret_cast<QWaitCondition*
>(Wait);
501 auto *context =
reinterpret_cast<AVCodecContext*
>(Context);
503 if (context && callback)
504 (void)callback(context);
514 result =
dynamic_cast<MythPlayerUI*
>(decoder->GetPlayer());
520 if (
auto * player =
GetPlayerUI(Context); player !=
nullptr)
522 const auto & supported = player->GetInteropTypes();
523 return supported.find(
Format) != supported.cend();
530 const QString &Debug)
532 if (!Context || !Callback)
535 return Callback(Context);
541 Context,
reinterpret_cast<void*
>(Callback));
542 return Context->hw_frames_ctx ? 0 : -1;
547 const QString &Debug)
549 if (!Context || !Callback)
552 return Callback(Context);
558 Context,
reinterpret_cast<void*
>(Callback));
559 return Context->hw_device_ctx ? 0 : -1;
564 AVBufferRef* result =
nullptr;
565 int res = av_hwdevice_ctx_create(&result, Type,
Device.isEmpty() ?
nullptr :
566 Device.toLocal8Bit().constData(),
nullptr, 0);
569 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Created hardware device '%1'%2")
570 .arg(av_hwdevice_get_type_name(Type),
571 Device ==
nullptr ?
"" : QString(
" (%1)").arg(
Device)));
572 auto *context =
reinterpret_cast<AVHWDeviceContext*
>(result->data);
574 if ((context->free || context->user_opaque) && !Interop)
576 LOG(VB_PLAYBACK, LOG_INFO,
"Creating dummy interop");
588 context->user_opaque = Interop;
593 LOG(VB_PLAYBACK, LOG_ERR,
LOC + QString(
"Failed to create hardware device '%1'%2 Error '%3'")
594 .arg(av_hwdevice_get_type_name(Type),
603 switch (Context->codec_id)
605 case AV_CODEC_ID_H264:
606 switch (Context->profile)
608 case AV_PROFILE_H264_HIGH_10:
609 case AV_PROFILE_H264_HIGH_10_INTRA:
610 case AV_PROFILE_H264_HIGH_422:
611 case AV_PROFILE_H264_HIGH_422_INTRA:
612 case AV_PROFILE_H264_HIGH_444_PREDICTIVE:
613 case AV_PROFILE_H264_HIGH_444_INTRA:
614 case AV_PROFILE_H264_CAVLC_444:
return true;
628 return avcodec_receive_frame(Context,
Frame);
633 if (!
Frame || !AvFrame)
636 AVFrame *temp = av_frame_alloc();
640 AVPixelFormat *pixelformats =
nullptr;
641 int ret = av_hwframe_transfer_get_formats(AvFrame->hw_frames_ctx,
642 AV_HWFRAME_TRANSFER_DIRECTION_FROM,
647 if (best != AV_PIX_FMT_NONE)
651 if (!valid || (
Frame->m_width != AvFrame->width) || (
Frame->m_height != AvFrame->height))
653 AvFrame->width, AvFrame->height);
660 for (
uint i = 0; i < 3; i++)
662 temp->data[i] = (i < max) ? (
Frame->m_buffer +
Frame->m_offsets[i]) :
nullptr;
663 temp->linesize[i] =
Frame->m_pitches[i];
667 temp->buf[0] = av_buffer_create(
reinterpret_cast<uint8_t*
>(
Frame), 0,
668 [](
void* , uint8_t* ){},
this, 0);
669 temp->width = AvFrame->width;
670 temp->height = AvFrame->height;
674 av_freep(
reinterpret_cast<void*
>(&pixelformats));
679 ret = av_hwframe_transfer_data(temp, AvFrame, 0);
681 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Error %1 transferring the data to system memory").arg(ret));
684 Frame->m_colorshifted =
true;
685 av_frame_free(&temp);
693 case AV_CODEC_ID_MPEG1VIDEO:
return MPEG1;
694 case AV_CODEC_ID_MPEG2VIDEO:
697 case AV_PROFILE_MPEG2_422:
return MPEG2422;
698 case AV_PROFILE_MPEG2_HIGH:
return MPEG2High;
700 case AV_PROFILE_MPEG2_SNR_SCALABLE:
return MPEG2SNR;
702 case AV_PROFILE_MPEG2_MAIN:
return MPEG2Main;
706 case AV_CODEC_ID_MPEG4:
711 case AV_PROFILE_MPEG4_CORE:
return MPEG4Core;
712 case AV_PROFILE_MPEG4_MAIN:
return MPEG4Main;
713 case AV_PROFILE_MPEG4_N_BIT:
return MPEG4NBit;
727 case AV_CODEC_ID_H263:
return H263;
728 case AV_CODEC_ID_H264:
734 case AV_PROFILE_H264_MAIN:
return H264Main;
736 case AV_PROFILE_H264_HIGH:
return H264High;
737 case AV_PROFILE_H264_HIGH_10:
return H264High10;
749 case AV_CODEC_ID_HEVC:
752 case AV_PROFILE_HEVC_MAIN:
return HEVCMain;
753 case AV_PROFILE_HEVC_MAIN_10:
return HEVCMain10;
754 case AV_PROFILE_HEVC_MAIN_STILL_PICTURE:
return HEVCMainStill;
755 case AV_PROFILE_HEVC_REXT:
return HEVCRext;
758 case AV_CODEC_ID_VC1:
761 case AV_PROFILE_VC1_SIMPLE:
return VC1Simple;
762 case AV_PROFILE_VC1_MAIN:
return VC1Main;
763 case AV_PROFILE_VC1_COMPLEX:
return VC1Complex;
767 case AV_CODEC_ID_VP8:
return VP8;
768 case AV_CODEC_ID_VP9:
771 case AV_PROFILE_VP9_0:
return VP9_0;
772 case AV_PROFILE_VP9_1:
return VP9_1;
773 case AV_PROFILE_VP9_2:
return VP9_2;
774 case AV_PROFILE_VP9_3:
return VP9_3;
777 case AV_CODEC_ID_AV1:
780 case AV_PROFILE_AV1_MAIN:
return AV1Main;
781 case AV_PROFILE_AV1_HIGH:
return AV1High;
785 case AV_CODEC_ID_MJPEG:
return MJPEG;
868 return QObject::tr(
"%1%2%3 (Max size: %4x%5)")
871 ColorDepth > 8 ? QString(
" %1Bit").arg(ColorDepth) :
"")
872 .arg(Size.width()).arg(Size.height());
static AVPixelFormat GetBestVideoFormat(AVPixelFormat *Formats, const VideoFrameTypes *RenderFormats)
Find a suitable frame format that is mutually acceptable to the decoder and render device.
virtual MythCodecID GetVideoCodecID(void) const =0
A device containing images (ie. USB stick, CD, storage group etc)
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
static MythCodecID FindDecoder(const QString &Decoder, AVStream *Stream, AVCodecContext **Context, const AVCodec **Codec)
static void DeviceContextFinished(AVHWDeviceContext *Context)
static void GetDecoders(RenderOptions &Opts, bool Reinit=false)
static int InitialiseDecoder(AVCodecContext *Context, CreateHWDecoder Callback, const QString &Debug)
Initialise a hardware decoder that is expected to use AVHWFramesContext.
static bool IsUnsupportedProfile(AVCodecContext *Context)
Most hardware decoders do not support these codecs/profiles.
static QStringList GetDecoderDescription(void)
static bool FrameTypeIsSupported(AVCodecContext *Context, VideoFrameType Format)
@ MPEG4AdvancedScaleableTexture
@ H264ConstrainedBaseline
static void ReleaseBuffer(void *Opaque, uint8_t *Data)
static int GetBuffer(struct AVCodecContext *Context, AVFrame *Frame, int Flags)
A generic hardware buffer initialisation method when using AVHWFramesContext.
virtual bool RetrieveHWFrame(MythVideoFrame *Frame, AVFrame *AvFrame)
static AVBufferRef * CreateDevice(AVHWDeviceType Type, MythInteropGPU *Interop, const QString &Device=QString())
static QAtomicInt s_hwFramesContextCount
static void DestroyInterop(MythInteropGPU *Interop)
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 CreateDecoderCallback(void *Wait, void *Context, void *Callback)
static void FramesContextFinished(AVHWFramesContext *Context)
static void NewHardwareFramesContext(void)
Track the number of concurrent frames contexts.
static MythCodecContext * CreateContext(DecoderBase *Parent, MythCodecID Codec)
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
MythCodecContext(DecoderBase *Parent, MythCodecID CodecID)
static bool GetBuffer2(struct AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int Flags)
A generic hardware buffer initialisation method when AVHWFramesContext is NOT used.
static MythPlayerUI * GetPlayerUI(AVCodecContext *Context)
virtual int FilteredReceiveFrame(AVCodecContext *Context, AVFrame *Frame)
Retrieve and process/filter AVFrame.
static CodecProfile FFmpegToMythProfile(AVCodecID CodecID, int Profile)
A generic context handler for codecs that return AV_PIX_FMT_DRM_PRIME frames.
static MythCodecID GetSupportedCodec(AVCodecContext **Context, const AVCodec **Codec, const QString &Decoder, AVStream *Stream, uint StreamType)
static bool HavePrimeDecoders(bool Reinit=false, AVCodecID Codec=AV_CODEC_ID_NONE)
void SetDefaultFree(FreeAVHWDeviceContext FreeContext)
FreeAVHWDeviceContext GetDefaultFree()
void SetDefaultUserOpaque(void *UserOpaque)
static MythInteropGPU * CreateDummy()
static InteropMap GetTypes(MythRender *Render)
MythPlayerUI * GetPlayer()
static bool HaveMMAL(bool Reinit=false)
static void GetDecoderList(QStringList &Decoders)
static MythCodecID GetSupportedCodec(AVCodecContext **Context, const AVCodec **Codec, const QString &Decoder, AVStream *Stream, uint StreamType)
static MythCodecID GetBestSupportedCodec(AVCodecContext **Context, const AVCodec **Codec, const QString &Decoder, AVStream *Stream, uint StreamType)
static bool HaveMediaCodec(bool Reinit=false)
static void GetDecoderList(QStringList &Decoders)
static void GetDecoderList(QStringList &Decoders)
static MythCodecID GetSupportedCodec(AVCodecContext **CodecContext, const AVCodec **Codec, const QString &Decoder, AVStream *Stream, uint StreamType)
Determine whether NVDEC decoding is supported for this codec.
static bool HaveNVDEC(bool Reinit=false)
void HandleDecoderCallback(const QString &Debug, DecoderCallback::Callback Function, void *Opaque1, void *Opaque2)
Convenience function to request and wait for a callback into the main thread.
static MythRenderOpenGL * GetOpenGLRender(void)
A handler for V4L2 Memory2Memory codecs.
static MythCodecID GetSupportedCodec(AVCodecContext **Context, const AVCodec **Codec, const QString &Decoder, AVStream *Stream, uint StreamType)
static bool HaveV4L2Codecs(bool Reinit=false)
static void GetDecoderList(QStringList &Decoders)
static QString HaveVAAPI(bool ReCheck=false)
Check whether VAAPI is available and not emulated via VDPAU.
static MythCodecID GetSupportedCodec(AVCodecContext **Context, const AVCodec **Codec, const QString &Decoder, uint StreamType)
Confirm whether VAAPI support is available given Decoder and Context.
static void GetDecoderList(QStringList &Decoders)
static MythCodecID GetSupportedCodec(AVCodecContext **CodecContext, const AVCodec **Codec, const QString &Decoder, uint StreamType)
static bool HaveVDPAU(bool Reinit=false)
static void GetDecoderList(QStringList &Decoders)
static bool HaveVTB(bool Reinit=false)
static MythCodecID GetSupportedCodec(AVCodecContext **Context, const AVCodec **Codec, const QString &Decoder, uint StreamType)
static void GetDecoderList(QStringList &Decoders)
static uint GetNumPlanes(VideoFrameType Type)
static QString FormatDescription(VideoFrameType Type)
std::array< uint8_t *, 4 > m_priv
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
virtual int IncrRef(void)
Increments reference count.
static bool ReinitBuffer(MythVideoFrame *Frame, VideoFrameType Type, MythCodecID CodecID, int Width, int Height)
static MythCodecID GetSupportedCodec(AVCodecContext **Context, const AVCodec **Codec, const QString &decoder, uint stream_type)
static const struct wl_interface * types[]
char * av_make_error_stdstring(std::string &errbuf, int errnum)
A C++ equivalent to av_make_error_string.
int(*)(AVCodecContext *Context) CreateHWDecoder
uint mpeg_version(AVCodecID codec_id)
static bool codec_is_v4l2_dec(MythCodecID id)
static bool codec_is_vdpau_dechw(MythCodecID id)
static bool codec_is_vdpau_hw(MythCodecID id)
static bool codec_is_mediacodec_dec(MythCodecID id)
static bool codec_is_mediacodec(MythCodecID id)
static bool codec_is_vtb_dec(MythCodecID id)
static bool codec_is_dxva2(MythCodecID id)
static bool codec_is_mmal_dec(MythCodecID id)
static bool codec_is_drmprime(MythCodecID id)
static bool codec_is_mmal(MythCodecID id)
static bool codec_is_nvdec(MythCodecID id)
static bool codec_is_vtb(MythCodecID id)
static bool codec_is_v4l2(MythCodecID id)
static bool codec_is_nvdec_dec(MythCodecID id)
static bool codec_is_vaapi(MythCodecID id)
static bool codec_is_vaapi_dec(MythCodecID id)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void(*)(struct AVHWDeviceContext *) FreeAVHWDeviceContext
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
bool HasMythMainWindow(void)
QMap< QString, QStringList > * equiv_decoders