MythTV  master
mythmmalinterop.cpp
Go to the documentation of this file.
1 // MythTV
2 #include "videocolourspace.h"
3 #include "fourcc.h"
4 #include "mythmmalinterop.h"
5 
6 extern "C" {
7 #include "libavutil/pixdesc.h"
8 }
9 
10 // EGL
11 #include "mythegldefs.h"
12 
13 #define LOC QString("MMALInterop: ")
14 
16  : MythOpenGLInterop(Context, MMAL)
17 {
18 }
19 
21 {
22  LOG(VB_GENERAL, LOG_INFO, LOC + "Destructor");
23 }
24 
26 {
27  if (FMT_MMAL != Format)
28  return Unsupported;
29 
31  if (!context)
32  return Unsupported;
33 
34  OpenGLLocker locker(context);
35  if (!context->IsEGL())
36  return Unsupported;
37 
38  // MMAL interop only works with the closed source driver
39  QString renderer = reinterpret_cast<const char*>(context->glGetString(GL_RENDERER));
40  if (!renderer.contains("VideoCore", Qt::CaseInsensitive))
41  {
42  LOG(VB_GENERAL, LOG_WARNING, LOC +
43  QString("Interop requires the closed source/Broadcom driver - not '%1'")
44  .arg(renderer));
45  return Unsupported;
46  }
47 
48  return context->hasExtension("GL_OES_EGL_image") ? MMAL : Unsupported;
49 }
50 
52 {
53  if (!Context)
54  return nullptr;
55  if (InteropType == MMAL)
56  return new MythMMALInterop(Context);
57  return nullptr;
58 }
59 
61 {
62  MMAL_BUFFER_HEADER_T* result = nullptr;
63 
64  if ((Frame->pix_fmt != AV_PIX_FMT_MMAL) || (Frame->codec != FMT_MMAL) ||
65  !Frame->buf || !Frame->priv[0])
66  {
67  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Invalid MMAL buffer %1 %2 %3 %4")
68  .arg(Frame->buf != nullptr).arg(Frame->priv[0] != nullptr)
69  .arg(format_description(Frame->codec))
70  .arg(av_get_pix_fmt_name(static_cast<AVPixelFormat>(Frame->pix_fmt))));
71  return result;
72  }
73 
74  // Sanity check the context
75  if (m_context != Context)
76  {
77  LOG(VB_GENERAL, LOG_ERR, LOC + "Mismatched OpenGL contexts!");
78  return result;
79  }
80 
81  // Check size
82  QSize surfacesize(Frame->width, Frame->height);
83  if (m_openglTextureSize != surfacesize)
84  {
85  if (!m_openglTextureSize.isEmpty())
86  LOG(VB_GENERAL, LOG_WARNING, LOC + "Video texture size changed!");
87  m_openglTextureSize = surfacesize;
88  }
89 
90  result = reinterpret_cast<MMAL_BUFFER_HEADER_T*>(Frame->buf);
91  return result;
92 }
93 
95  VideoColourSpace *ColourSpace,
97  FrameScanType Scan)
98 {
99  vector<MythVideoTexture*> result;
100  if (!Frame)
101  return result;
102 
103  MMAL_BUFFER_HEADER_T* buffer = VerifyBuffer(Context, Frame);
104  if (!buffer)
105  return result;
106 
107  // Disallow kernel GLSL deint. There are not enough texture units with the
108  // Broadcom driver and we don't retain references
109  Frame->deinterlace_allowed = (Frame->deinterlace_allowed & ~DEINT_HIGH) | DEINT_MEDIUM;
110 
111  // Update frame colourspace and initialise on first frame
112  if (ColourSpace)
113  {
114  if (m_openglTextures.isEmpty())
116  ColourSpace->UpdateColourSpace(Frame);
117  }
118 
119  // Deinterlacing
120  if (is_interlaced(Scan))
121  {
122  // only shader support for now
124  if (shader)
125  {
126  Frame->deinterlace_double = Frame->deinterlace_double | DEINT_SHADER;
127  }
128  else
129  {
131  if (shader)
132  Frame->deinterlace_single = Frame->deinterlace_single | DEINT_SHADER;
133  }
134  }
135 
136  OpenGLLocker locker(m_context);
137 
138  VideoFrameType format = FMT_YV12;
139  uint count = planes(format);
140 
141  if (m_openglTextures.isEmpty())
142  {
143  vector<QSize> sizes;
144  for (uint plane = 0 ; plane < count; ++plane)
145  {
146  QSize size(width_for_plane(format, Frame->width, plane), height_for_plane(format, Frame->height, plane));
147  sizes.push_back(size);
148  }
149 
150  vector<MythVideoTexture*> textures =
152  if (textures.size() != count)
153  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create all textures");
154 
155  for (uint i = 0; i < textures.size(); ++i)
156  {
157  textures[i]->m_allowGLSLDeint = true;
158  textures[i]->m_flip = false;
159  }
160  m_openglTextures.insert(DUMMY_INTEROP_ID, textures);
161  }
162 
163  if (!m_openglTextures.contains(DUMMY_INTEROP_ID))
164  return result;
166 
167  for (uint plane = 0; plane < result.size(); ++plane)
168  {
169  MythVideoTexture* texture = result[plane];
170  EGLenum target = EGL_IMAGE_BRCM_MULTIMEDIA_Y;
171  if (plane == 1)
173  else if (plane == 2)
175 
176  EGLImageKHR image = m_context->eglCreateImageKHR(m_context->GetEGLDisplay(), EGL_NO_CONTEXT, target,
177  (EGLClientBuffer)buffer->data, nullptr);
178  if (!image)
179  LOG(VB_GENERAL, LOG_ERR, LOC + QString("No EGLImage for plane %1 %2")
180  .arg(plane).arg(m_context->GetEGLError()));
181 
182  m_context->glBindTexture(texture->m_target, texture->m_textureId);
184  m_context->glBindTexture(texture->m_target, 0);
186  }
187 
188  return result;
189 }
VideoColourSpace contains a QMatrix4x4 that can convert YCbCr data to RGB.
static vector< MythVideoTexture * > CreateTextures(MythRenderOpenGL *Context, VideoFrameType Type, VideoFrameType Format, vector< QSize > Sizes, GLenum Target=QOpenGLTexture::Target2D)
Create a set of textures suitable for the given Type and Format.
void eglDestroyImageKHR(void *Disp, void *Image)
Definition: mythegl.cpp:160
MythDeintType GetDoubleRateOption(const VideoFrame *Frame, MythDeintType Type, MythDeintType Override)
Definition: mythframe.cpp:847
virtual ~MythMMALInterop() override
MMAL_BUFFER_HEADER_T * VerifyBuffer(MythRenderOpenGL *Context, VideoFrame *Frame)
QHash< QString, Action * > Context
Definition: action.h:77
#define EGL_IMAGE_BRCM_MULTIMEDIA_V
Definition: mythegldefs.h:18
static qint32 GetEGLError(void)
Definition: mythegl.cpp:137
void * eglCreateImageKHR(void *Disp, void *Context, unsigned int Target, void *Buffer, const int32_t *Attributes)
Definition: mythegl.cpp:152
#define DUMMY_INTEROP_ID
#define GL_TEXTURE_EXTERNAL_OES
FrameScanType
Definition: videoouttypes.h:78
VideoFrameType
Definition: mythframe.h:23
MythMMALInterop(MythRenderOpenGL *Context)
virtual vector< MythVideoTexture * > Acquire(MythRenderOpenGL *Context, VideoColourSpace *ColourSpace, VideoFrame *Frame, FrameScanType Scan) override
#define EGL_IMAGE_BRCM_MULTIMEDIA_Y
Definition: mythegldefs.h:12
static uint planes(VideoFrameType Type)
Definition: mythframe.h:569
#define LOC
MythDeintType
Definition: mythframe.h:120
static int height_for_plane(VideoFrameType Type, int Height, uint Plane)
Definition: mythframe.h:439
void eglImageTargetTexture2DOES(GLenum Target, void *Image)
Definition: mythegl.cpp:146
unsigned int uint
Definition: compat.h:140
static Type GetInteropType(VideoFrameType Format)
#define ALL_PICTURE_ATTRIBUTES
void * GetEGLDisplay(void)
Definition: mythegl.cpp:80
#define EGL_IMAGE_BRCM_MULTIMEDIA_U
Definition: mythegldefs.h:15
void SetSupportedAttributes(PictureAttributeSupported Supported)
Enable the given set of picture attributes.
MythRenderOpenGL * m_context
static MythRenderOpenGL * GetOpenGLRender(void)
QHash< unsigned long long, vector< MythVideoTexture * > > m_openglTextures
const char * format_description(VideoFrameType Type)
Definition: mythframe.cpp:33
static int width_for_plane(VideoFrameType Type, int Width, uint Plane)
Definition: mythframe.h:394
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.
static MythMMALInterop * Create(MythRenderOpenGL *Context, Type InteropType)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23