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 
8 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
9 QMutex MythDRMPRIMEContext::s_drmPrimeLock(QMutex::Recursive);
10 #else
12 #endif
13 
15 
35  : MythCodecContext(Parent, CodecID)
36 {
37 }
38 
40 {
41  if (m_interop)
43 }
44 
46  const AVCodec **Codec,
47  AVStream *Stream,
48  MythCodecID Successs,
49  MythCodecID Failure,
50  const QString &CodecName,
51  AVPixelFormat Format)
52 {
53  // Find decoder
54  QString name = QString((*Codec)->name) + "_" + CodecName;
55  if (name.startsWith("mpeg2video"))
56  name = "mpeg2_" + CodecName;
57  const AVCodec *codec = avcodec_find_decoder_by_name(name.toLocal8Bit());
58  auto *decoder = dynamic_cast<AvFormatDecoder*>(reinterpret_cast<DecoderBase*>((*Context)->opaque));
59  if (!codec || !decoder)
60  {
61  // this shouldn't happen!
62  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to find %1").arg(name));
63  return Failure;
64  }
65 
66  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Found FFmpeg decoder '%1'").arg(name));
67  *Codec = codec;
68  decoder->CodecMap()->FreeCodecContext(Stream);
69  *Context = decoder->CodecMap()->GetCodecContext(Stream, *Codec);
70  (*Context)->pix_fmt = Format;
71  return Successs;
72 }
73 
75  const AVCodec **Codec,
76  const QString &Decoder,
77  AVStream *Stream,
78  uint StreamType)
79 {
80  auto success = static_cast<MythCodecID>(kCodec_MPEG1_DRMPRIME + (StreamType - 1));
81  auto failure = static_cast<MythCodecID>(kCodec_MPEG1 + (StreamType - 1));
82 
83  // not us
84  if (Decoder != "drmprime")
85  return failure;
86 
87  // Direct rendering needs interop support
88  if (!FrameTypeIsSupported(*Context, FMT_DRMPRIME))
89  return failure;
90 
91  // check support
92  if (!HavePrimeDecoders((*Codec)->id))
93  return failure;
94 
95  QString codecname;
96  {
97  QMutexLocker locker(&s_drmPrimeLock);
98  // just take the first - there should only ever be one
99  if (!s_drmPrimeDecoders.isEmpty())
100  codecname = s_drmPrimeDecoders.first();
101  }
102  if (codecname.isEmpty())
103  return failure;
104 
105  // and get the codec
106  return MythDRMPRIMEContext::GetPrimeCodec(Context, Codec, Stream, success,
107  failure, codecname, AV_PIX_FMT_DRM_PRIME);
108 }
109 
110 int MythDRMPRIMEContext::HwDecoderInit(AVCodecContext *Context)
111 {
112  if (!Context)
113  return -1;
114  if (Context->pix_fmt != AV_PIX_FMT_DRM_PRIME)
115  return -1;
116 
117 #ifdef USING_EGL
118  if (auto * player = GetPlayerUI(Context); player != nullptr)
119  if (FrameTypeIsSupported(Context, FMT_DRMPRIME))
120  m_interop = MythDRMPRIMEInterop::CreateDRM(dynamic_cast<MythRenderOpenGL*>(player->GetRender()), player);
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;
130  Context->get_format = MythDRMPRIMEContext::GetFormat;
131  return;
132  }
133 
134  MythCodecContext::InitVideoCodec(Context, SelectedStream, DirectRendering);
135 }
136 
138 {
139  return true;
140 }
141 
142 bool MythDRMPRIMEContext::RetrieveFrame(AVCodecContext *Context, MythVideoFrame *Frame, AVFrame *AvFrame)
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, MythVideoFrame *Frame, AVFrame *AvFrame, int /*unused*/)
162 {
163  if (!Context || !AvFrame || !Frame)
164  return false;
165 
166  if (Frame->m_type != 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->m_width = AvFrame->width;
173  Frame->m_height = AvFrame->height;
174  Frame->m_pixFmt = Context->pix_fmt;
175  Frame->m_swPixFmt = Context->sw_pix_fmt;
176  Frame->m_directRendering = true;
177  AvFrame->opaque = Frame;
178  AvFrame->reordered_opaque = Context->reordered_opaque;
179 
180  // Frame->data[0] holds AVDRMFrameDescriptor
181  Frame->m_buffer = AvFrame->data[0];
182  // Retain the buffer so it is not released before we display it
183  Frame->m_priv[0] = reinterpret_cast<unsigned char*>(av_buffer_ref(AvFrame->buf[0]));
184  // Add interop
185  Frame->m_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 
192 bool MythDRMPRIMEContext::HavePrimeDecoders(bool Reinit /*=false*/, AVCodecID Codec /*=AV_CODEC_ID_NONE*/)
193 {
194  static bool s_needscheck = true;
195  static QVector<AVCodecID> s_supportedCodecs;
196 
197  QMutexLocker locker(&s_drmPrimeLock);
198 
199  if (s_needscheck || Reinit)
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 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
229  QStringList name = QString(codec->name).split("_", QString::SkipEmptyParts);
230 #else
231  QStringList name = QString(codec->name).split("_", Qt::SkipEmptyParts);
232 #endif
233  if (name.size() > 1 && !s_drmPrimeDecoders.contains(name[1]))
234  s_drmPrimeDecoders.append(name[1]);
235  if (!s_supportedCodecs.contains(codec->id))
236  {
237  s_supportedCodecs.append(codec->id);
238  debugcodecs.append(avcodec_get_name(codec->id));
239  }
240  }
241  }
242  }
243 
244  if (debugcodecs.isEmpty())
245  debugcodecs.append("None");
246  LOG(VB_GENERAL, LOG_INFO, LOC + QString("DRM PRIME codecs supported: %1 %2")
247  .arg(debugcodecs.join(","),
248  s_drmPrimeDecoders.isEmpty() ? "" : QString("using: %1").arg(s_drmPrimeDecoders.join(","))));
249  }
250 
251  if (!Codec)
252  return !s_supportedCodecs.isEmpty();
253  return s_supportedCodecs.contains(Codec);
254 }
MythDRMPRIMEContext::HavePrimeDecoders
static bool HavePrimeDecoders(bool Reinit=false, AVCodecID Codec=AV_CODEC_ID_NONE)
Definition: mythdrmprimecontext.cpp:192
kCodec_MPEG1_DRMPRIME
@ kCodec_MPEG1_DRMPRIME
Definition: mythcodecid.h:277
MythDRMPRIMEContext::s_drmPrimeDecoders
static QStringList s_drmPrimeDecoders
Definition: mythdrmprimecontext.h:46
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:125
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:74
MythDRMPRIMEContext::GetPrimeCodec
static MythCodecID GetPrimeCodec(AVCodecContext **Context, const AVCodec **Codec, AVStream *Stream, MythCodecID Successs, MythCodecID Failure, const QString &CodecName, AVPixelFormat Format)
Definition: mythdrmprimecontext.cpp:45
MythDRMPRIMEContext::HwDecoderInit
int HwDecoderInit(AVCodecContext *Context) override
Definition: mythdrmprimecontext.cpp:110
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:142
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:150
uint
unsigned int uint
Definition: compat.h:81
MythDRMPRIMEContext::DecoderWillResetOnFlush
bool DecoderWillResetOnFlush(void) override
Definition: mythdrmprimecontext.cpp:137
MythDRMPRIMEContext::m_interop
MythOpenGLInterop * m_interop
Definition: mythdrmprimecontext.h:47
MythRenderOpenGL
Definition: mythrenderopengl.h:100
MythDRMPRIMEContext::MythDRMPRIMEContext
MythDRMPRIMEContext(DecoderBase *Parent, MythCodecID CodecID)
Definition: mythdrmprimecontext.cpp:34
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:161
LOC
#define LOC
Definition: mythdrmprimecontext.cpp:6
MythCodecContext
Definition: mythcodeccontext.h:54
MythVideoFrame
Definition: mythframe.h:88
mythdrmprimecontext.h
MythDRMPRIMEContext::~MythDRMPRIMEContext
~MythDRMPRIMEContext() override
Definition: mythdrmprimecontext.cpp:39
MythDRMPRIMEContext::s_drmPrimeLock
static QRecursiveMutex s_drmPrimeLock
Definition: mythdrmprimecontext.h:44
DecoderBase
Definition: decoderbase.h:120
MythCodecContext::GetPlayerUI
static MythPlayerUI * GetPlayerUI(AVCodecContext *Context)
Definition: mythcodeccontext.cpp:507