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  AvFormatDecoder *decoder = dynamic_cast<AvFormatDecoder*>(reinterpret_cast<DecoderBase*>((*Context)->opaque));
53  if (!codec || !decoder)
54  {
55  // this shouldn't happen!
56  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to find %1").arg(name));
57  return Failure;
58  }
59 
60  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Found FFmpeg decoder '%1'").arg(name));
61  *Codec = codec;
62  decoder->CodecMap()->freeCodecContext(Stream);
63  *Context = decoder->CodecMap()->getCodecContext(Stream, *Codec);
64  (*Context)->pix_fmt = Format;
65  return Successs;
66 }
67 
69  AVCodec **Codec,
70  const QString &Decoder,
71  AVStream *Stream,
72  uint StreamType)
73 {
74  auto success = static_cast<MythCodecID>(kCodec_MPEG1_DRMPRIME + (StreamType - 1));
75  auto failure = static_cast<MythCodecID>(kCodec_MPEG1 + (StreamType - 1));
76 
77  // not us
78  if (Decoder != "drmprime")
79  return failure;
80 
81  // direct rendering needs interop support
82  MythPlayer* player = nullptr;
83  if (!gCoreContext->IsUIThread())
84  {
85  auto* decoder = reinterpret_cast<AvFormatDecoder*>((*Context)->opaque);
86  if (decoder)
87  player = decoder->GetPlayer();
88  }
89 
91  return failure;
92 
93  // check support
94  if (!HavePrimeDecoders((*Codec)->id))
95  return failure;
96 
97  QString codecname;
98  {
99  QMutexLocker locker(&s_drmPrimeLock);
100  // just take the first - there should only ever be one
101  if (!s_drmPrimeDecoders.isEmpty())
102  codecname = s_drmPrimeDecoders.first();
103  }
104  if (codecname.isEmpty())
105  return failure;
106 
107  // and get the codec
108  return MythDRMPRIMEContext::GetPrimeCodec(Context, Codec, Stream, success,
109  failure, codecname, AV_PIX_FMT_DRM_PRIME);
110 }
111 
113 {
114  if (!Context)
115  return -1;
116  if (Context->pix_fmt != AV_PIX_FMT_DRM_PRIME)
117  return -1;
118 
119 #ifdef USING_EGL
122 #endif
123  return m_interop ? 0 : -1;
124 }
125 
126 void MythDRMPRIMEContext::InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
127 {
128  if (Context->pix_fmt == AV_PIX_FMT_DRM_PRIME)
129  {
130  DirectRendering = false;
132  return;
133  }
134 
135  MythCodecContext::InitVideoCodec(Context, SelectedStream, DirectRendering);
136 }
137 
139 {
140  return true;
141 }
142 
144 {
145  // Hrm - Context doesn't have the correct pix_fmt here (v4l2 at least). Bug? Use AvFrame
146  if (AvFrame->format == AV_PIX_FMT_DRM_PRIME)
147  return GetDRMBuffer(Context, Frame, AvFrame, 0);
148  return false;
149 }
150 
151 AVPixelFormat MythDRMPRIMEContext::GetFormat(AVCodecContext */*Context*/, const AVPixelFormat *PixFmt)
152 {
153  while (*PixFmt != AV_PIX_FMT_NONE)
154  {
155  if (*PixFmt == AV_PIX_FMT_DRM_PRIME)
156  return AV_PIX_FMT_DRM_PRIME;
157  PixFmt++;
158  }
159  return AV_PIX_FMT_NONE;
160 }
161 
162 bool MythDRMPRIMEContext::GetDRMBuffer(AVCodecContext *Context, VideoFrame *Frame, AVFrame *AvFrame, int /*unused*/)
163 {
164  if (!Context || !AvFrame || !Frame)
165  return false;
166 
167  if (Frame->codec != FMT_DRMPRIME || static_cast<AVPixelFormat>(AvFrame->format) != AV_PIX_FMT_DRM_PRIME)
168  {
169  LOG(VB_GENERAL, LOG_ERR, LOC + "Not a DRM PRIME buffer");
170  return false;
171  }
172 
173  Frame->width = AvFrame->width;
174  Frame->height = AvFrame->height;
175  Frame->pix_fmt = Context->pix_fmt;
176  Frame->sw_pix_fmt = Context->sw_pix_fmt;
177  Frame->directrendering = 1;
178  AvFrame->opaque = Frame;
179  AvFrame->reordered_opaque = Context->reordered_opaque;
180 
181  // Frame->data[0] holds AVDRMFrameDescriptor
182  Frame->buf = AvFrame->data[0];
183  // Retain the buffer so it is not released before we display it
184  Frame->priv[0] = reinterpret_cast<unsigned char*>(av_buffer_ref(AvFrame->buf[0]));
185  // Add interop
186  Frame->priv[1] = reinterpret_cast<unsigned char*>(m_interop);
187  // Set the release method
188  AvFrame->buf[1] = av_buffer_create(reinterpret_cast<uint8_t*>(Frame), 0, MythCodecContext::ReleaseBuffer,
189  static_cast<AvFormatDecoder*>(Context->opaque), 0);
190  return true;
191 }
192 
194 {
195  static bool s_needscheck = true;
196  static QVector<AVCodecID> s_supportedCodecs;
197 
198  QMutexLocker locker(&s_drmPrimeLock);
199 
200  if (s_needscheck)
201  {
202  s_needscheck = false;
203  s_supportedCodecs.clear();
204  s_drmPrimeDecoders.clear();
205 
206  const AVCodec* codec = nullptr;
207  void* opaque = nullptr;
208  QStringList debugcodecs;
209 
210  while ((codec = av_codec_iterate(&opaque)))
211  {
212  if (!av_codec_is_decoder(codec))
213  continue;
214 
215  // Filter out v4l2_m2m decoders - which have their own implementation
216  if (QString(codec->name).contains("v4l2m2m"))
217  continue;
218 
219  const AVCodecHWConfig* config = nullptr;
220  for (int i = 0; (config = avcodec_get_hw_config(codec, i)); ++i)
221  {
222  if (config->pix_fmt != AV_PIX_FMT_DRM_PRIME)
223  continue;
224 
225  // N.B. no support yet for DRMPRIME codecs using frames and/or
226  // device contexts. None exist yet:)
227  if (config->methods & AV_CODEC_HW_CONFIG_METHOD_INTERNAL)
228  {
229  QStringList name = QString(codec->name).split("_", QString::SkipEmptyParts);
230  if (name.size() > 1 && !s_drmPrimeDecoders.contains(name[1]))
231  s_drmPrimeDecoders.append(name[1]);
232  if (!s_supportedCodecs.contains(codec->id))
233  {
234  s_supportedCodecs.append(codec->id);
235  debugcodecs.append(avcodec_get_name(codec->id));
236  }
237  }
238  }
239  }
240 
241  if (debugcodecs.isEmpty())
242  debugcodecs.append("None");
243  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("DRM PRIME codecs supported: %1 %2")
244  .arg(debugcodecs.join(","))
245  .arg(s_drmPrimeDecoders.isEmpty() ? "" : QString("using: %1").arg(s_drmPrimeDecoders.join(","))));
246  }
247 
248  if (!Codec)
249  return !s_supportedCodecs.isEmpty();
250  return s_supportedCodecs.contains(Codec);
251 }
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
static bool HavePrimeDecoders(AVCodecID Codec=AV_CODEC_ID_NONE)
static QMutex s_drmPrimeLock
static enum AVPixelFormat GetFormat(AVCodecContext *Context, const AVPixelFormat *PixFmt)
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)
A decoder for video files.
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