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