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