MythTV master
mythdrmprimecontext.cpp
Go to the documentation of this file.
1// MythTV
2#include "libmythbase/mythconfig.h"
4
5#include "avformatdecoder.h"
6#include "mythplayerui.h"
8
9#define LOC QString("DRMPRIMECtx: ")
10
12
14
34 : MythCodecContext(Parent, CodecID)
35{
36}
37
39{
40 if (m_interop)
42}
43
45 const AVCodec **Codec,
46 AVStream *Stream,
47 MythCodecID Successs,
48 MythCodecID Failure,
49 const QString &CodecName,
50 AVPixelFormat Format)
51{
52 // Find decoder
53 QString name = QString((*Codec)->name) + "_" + CodecName;
54 if (name.startsWith("mpeg2video"))
55 name = "mpeg2_" + CodecName;
56 const AVCodec *codec = avcodec_find_decoder_by_name(name.toLocal8Bit());
57 auto *decoder = dynamic_cast<AvFormatDecoder*>(reinterpret_cast<DecoderBase*>((*Context)->opaque));
58 if (!codec || !decoder)
59 {
60 // this shouldn't happen!
61 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to find %1").arg(name));
62 return Failure;
63 }
64
65 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Found FFmpeg decoder '%1'").arg(name));
66 *Codec = codec;
67 decoder->CodecMap()->FreeCodecContext(Stream);
68 *Context = decoder->CodecMap()->GetCodecContext(Stream, *Codec);
69 (*Context)->pix_fmt = Format;
70 return Successs;
71}
72
74 const AVCodec **Codec,
75 const QString &Decoder,
76 AVStream *Stream,
77 uint StreamType)
78{
79 auto success = static_cast<MythCodecID>(kCodec_MPEG1_DRMPRIME + (StreamType - 1));
80 auto failure = static_cast<MythCodecID>(kCodec_MPEG1 + (StreamType - 1));
81
82 // not us
83 if (Decoder != "drmprime")
84 return failure;
85
86 // Direct rendering needs interop support
87 if (!FrameTypeIsSupported(*Context, FMT_DRMPRIME))
88 return failure;
89
90 // check support
91 if (!HavePrimeDecoders((*Codec)->id))
92 return failure;
93
94 QString codecname;
95 {
96 QMutexLocker locker(&s_drmPrimeLock);
97 // just take the first - there should only ever be one
98 if (!s_drmPrimeDecoders.isEmpty())
99 codecname = s_drmPrimeDecoders.first();
100 }
101 if (codecname.isEmpty())
102 return failure;
103
104 // and get the codec
105 return MythDRMPRIMEContext::GetPrimeCodec(Context, Codec, Stream, success,
106 failure, codecname, AV_PIX_FMT_DRM_PRIME);
107}
108
109int MythDRMPRIMEContext::HwDecoderInit(AVCodecContext *Context)
110{
111 if (!Context)
112 return -1;
113 if (Context->pix_fmt != AV_PIX_FMT_DRM_PRIME)
114 return -1;
115
116#if CONFIG_EGL
117 if (auto * player = GetPlayerUI(Context); player != nullptr)
119 m_interop = MythDRMPRIMEInterop::CreateDRM(dynamic_cast<MythRenderOpenGL*>(player->GetRender()), player);
120#endif
121 return m_interop ? 0 : -1;
122}
123
124void MythDRMPRIMEContext::InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
125{
126 if (Context->pix_fmt == AV_PIX_FMT_DRM_PRIME)
127 {
128 DirectRendering = false;
129 Context->get_format = MythDRMPRIMEContext::GetFormat;
130 return;
131 }
132
133 MythCodecContext::InitVideoCodec(Context, SelectedStream, DirectRendering);
134}
135
137{
138 return true;
139}
140
141bool MythDRMPRIMEContext::RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame)
142{
143 // Hrm - Context doesn't have the correct pix_fmt here (v4l2 at least). Bug? Use AvFrame
144 if (AvFrame->format == AV_PIX_FMT_DRM_PRIME)
145 return GetDRMBuffer(Context, Frame, AvFrame, 0);
146 return false;
147}
148
149AVPixelFormat MythDRMPRIMEContext::GetFormat(AVCodecContext */*Context*/, const AVPixelFormat *PixFmt)
150{
151 while (*PixFmt != AV_PIX_FMT_NONE)
152 {
153 if (*PixFmt == AV_PIX_FMT_DRM_PRIME)
154 return AV_PIX_FMT_DRM_PRIME;
155 PixFmt++;
156 }
157 return AV_PIX_FMT_NONE;
158}
159
160bool MythDRMPRIMEContext::GetDRMBuffer(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int /*unused*/)
161{
162 if (!Context || !AvFrame || !Frame)
163 return false;
164
165 if (Frame->m_type != FMT_DRMPRIME || static_cast<AVPixelFormat>(AvFrame->format) != AV_PIX_FMT_DRM_PRIME)
166 {
167 LOG(VB_GENERAL, LOG_ERR, LOC + "Not a DRM PRIME buffer");
168 return false;
169 }
170
171 Frame->m_width = AvFrame->width;
172 Frame->m_height = AvFrame->height;
173 Frame->m_pixFmt = Context->pix_fmt;
174 Frame->m_swPixFmt = Context->sw_pix_fmt;
175 Frame->m_directRendering = true;
176 AvFrame->opaque = Frame;
177
178 // Frame->data[0] holds AVDRMFrameDescriptor
179 Frame->m_buffer = AvFrame->data[0];
180 // Retain the buffer so it is not released before we display it
181 Frame->m_priv[0] = reinterpret_cast<unsigned char*>(av_buffer_ref(AvFrame->buf[0]));
182 // Add interop
183 Frame->m_priv[1] = reinterpret_cast<unsigned char*>(m_interop);
184 // Set the release method
185 AvFrame->buf[1] = av_buffer_create(reinterpret_cast<uint8_t*>(Frame), 0, MythCodecContext::ReleaseBuffer,
186 static_cast<AvFormatDecoder*>(Context->opaque), 0);
187 return true;
188}
189
190bool MythDRMPRIMEContext::HavePrimeDecoders(bool Reinit /*=false*/, AVCodecID Codec /*=AV_CODEC_ID_NONE*/)
191{
192 static bool s_needscheck = true;
193 static QVector<AVCodecID> s_supportedCodecs;
194
195 QMutexLocker locker(&s_drmPrimeLock);
196
197 if (s_needscheck || Reinit)
198 {
199 s_needscheck = false;
200 s_supportedCodecs.clear();
201 s_drmPrimeDecoders.clear();
202
203 const AVCodec* codec = nullptr;
204 void* opaque = nullptr;
205 QStringList debugcodecs;
206
207 while ((codec = av_codec_iterate(&opaque)))
208 {
209 if (!av_codec_is_decoder(codec))
210 continue;
211
212 // Filter out v4l2_m2m decoders - which have their own implementation
213 if (QString(codec->name).contains("v4l2m2m"))
214 continue;
215
216 const AVCodecHWConfig* config = nullptr;
217 for (int i = 0; (config = avcodec_get_hw_config(codec, i)); ++i)
218 {
219 if (config->pix_fmt != AV_PIX_FMT_DRM_PRIME)
220 continue;
221
222 // N.B. no support yet for DRMPRIME codecs using frames and/or
223 // device contexts. None exist yet:)
224 if (config->methods & AV_CODEC_HW_CONFIG_METHOD_INTERNAL)
225 {
226 QStringList name = QString(codec->name).split("_", Qt::SkipEmptyParts);
227 if (name.size() > 1 && !s_drmPrimeDecoders.contains(name[1]))
228 s_drmPrimeDecoders.append(name[1]);
229 if (!s_supportedCodecs.contains(codec->id))
230 {
231 s_supportedCodecs.append(codec->id);
232 debugcodecs.append(avcodec_get_name(codec->id));
233 }
234 }
235 }
236 }
237
238 if (debugcodecs.isEmpty())
239 debugcodecs.append("None");
240 LOG(VB_GENERAL, LOG_INFO, LOC + QString("DRM PRIME codecs supported: %1 %2")
241 .arg(debugcodecs.join(","),
242 s_drmPrimeDecoders.isEmpty() ? "" : QString("using: %1").arg(s_drmPrimeDecoders.join(","))));
243 }
244
245 if (!Codec)
246 return !s_supportedCodecs.isEmpty();
247 return s_supportedCodecs.contains(Codec);
248}
AVFrame AVFrame
A decoder for media files.
static bool FrameTypeIsSupported(AVCodecContext *Context, VideoFrameType Format)
static void ReleaseBuffer(void *Opaque, uint8_t *Data)
static void DestroyInterop(MythInteropGPU *Interop)
virtual void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
static MythPlayerUI * GetPlayerUI(AVCodecContext *Context)
void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering) override
static QStringList s_drmPrimeDecoders
static enum AVPixelFormat GetFormat(AVCodecContext *Context, const AVPixelFormat *PixFmt)
bool DecoderWillResetOnFlush(void) override
static MythCodecID GetSupportedCodec(AVCodecContext **Context, const AVCodec **Codec, const QString &Decoder, AVStream *Stream, uint StreamType)
bool GetDRMBuffer(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame, int)
static bool HavePrimeDecoders(bool Reinit=false, AVCodecID Codec=AV_CODEC_ID_NONE)
MythDRMPRIMEContext(DecoderBase *Parent, MythCodecID CodecID)
static MythCodecID GetPrimeCodec(AVCodecContext **Context, const AVCodec **Codec, AVStream *Stream, MythCodecID Successs, MythCodecID Failure, const QString &CodecName, AVPixelFormat Format)
MythOpenGLInterop * m_interop
int HwDecoderInit(AVCodecContext *Context) override
static QRecursiveMutex s_drmPrimeLock
bool RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame) override
static MythDRMPRIMEInterop * CreateDRM(MythRenderOpenGL *Context, MythPlayerUI *Player)
Create a DRM PRIME interop instance.
unsigned int uint
Definition: freesurround.h:24
MythCodecID
Definition: mythcodecid.h:14
@ kCodec_MPEG1
Definition: mythcodecid.h:24
@ kCodec_MPEG1_DRMPRIME
Definition: mythcodecid.h:280
#define LOC
@ FMT_DRMPRIME
Definition: mythframe.h:63
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39