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