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