MythTV  master
mythdrmprimeinterop.cpp
Go to the documentation of this file.
1 // MythTV
2 #include "videocolourspace.h"
3 #include "mythdrmprimeinterop.h"
4 
5 // FFmpeg
6 extern "C" {
7 #include "libavutil/hwcontext_drm.h"
8 #include "libavutil/pixdesc.h"
9 }
10 
11 #define LOC QString("DRMInterop: ")
12 
14  : MythOpenGLInterop(Context, DRMPRIME),
16 {
17 }
18 
20 {
22 }
23 
25 {
26  OpenGLLocker locker(m_context);
27 
28  if (!m_openglTextures.isEmpty() && m_context->IsEGL())
29  {
30  int count = 0;
31  for (auto it = m_openglTextures.constBegin(); it != m_openglTextures.constEnd(); ++it)
32  {
33  vector<MythVideoTexture*> textures = it.value();
34  for (auto & texture : textures)
35  {
36  if (texture->m_data)
37  {
39  texture->m_data = nullptr;
40  count++;
41  }
42  }
43  }
44  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Deleted %1 EGL images in %2 groups")
45  .arg(count).arg(m_openglTextures.size()));
46  }
47 
49 }
50 
52 {
53  if (Context && (InteropType == DRMPRIME))
54  return new MythDRMPRIMEInterop(Context);
55  return nullptr;
56 }
57 
59 {
60  if (FMT_DRMPRIME != Format)
61  return Unsupported;
63  if (!context)
64  return Unsupported;
65  return HaveDMABuf(context) ? DRMPRIME : Unsupported;
66 }
67 
69 {
70  AVDRMFrameDescriptor* result = nullptr;
71 
72  if ((Frame->pix_fmt != AV_PIX_FMT_DRM_PRIME) || (Frame->codec != FMT_DRMPRIME) ||
73  !Frame->buf || !Frame->priv[0])
74  {
75  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Invalid DRM PRIME buffer %1 %2 %3 %4")
76  .arg(Frame->buf != nullptr).arg(Frame->priv[0] != nullptr)
77  .arg(format_description(Frame->codec))
78  .arg(av_get_pix_fmt_name(static_cast<AVPixelFormat>(Frame->pix_fmt))));
79  return result;
80  }
81 
82  // Sanity check the context
83  if (m_context != Context)
84  {
85  LOG(VB_GENERAL, LOG_ERR, LOC + "Mismatched OpenGL contexts!");
86  return result;
87  }
88 
89  // Check size
90  QSize surfacesize(Frame->width, Frame->height);
91  if (m_openglTextureSize != surfacesize)
92  {
93  if (!m_openglTextureSize.isEmpty())
94  LOG(VB_GENERAL, LOG_WARNING, LOC + "Video texture size changed!");
95  m_openglTextureSize = surfacesize;
96  }
97 
98  return reinterpret_cast<AVDRMFrameDescriptor*>(Frame->buf);
99 }
100 
102  VideoColourSpace *ColourSpace,
103  VideoFrame *Frame,
104  FrameScanType Scan)
105 {
106  vector<MythVideoTexture*> result;
107  if (!Frame)
108  return result;
109 
110  auto *drmdesc = VerifyBuffer(Context, Frame);
111  if (!drmdesc)
112  return result;
113 
114  bool firstpass = m_openglTextures.isEmpty();
115  bool interlaced = is_interlaced(Scan);
116  bool composed = static_cast<uint>(drmdesc->nb_layers) == 1 && m_composable;
117  auto id = reinterpret_cast<unsigned long long>(drmdesc);
118 
119  auto Separate = [=]()
120  {
121  vector<MythVideoTexture*> textures;
122  if (!m_openglTextures.contains(id))
123  {
124  textures = CreateTextures(drmdesc, m_context, Frame, true);
125  m_openglTextures.insert(id, textures);
126  }
127  else
128  {
129  textures = m_openglTextures[id];
130  }
131 
132  if (textures.empty() ? false : format_is_yuv(textures[0]->m_frameFormat))
133  {
134  // Enable colour controls for YUV frame
135  if (firstpass)
137  ColourSpace->UpdateColourSpace(Frame);
138  // and shader based deinterlacing
139  Frame->deinterlace_allowed = Frame->deinterlace_allowed | DEINT_SHADER;
140  }
141  return textures;
142  };
143 
144  // Separate texture for each plane
145  if (!composed)
146  return Separate();
147 
148  // Single RGB texture
149  // Disable picture attributes
150  if (firstpass)
152 
153  // Is deinterlacing selected? Accept any value as RGB frames can only be deinterlaced here
154  bool doublerate = false;
156  if (option != DEINT_NONE)
157  doublerate = true;
158  else
160  interlaced &= option != DEINT_NONE;
161 
162  // Clear redundant frame caches
163  if (interlaced && !m_deinterlacing)
164  {
165  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Clearing progessive frame cache");
166  DeleteTextures();
167  }
168  else if (m_deinterlacing && !interlaced)
169  {
170  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Clearing interlaced field cache");
171  DeleteTextures();
172  }
173  m_deinterlacing = interlaced;
174 
175  if (!m_openglTextures.contains(id))
176  {
177  // This will create 2 half height textures representing the top and bottom fields
178  // if deinterlacing
179  result = CreateTextures(drmdesc, m_context, Frame, false,
181  // Fallback to separate textures if the driver does not support composition
182  if (result.empty())
183  {
184  m_composable = false;
185  m_deinterlacing = false;
186  DeleteTextures();
187  LOG(VB_GENERAL, LOG_INFO, LOC + "YUV composition failed. Trying separate textures.");
188  return Separate();
189  }
190  m_openglTextures.insert(id, result);
191  }
192  else
193  {
194  result = m_openglTextures[id];
195  }
196 
197  if (m_deinterlacing)
198  {
199  result.clear();
200  Frame->deinterlace_inuse = DEINT_DRIVER | DEINT_BASIC;
201  Frame->deinterlace_inuse2x = doublerate;
202  bool tff = Frame->interlaced_reversed ? !Frame->top_field_first : Frame->top_field_first;
203  result.emplace_back(m_openglTextures[id].at(Scan == kScan_Interlaced ? (tff ? 1 : 0) : tff ? 0 : 1));
204  }
205 
206  return result;
207 }
208 
VideoColourSpace contains a QMatrix4x4 that can convert YCbCr data to RGB.
AVDRMFrameDescriptor * VerifyBuffer(MythRenderOpenGL *Context, VideoFrame *Frame)
static bool format_is_yuv(VideoFrameType Type)
Definition: mythframe.h:114
void eglDestroyImageKHR(void *Disp, void *Image)
Definition: mythegl.cpp:160
MythDeintType GetDoubleRateOption(const VideoFrame *Frame, MythDeintType Type, MythDeintType Override)
Definition: mythframe.cpp:847
QHash< QString, Action * > Context
Definition: action.h:77
FrameScanType
Definition: videoouttypes.h:78
VideoFrameType
Definition: mythframe.h:23
MythDeintType
Definition: mythframe.h:120
static Type GetInteropType(VideoFrameType Format)
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
static bool HaveDMABuf(MythRenderOpenGL *Context)
static MythDRMPRIMEInterop * Create(MythRenderOpenGL *Context, Type InteropType)
vector< MythVideoTexture * > Acquire(MythRenderOpenGL *Context, VideoColourSpace *ColourSpace, VideoFrame *Frame, FrameScanType Scan) override
#define ALL_PICTURE_ATTRIBUTES
void * GetEGLDisplay(void)
Definition: mythegl.cpp:80
void DeleteTextures(void) override
#define LOC
MythDRMPRIMEInterop(MythRenderOpenGL *Context)
void SetSupportedAttributes(PictureAttributeSupported Supported)
Enable the given set of picture attributes.
virtual void DeleteTextures(void)
MythRenderOpenGL * m_context
vector< MythVideoTexture * > CreateTextures(AVDRMFrameDescriptor *Desc, MythRenderOpenGL *Context, VideoFrame *Frame, bool UseSeparate, FrameScanType Scan=kScan_Progressive)
static MythRenderOpenGL * GetOpenGLRender(void)
QHash< unsigned long long, vector< MythVideoTexture * > > m_openglTextures
const char * format_description(VideoFrameType Type)
Definition: mythframe.cpp:33
bool is_interlaced(FrameScanType Scan)
bool IsEGL(void)
Definition: mythegl.cpp:29
MythDeintType GetSingleRateOption(const VideoFrame *Frame, MythDeintType Type, MythDeintType Override)
Definition: mythframe.cpp:834
bool UpdateColourSpace(const VideoFrame *Frame)
Set the current colourspace to use.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23