MythTV  master
mythdrmprimeinterop.cpp
Go to the documentation of this file.
1 // MythTV
2 #include "mythplayerui.h"
3 #include "mythvideocolourspace.h"
4 #include "mythdrmprimeinterop.h"
5 
6 #ifdef USING_DRM_VIDEO
9 #endif
10 
11 // FFmpeg
12 extern "C" {
13 #include "libavutil/hwcontext_drm.h"
14 #include "libavutil/pixdesc.h"
15 }
16 
17 #define LOC QString("DRMInterop: ")
18 
20  : MythOpenGLInterop(Context, Type, Player),
21  MythEGLDMABUF(Context)
22 {
23 }
24 
26 {
27 #ifdef USING_DRM_VIDEO
28  delete m_drm;
29 #endif
31 }
32 
34 {
36 
37  if (!m_openglTextures.isEmpty() && m_openglContext->IsEGL())
38  {
39  int count = 0;
40  for (auto it = m_openglTextures.constBegin(); it != m_openglTextures.constEnd(); ++it)
41  {
42  std::vector<MythVideoTextureOpenGL*> textures = it.value();
43  for (auto & texture : textures)
44  {
45  if (texture->m_data)
46  {
48  texture->m_data = nullptr;
49  count++;
50  }
51  }
52  }
53  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Deleted %1 EGL images in %2 groups")
54  .arg(count).arg(m_openglTextures.size()));
55  }
56 
58 }
59 
63 {
64  if (!(Player && Context))
65  return nullptr;
66 
67  const auto & types = Player->GetInteropTypes();
68  if (const auto & drm = types.find(FMT_DRMPRIME); drm != types.cend())
69  {
70  auto matchType = [](auto type){ return (type == GL_DRMPRIME) || (type == DRM_DRMPRIME); };
71  auto it = std::find_if(drm->second.cbegin(), drm->second.cend(), matchType);
72  if (it != drm->second.cend())
73  return new MythDRMPRIMEInterop(Context, Player, *it);
74  }
75  return nullptr;
76 }
77 
79 {
81 
82 #ifdef USING_DRM_VIDEO
84  drmtypes.emplace_back(DRM_DRMPRIME);
85 #endif
86 
87  if (HaveDMABuf(Render))
88  drmtypes.emplace_back(GL_DRMPRIME);
89 
90  if (!drmtypes.empty())
91  Types[FMT_DRMPRIME] = drmtypes;
92 }
93 
95 {
96  AVDRMFrameDescriptor* result = nullptr;
97 
98  if ((Frame->m_pixFmt != AV_PIX_FMT_DRM_PRIME) || (Frame->m_type != FMT_DRMPRIME) ||
99  !Frame->m_buffer || !Frame->m_priv[0])
100  {
101  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Invalid DRM PRIME buffer %1 %2 %3 %4")
102  .arg(Frame->m_buffer != nullptr).arg(Frame->m_priv[0] != nullptr)
104  av_get_pix_fmt_name(static_cast<AVPixelFormat>(Frame->m_pixFmt))));
105  return result;
106  }
107 
108  // Sanity check the context
109  if (m_openglContext != Context)
110  {
111  LOG(VB_GENERAL, LOG_ERR, LOC + "Mismatched OpenGL contexts!");
112  return result;
113  }
114 
115  // Check size
116  QSize surfacesize(Frame->m_width, Frame->m_height);
117  if (m_textureSize != surfacesize)
118  {
119  if (!m_textureSize.isEmpty())
120  LOG(VB_GENERAL, LOG_WARNING, LOC + "Video texture size changed!");
121  m_textureSize = surfacesize;
122  }
123 
124  return reinterpret_cast<AVDRMFrameDescriptor*>(Frame->m_buffer);
125 }
126 
127 std::vector<MythVideoTextureOpenGL*>
129  MythVideoColourSpace *ColourSpace,
131  FrameScanType Scan)
132 {
133  std::vector<MythVideoTextureOpenGL*> result;
134  if (!Frame)
135  return result;
136 
137  auto * drmdesc = VerifyBuffer(Context, Frame);
138  if (!drmdesc)
139  return result;
140 
141 #ifdef USING_DRM_VIDEO
142  if (HandleDRMVideo(ColourSpace, Frame, drmdesc))
143  return result;
144 #endif
145 
146  bool firstpass = m_openglTextures.isEmpty();
147  bool interlaced = is_interlaced(Scan);
148  bool composed = static_cast<uint>(drmdesc->nb_layers) == 1 && m_composable;
149  auto id = reinterpret_cast<unsigned long long>(drmdesc);
150 
151  auto Separate = [this, id, drmdesc, Frame, firstpass, ColourSpace]()
152  {
153  std::vector<MythVideoTextureOpenGL*> textures;
154  if (!m_openglTextures.contains(id))
155  {
156  textures = CreateTextures(drmdesc, m_openglContext, Frame, true);
157  m_openglTextures.insert(id, textures);
158  }
159  else
160  {
161  textures = m_openglTextures[id];
162  }
163 
164  if (textures.empty() ? false : MythVideoFrame::YUVFormat(textures[0]->m_frameFormat))
165  {
166  // Enable colour controls for YUV frame
167  if (firstpass)
169  ColourSpace->UpdateColourSpace(Frame);
170  // and shader based deinterlacing
171  Frame->m_deinterlaceAllowed = Frame->m_deinterlaceAllowed | DEINT_SHADER;
172  }
173  return textures;
174  };
175 
176  // Separate texture for each plane
177  if (!composed)
178  return Separate();
179 
180  // Single RGB texture
181  // Disable picture attributes
182  if (firstpass)
184 
185  // Is deinterlacing selected? Accept any value as RGB frames can only be deinterlaced here
186  bool doublerate = false;
187  MythDeintType option = Frame->GetDoubleRateOption(DEINT_CPU | DEINT_SHADER | DEINT_DRIVER, DEINT_ALL);
188  if (option != DEINT_NONE)
189  doublerate = true;
190  else
191  option = Frame->GetSingleRateOption(DEINT_CPU | DEINT_SHADER | DEINT_DRIVER, DEINT_ALL);
192  interlaced &= option != DEINT_NONE;
193 
194  // Clear redundant frame caches
195  if (interlaced && !m_deinterlacing)
196  {
197  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Clearing progessive frame cache");
198  DeleteTextures();
199  }
200  else if (m_deinterlacing && !interlaced)
201  {
202  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Clearing interlaced field cache");
203  DeleteTextures();
204  }
205  m_deinterlacing = interlaced;
206 
207  if (!m_openglTextures.contains(id))
208  {
209  // This will create 2 half height textures representing the top and bottom fields
210  // if deinterlacing
211  result = CreateTextures(drmdesc, m_openglContext, Frame, false,
213  // Fallback to separate textures if the driver does not support composition
214  if (result.empty())
215  {
216  m_composable = false;
217  m_deinterlacing = false;
218  DeleteTextures();
219  LOG(VB_GENERAL, LOG_INFO, LOC + "YUV composition failed. Trying separate textures.");
220  return Separate();
221  }
222  m_openglTextures.insert(id, result);
223  }
224  else
225  {
226  result = m_openglTextures[id];
227  }
228 
229  if (m_deinterlacing)
230  {
231  result.clear();
232  Frame->m_deinterlaceInuse = DEINT_DRIVER | DEINT_BASIC;
233  Frame->m_deinterlaceInuse2x = doublerate;
234  bool tff = Frame->m_interlacedReverse ? !Frame->m_topFieldFirst : Frame->m_topFieldFirst;
235  int value {0};
236  if (Scan == kScan_Interlaced)
237  value = tff ? 1 : 0;
238  else
239  value = tff ? 0 : 1;
240  result.emplace_back(m_openglTextures[id].at(value));
241  }
242 
243  return result;
244 }
245 
246 #ifdef USING_DRM_VIDEO
247 bool MythDRMPRIMEInterop::HandleDRMVideo(MythVideoColourSpace* ColourSpace, MythVideoFrame* Frame,
248  AVDRMFrameDescriptor* DRMDesc)
249 {
250  if (!((m_type == DRM_DRMPRIME) && !m_drmTriedAndFailed && Frame && DRMDesc && ColourSpace))
251  return false;
252 
253  if (!m_drm)
254  m_drm = new MythVideoDRM(ColourSpace);
255 
256  if (m_drm)
257  {
258  if (m_drm->IsValid())
259  {
260  ColourSpace->UpdateColourSpace(Frame);
261  if (m_drm->RenderFrame(DRMDesc, Frame))
262  return true;
263  }
264 
265  // RenderFrame may have decided we should give up
266  if (!m_drm->IsValid())
267  {
268  LOG(VB_GENERAL, LOG_INFO, LOC + "Disabling DRM video");
269  m_drmTriedAndFailed = true;
270  delete m_drm;
271  m_drm = nullptr;
272  }
273  }
274  return false;
275 }
276 #endif
MythInteropGPU::m_type
InteropType m_type
Definition: mythinteropgpu.h:67
mythplayerui.h
LOC
#define LOC
Definition: mythdrmprimeinterop.cpp:17
MythDRMPRIMEInterop::CreateDRM
static MythDRMPRIMEInterop * CreateDRM(MythRenderOpenGL *Context, MythPlayerUI *Player)
Create a DRM PRIME interop instance.
Definition: mythdrmprimeinterop.cpp:62
MythDRMPRIMEInterop::GetDRMTypes
static void GetDRMTypes(MythRenderOpenGL *Render, MythInteropGPU::InteropMap &Types)
Definition: mythdrmprimeinterop.cpp:78
MythDRMPRIMEInterop
Definition: mythdrmprimeinterop.h:14
MythEGL::GetEGLDisplay
void * GetEGLDisplay(void)
Definition: mythegl.cpp:76
kScan_Progressive
@ kScan_Progressive
Definition: videoouttypes.h:100
Frame
Definition: zmdefines.h:93
MythDRMPRIMEInterop::DeleteTextures
void DeleteTextures(void) override
Definition: mythdrmprimeinterop.cpp:33
MythVideoColourSpace::UpdateColourSpace
bool UpdateColourSpace(const MythVideoFrame *Frame)
Set the current colourspace to use.
Definition: mythvideocolourspace.cpp:337
types
static const struct wl_interface * types[]
Definition: idle_inhibit_unstable_v1.c:39
MythVideoColourSpace::SetSupportedAttributes
void SetSupportedAttributes(PictureAttributeSupported Supported)
Enable the given set of picture attributes.
Definition: mythvideocolourspace.cpp:111
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythEGLDMABUF
Definition: mythegldmabuf.h:15
MythEGLDMABUF::HaveDMABuf
static bool HaveDMABuf(MythRenderOpenGL *Context)
Definition: mythegldmabuf.cpp:26
MythEGL::eglDestroyImageKHR
void eglDestroyImageKHR(void *Disp, void *Image)
Definition: mythegl.cpp:156
MythDeintType
MythDeintType
Definition: mythframe.h:67
MythInteropGPU::InteropMap
std::map< VideoFrameType, InteropTypes > InteropMap
Definition: mythinteropgpu.h:44
MythDRMPRIMEInterop::m_composable
bool m_composable
Definition: mythdrmprimeinterop.h:32
MythVideoFrame::YUVFormat
static bool YUVFormat(VideoFrameType Type)
Definition: mythframe.h:466
MythPlayerUI
Definition: mythplayerui.h:12
MythInteropGPU::DRM_DRMPRIME
@ DRM_DRMPRIME
Definition: mythinteropgpu.h:38
mythvideocolourspace.h
MythEGLDMABUF::CreateTextures
std::vector< MythVideoTextureOpenGL * > CreateTextures(AVDRMFrameDescriptor *Desc, MythRenderOpenGL *Context, MythVideoFrame *Frame, bool UseSeparate, FrameScanType Scan=kScan_Progressive)
Definition: mythegldmabuf.cpp:372
MythOpenGLInterop
Definition: mythopenglinterop.h:17
MythOpenGLInterop::m_openglContext
MythRenderOpenGL * m_openglContext
Definition: mythopenglinterop.h:41
MythInteropGPU::InteropType
InteropType
Definition: mythinteropgpu.h:25
MythInteropGPU::GL_DRMPRIME
@ GL_DRMPRIME
Definition: mythinteropgpu.h:37
DEINT_ALL
@ DEINT_ALL
Definition: mythframe.h:76
mythdisplaydrm.h
DEINT_DRIVER
@ DEINT_DRIVER
Definition: mythframe.h:75
DEINT_SHADER
@ DEINT_SHADER
Definition: mythframe.h:74
DEINT_BASIC
@ DEINT_BASIC
Definition: mythframe.h:70
FMT_DRMPRIME
@ FMT_DRMPRIME
Definition: mythframe.h:64
MythVideoDRM
Definition: mythvideodrm.h:14
MythEGL::IsEGL
bool IsEGL(void)
Definition: mythegl.cpp:29
MythDRMPRIMEInterop::m_deinterlacing
bool m_deinterlacing
Definition: mythdrmprimeinterop.h:31
uint
unsigned int uint
Definition: compat.h:81
DEINT_NONE
@ DEINT_NONE
Definition: mythframe.h:69
DEINT_CPU
@ DEINT_CPU
Definition: mythframe.h:73
ALL_PICTURE_ATTRIBUTES
#define ALL_PICTURE_ATTRIBUTES
Definition: videoouttypes.h:127
MythOpenGLInterop::m_openglTextures
QHash< unsigned long long, std::vector< MythVideoTextureOpenGL * > > m_openglTextures
Definition: mythopenglinterop.h:42
kScan_Interlaced
@ kScan_Interlaced
Definition: videoouttypes.h:98
MythRenderOpenGL
Definition: mythrenderopengl.h:96
kPictureAttributeSupported_None
@ kPictureAttributeSupported_None
Definition: videoouttypes.h:118
MythDisplayDRM::DirectRenderingAvailable
static bool DirectRenderingAvailable()
Definition: mythdisplaydrm.cpp:17
MythVideoFrame::FormatDescription
static QString FormatDescription(VideoFrameType Type)
Definition: mythframe.cpp:368
MythOpenGLInterop::DeleteTextures
virtual void DeleteTextures()
Definition: mythopenglinterop.cpp:138
MythDRMPRIMEInterop::Acquire
std::vector< MythVideoTextureOpenGL * > Acquire(MythRenderOpenGL *Context, MythVideoColourSpace *ColourSpace, MythVideoFrame *Frame, FrameScanType Scan) override
Definition: mythdrmprimeinterop.cpp:128
MythDRMPRIMEInterop::VerifyBuffer
AVDRMFrameDescriptor * VerifyBuffer(MythRenderOpenGL *Context, MythVideoFrame *Frame)
Definition: mythdrmprimeinterop.cpp:94
mythdrmprimeinterop.h
MythDRMPRIMEInterop::~MythDRMPRIMEInterop
~MythDRMPRIMEInterop() override
Definition: mythdrmprimeinterop.cpp:25
FrameScanType
FrameScanType
Definition: videoouttypes.h:94
Player
Definition: zmliveplayer.h:34
MythVideoFrame
Definition: mythframe.h:88
mythmainwindow.h
MythInteropGPU::m_textureSize
QSize m_textureSize
Definition: mythinteropgpu.h:62
is_interlaced
bool is_interlaced(FrameScanType Scan)
Definition: videoouttypes.h:188
MythDRMPRIMEInterop::MythDRMPRIMEInterop
MythDRMPRIMEInterop(MythRenderOpenGL *Context, MythPlayerUI *Player, InteropType Type)
Definition: mythdrmprimeinterop.cpp:19
MythVideoColourSpace
MythVideoColourSpace contains a QMatrix4x4 that can convert YCbCr data to RGB.
Definition: mythvideocolourspace.h:18
MythInteropGPU::InteropTypes
std::vector< InteropType > InteropTypes
Definition: mythinteropgpu.h:43
OpenGLLocker
Definition: mythrenderopengl.h:255