MythTV  master
mythvtbinterop.cpp
Go to the documentation of this file.
1 // MythTV
4 #include "mythvideocolourspace.h"
6 
7 #define LOC QString("VTBInterop: ")
8 
10 {
11  if (Render->isOpenGLES() || Render->IsEGL())
12  return;
14  if (Render->hasExtension("GL_ARB_texture_rg"))
15  types.emplace_back(GL_VTBSURFACE);
16  types.emplace_back(GL_VTB);
17  Types[FMT_VTB] = types;
18 }
19 
21 {
22  if (!(Context && Player))
23  return nullptr;
24 
26  GetVTBTypes(Context, types);
27  if (auto vtb = types.find(FMT_VTB); vtb != types.end())
28  {
29  for (auto type : vtb->second)
30  {
31  if (type == GL_VTBSURFACE)
32  return new MythVTBSurfaceInterop(Player, Context);
33  else if (type == GL_VTB)
34  return new MythVTBInterop(Player, Context, GL_VTB);
35  }
36  }
37  return nullptr;
38 }
39 
42  : MythOpenGLInterop(Context, Type, Player)
43 {
44 }
45 
47 {
48 }
49 
51 {
52  if (!Frame)
53  return nullptr;
54 
55  if (Context && (Context != m_openglContext))
56  LOG(VB_GENERAL, LOG_WARNING, LOC + "Mismatched OpenGL contexts");
57 
58  // Check size
59  QSize surfacesize(Frame->m_width, Frame->m_height);
60  if (m_textureSize != surfacesize)
61  {
62  if (!m_textureSize.isEmpty())
63  {
64  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Video texture size changed! %1x%2->%3x%4")
65  .arg(m_textureSize.width()).arg(m_textureSize.height())
66  .arg(Frame->m_width).arg(Frame->m_height));
67  }
69  m_textureSize = surfacesize;
70  }
71 
72  // Update colourspace and initialise on first frame
73  if (ColourSpace)
74  {
75  if (m_openglTextures.isEmpty())
77  ColourSpace->UpdateColourSpace(Frame);
78  }
79 
80  // Retrieve pixel buffer
81  // N.B. Buffer was retained in MythVTBContext and will be released in VideoBuffers
82  return reinterpret_cast<CVPixelBufferRef>(Frame->m_buffer);
83 }
84 
85 std::vector<MythVideoTextureOpenGL*>
87  MythVideoColourSpace* ColourSpace,
90 {
91  std::vector<MythVideoTextureOpenGL*> result;
93 
94  CVPixelBufferRef buffer = Verify(Context, ColourSpace, Frame);
95  if (!buffer)
96  return result;
97 
98  // There are only ever one set of textures which are updated on each pass.
99  // Hence we cannot use reference frames without significant additional work here -
100  // but MythVTBSurfaceInterop will almost certainly always be used - so just drop back
101  // to Linearblend
102  Frame->m_deinterlaceAllowed = (Frame->m_deinterlaceAllowed & ~DEINT_HIGH) | DEINT_MEDIUM;
103 
104  int planes = CVPixelBufferGetPlaneCount(buffer);
105  CVPixelBufferLockBaseAddress(buffer, kCVPixelBufferLock_ReadOnly);
106 
107  // FIXME? There is no P010 support here as I cannot test it - but SurfaceInterop
108  // should be used at all times - so this code is not going to be hit.
109  // Note - and the reason this code is retained is because it may at some point
110  // be useful for an iOS port (iOS has no surace interop)
111 
112  // Create necessary textures
113  if (m_openglTextures.isEmpty())
114  {
115  for (int plane = 0; plane < planes; ++plane)
116  {
117  int width = CVPixelBufferGetWidthOfPlane(buffer, plane);
118  int height = CVPixelBufferGetHeightOfPlane(buffer, plane);
119  QSize size(width, height);
121  if (texture)
122  {
123  texture->m_frameType = FMT_VTB;
124  texture->m_frameFormat = FMT_NV12;
125  texture->m_plane = static_cast<uint>(plane);
126  texture->m_planeCount = static_cast<uint>(planes);
127  texture->m_allowGLSLDeint = true;
128  result.push_back(texture);
129  }
130  }
131 
132  if (result.size() != static_cast<uint>(planes))
133  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create all textures");
134  m_openglTextures.insert(DUMMY_INTEROP_ID, result);
135  }
136 
137  if (m_openglTextures.contains(DUMMY_INTEROP_ID))
138  {
140  m_openglContext->glEnable(QOpenGLTexture::Target2D);
141 
142  // Update textures
143  for (int plane = 0; plane < planes; ++plane)
144  {
145  if (static_cast<uint>(plane) >= result.size())
146  continue;
147 
148  int width = CVPixelBufferGetWidthOfPlane(buffer, plane);
149  int height = CVPixelBufferGetHeightOfPlane(buffer, plane);
150  int bytes = CVPixelBufferGetBytesPerRowOfPlane(buffer, plane) / width;
151  void* buf = CVPixelBufferGetBaseAddressOfPlane(buffer, plane);
152  result[plane]->m_texture->bind();
153  if ((bytes == 1) && buf)
154  {
155  m_openglContext->glTexImage2D(QOpenGLTexture::Target2D, 0, QOpenGLTexture::RGBA, width, height,
156  0, QOpenGLTexture::Red, QOpenGLTexture::UInt8, buf);
157  }
158  else if ((bytes == 2) && buf)
159  {
160  m_openglContext->glTexImage2D(QOpenGLTexture::Target2D, 0, QOpenGLTexture::RGBA, width, height,
161  0, QOpenGLTexture::RG, QOpenGLTexture::UInt8, buf);
162  }
163  result[plane]->m_texture->release();
164  }
165  }
166  CVPixelBufferUnlockBaseAddress(buffer, kCVPixelBufferLock_ReadOnly);
167  return result;
168 }
169 
171  : MythVTBInterop(Player, Context, GL_VTBSURFACE)
172 {
173 }
174 
176 {
177 }
178 
179 std::vector<MythVideoTextureOpenGL*>
181  MythVideoColourSpace* ColourSpace,
183  FrameScanType Scan)
184 {
185  std::vector<MythVideoTextureOpenGL*> result;
187 
188  CVPixelBufferRef buffer = Verify(Context, ColourSpace, Frame);
189  if (!buffer)
190  return result;
191 
192  IOSurfaceRef surface = CVPixelBufferGetIOSurface(buffer);
193  if (!surface)
194  {
195  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to retrieve IOSurface from CV buffer");
196  return result;
197  }
198 
199  IOSurfaceID surfaceid = IOSurfaceGetID(surface);
200  if (!surfaceid)
201  return result;
202 
203  // check whether we need to return multiple frames for GLSL kernel deinterlacing
204  bool needreferences = false;
205  if (is_interlaced(Scan))
206  {
207  MythDeintType shader = Frame->GetDoubleRateOption(DEINT_SHADER);
208  if (shader)
209  needreferences = shader == DEINT_HIGH;
210  else
211  needreferences = Frame->GetSingleRateOption(DEINT_SHADER) == DEINT_HIGH;
212  }
213 
214  if (needreferences)
215  {
216  if (qAbs(Frame->m_frameCounter - m_discontinuityCounter) > 1)
217  m_referenceFrames.clear();
218  RotateReferenceFrames(surfaceid);
219  }
220  else
221  {
222  m_referenceFrames.clear();
223  }
224  m_discontinuityCounter = Frame->m_frameCounter;
225 
226  // return cached textures if available
227  if (m_openglTextures.contains(surfaceid))
228  {
229  if (needreferences)
230  return GetReferenceFrames();
231  return m_openglTextures[surfaceid];
232  }
233 
234  // Create new and attach to IOSurface
235  int planes = IOSurfaceGetPlaneCount(surface);
236  IOSurfaceLock(surface, kIOSurfaceLockReadOnly, nullptr);
237 
238  // Create raw rectangular textures
239  std::vector<QSize> sizes;
240  for (int plane = 0; plane < planes; ++plane)
241  {
242  int width = IOSurfaceGetWidthOfPlane(surface, plane);
243  int height = IOSurfaceGetHeightOfPlane(surface, plane);
244  sizes.push_back(QSize(width, height));
245  }
246  // NB P010 support is untested
247  // NB P010 support was added to FFmpeg in https://github.com/FFmpeg/FFmpeg/commit/036b4b0f85933f49a709
248  // which has not yet been merged into the MythTV FFmpeg version (as of 22/6/19)
249  VideoFrameType frameformat = MythAVUtil::PixelFormatToFrameType(static_cast<AVPixelFormat>(Frame->m_swPixFmt));
250  if ((frameformat != FMT_NV12) && (frameformat != FMT_P010))
251  {
252  IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, nullptr);
253  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unsupported frame format %1")
254  .arg(MythVideoFrame::FormatDescription(frameformat)));
255  return result;
256  }
257 
258  result = MythVideoTextureOpenGL::CreateTextures(m_openglContext, FMT_VTB, frameformat, sizes, QOpenGLTexture::TargetRectangle);
259 
260  for (uint plane = 0; plane < result.size(); ++plane)
261  {
262  MythVideoTextureOpenGL* texture = result[plane];
263  if (!texture)
264  continue;
265  texture->m_allowGLSLDeint = true;
266  m_openglContext->glBindTexture(texture->m_target, texture->m_textureId);
267 
268  GLenum format = (plane == 0) ? QOpenGLTexture::Red : QOpenGLTexture::RG;;
269  GLenum dataformat = (frameformat == FMT_NV12) ? QOpenGLTexture::UInt8 : QOpenGLTexture::UInt16;
270 
271  CGLError error = CGLTexImageIOSurface2D(
272  CGLGetCurrentContext(), QOpenGLTexture::TargetRectangle, format,
273  texture->m_size.width(), texture->m_size.height(),
274  format, dataformat, surface, plane);
275  if (error != kCGLNoError)
276  LOG(VB_GENERAL, LOG_ERR, LOC + QString("CGLTexImageIOSurface2D error %1").arg(error));
277  m_openglContext->glBindTexture(QOpenGLTexture::TargetRectangle, 0);
278  }
279 
280  IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, nullptr);
281  m_openglTextures.insert(surfaceid, result);
282 
283  if (needreferences)
284  return GetReferenceFrames();
285  return result;
286 }
287 
289 {
290  if (!Buffer)
291  return;
292 
293  // don't retain twice for double rate
294  if ((m_referenceFrames.size() > 0) && (m_referenceFrames[0] == Buffer))
295  return;
296 
297  m_referenceFrames.push_front(Buffer);
298 
299  // release old frames
300  while (m_referenceFrames.size() > 3)
301  m_referenceFrames.pop_back();
302 }
303 
304 std::vector<MythVideoTextureOpenGL*> MythVTBSurfaceInterop::GetReferenceFrames(void)
305 {
306  std::vector<MythVideoTextureOpenGL*> result;
307  int size = m_referenceFrames.size();
308  if (size < 1)
309  return result;
310 
311  IOSurfaceID next = m_referenceFrames[0];
312  IOSurfaceID current = m_referenceFrames[size > 1 ? 1 : 0];
313  IOSurfaceID last = m_referenceFrames[size > 2 ? 2 : 0];
314 
315  if (!m_openglTextures.contains(next) || !m_openglTextures.contains(current) ||
316  !m_openglTextures.contains(last))
317  {
318  LOG(VB_GENERAL, LOG_ERR, LOC + "Reference frame error");
319  return result;
320  }
321 
322  result = m_openglTextures[last];
323  std::copy(m_openglTextures[current].cbegin(), m_openglTextures[current].cend(), std::back_inserter(result));
324  std::copy(m_openglTextures[next].cbegin(), m_openglTextures[next].cend(), std::back_inserter(result));
325  return result;
326 }
DUMMY_INTEROP_ID
static constexpr uint64_t DUMMY_INTEROP_ID
Definition: mythinteropgpu.h:18
MythVTBSurfaceInterop::m_referenceFrames
QVector< IOSurfaceID > m_referenceFrames
Definition: mythvtbinterop.h:42
DEINT_MEDIUM
@ DEINT_MEDIUM
Definition: mythframe.h:71
error
static void error(const char *str,...)
Definition: vbi.cpp:36
FMT_VTB
@ FMT_VTB
Definition: mythframe.h:62
DEINT_SHADER
@ DEINT_SHADER
Definition: mythframe.h:74
MythVideoTextureOpenGL
Definition: mythvideotextureopengl.h:21
MythVideoTextureOpenGL::m_planeCount
uint m_planeCount
Definition: mythvideotextureopengl.h:54
Frame
Definition: zmdefines.h:93
FMT_P010
@ FMT_P010
Definition: mythframe.h:54
MythVideoColourSpace::UpdateColourSpace
bool UpdateColourSpace(const MythVideoFrame *Frame)
Set the current colourspace to use.
Definition: mythvideocolourspace.cpp:321
FrameScanType
FrameScanType
Definition: videoouttypes.h:94
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
MythVTBInterop::Acquire
std::vector< MythVideoTextureOpenGL * > Acquire(MythRenderOpenGL *Context, MythVideoColourSpace *ColourSpace, MythVideoFrame *Frame, FrameScanType Scan) override
Definition: mythvtbinterop.cpp:86
MythVideoTextureOpenGL::m_frameFormat
VideoFrameType m_frameFormat
Definition: mythvideotextureopengl.h:52
MythVTBInterop::Verify
CVPixelBufferRef Verify(MythRenderOpenGL *Context, MythVideoColourSpace *ColourSpace, MythVideoFrame *Frame)
Definition: mythvtbinterop.cpp:50
MythVTBSurfaceInterop::Acquire
std::vector< MythVideoTextureOpenGL * > Acquire(MythRenderOpenGL *Context, MythVideoColourSpace *ColourSpace, MythVideoFrame *Frame, FrameScanType Scan) override
Definition: mythvtbinterop.cpp:180
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
LOC
#define LOC
Definition: mythvtbinterop.cpp:7
MythVTBInterop::CreateVTB
static MythVTBInterop * CreateVTB(MythPlayerUI *Player, MythRenderOpenGL *Context)
Definition: mythvtbinterop.cpp:20
MythInteropGPU::InteropMap
std::map< VideoFrameType, InteropTypes > InteropMap
Definition: mythinteropgpu.h:44
MythVTBInterop::GetVTBTypes
static void GetVTBTypes(MythRenderOpenGL *Render, MythInteropGPU::InteropMap &Types)
Definition: mythvtbinterop.cpp:9
MythInteropGPU::GL_VTBSURFACE
@ GL_VTBSURFACE
Definition: mythinteropgpu.h:32
MythVTBSurfaceInterop::MythVTBSurfaceInterop
MythVTBSurfaceInterop(MythPlayerUI *Player, MythRenderOpenGL *Context)
Definition: mythvtbinterop.cpp:170
MythPlayerUI
Definition: mythplayerui.h:10
mythvideocolourspace.h
MythVTBInterop::~MythVTBInterop
~MythVTBInterop() override
Definition: mythvtbinterop.cpp:46
MythOpenGLInterop
Definition: mythopenglinterop.h:17
MythOpenGLInterop::m_openglContext
MythRenderOpenGL * m_openglContext
Definition: mythopenglinterop.h:41
MythFile::copy
MBASE_PUBLIC long long copy(QFile &dst, QFile &src, uint block_size=0)
Copies src file to dst file.
Definition: mythmiscutil.cpp:263
MythInteropGPU::GL_VTB
@ GL_VTB
Definition: mythinteropgpu.h:31
MythVideoTextureOpenGL::m_allowGLSLDeint
bool m_allowGLSLDeint
Definition: mythvideotextureopengl.h:55
MythEGL::IsEGL
bool IsEGL(void)
Definition: mythegl.cpp:29
mythvtbinterop.h
uint
unsigned int uint
Definition: compat.h:81
MythVTBSurfaceInterop::GetReferenceFrames
std::vector< MythVideoTextureOpenGL * > GetReferenceFrames(void)
Definition: mythvtbinterop.cpp:304
MythVideoTextureOpenGL::m_plane
uint m_plane
Definition: mythvideotextureopengl.h:53
ALL_PICTURE_ATTRIBUTES
#define ALL_PICTURE_ATTRIBUTES
Definition: videoouttypes.h:127
MythAVUtil::PixelFormatToFrameType
static VideoFrameType PixelFormatToFrameType(AVPixelFormat Fmt)
Definition: mythavutil.cpp:71
MythOpenGLInterop::m_openglTextures
QHash< unsigned long long, std::vector< MythVideoTextureOpenGL * > > m_openglTextures
Definition: mythopenglinterop.h:42
MythVTBSurfaceInterop::~MythVTBSurfaceInterop
~MythVTBSurfaceInterop() override
Definition: mythvtbinterop.cpp:175
MythGLTexture::m_target
GLenum m_target
Definition: mythrenderopengl.h:77
MythRenderOpenGL
Definition: mythrenderopengl.h:96
MythDeintType
MythDeintType
Definition: mythframe.h:67
Buffer
Definition: MythExternControl.h:36
musicbrainzngs.compat.bytes
bytes
Definition: compat.py:49
MythVideoFrame::FormatDescription
static QString FormatDescription(VideoFrameType Type)
Definition: mythframe.cpp:368
MythVTBInterop::MythVTBInterop
MythVTBInterop(MythPlayerUI *Player, MythRenderOpenGL *Context, MythOpenGLInterop::InteropType Type)
Definition: mythvtbinterop.cpp:40
MythGLTexture::m_textureId
GLuint m_textureId
Definition: mythrenderopengl.h:65
mythcorecontext.h
MythOpenGLInterop::DeleteTextures
virtual void DeleteTextures()
Definition: mythopenglinterop.cpp:138
DEINT_HIGH
@ DEINT_HIGH
Definition: mythframe.h:72
MythGLTexture::m_size
QSize m_size
Definition: mythrenderopengl.h:70
MythInteropGPU::m_discontinuityCounter
uint64_t m_discontinuityCounter
Definition: mythinteropgpu.h:63
MythVTBSurfaceInterop
Definition: mythvtbinterop.h:27
MythVTBSurfaceInterop::RotateReferenceFrames
void RotateReferenceFrames(IOSurfaceID Buffer)
Definition: mythvtbinterop.cpp:288
MythVideoTextureOpenGL::m_frameType
VideoFrameType m_frameType
Definition: mythvideotextureopengl.h:51
VideoFrameType
VideoFrameType
Definition: mythframe.h:20
Player
Definition: zmliveplayer.h:34
MythVideoTextureOpenGL::CreateTexture
static MythVideoTextureOpenGL * CreateTexture(MythRenderOpenGL *Context, QSize Size, GLenum Target=QOpenGLTexture::Target2D, QOpenGLTexture::PixelType PixelType=QOpenGLTexture::UInt8, QOpenGLTexture::PixelFormat PixelFormat=QOpenGLTexture::RGBA, QOpenGLTexture::TextureFormat Format=QOpenGLTexture::NoFormat, QOpenGLTexture::Filter Filter=QOpenGLTexture::Linear, QOpenGLTexture::WrapMode Wrap=QOpenGLTexture::ClampToEdge)
Create and initialise a MythVideoTexture that is backed by a QOpenGLTexture.
Definition: mythvideotextureopengl.cpp:432
MythVideoFrame
Definition: mythframe.h:88
FMT_NV12
@ FMT_NV12
Definition: mythframe.h:53
MythInteropGPU::InteropType
InteropType
Definition: mythinteropgpu.h:25
mythmainwindow.h
MythInteropGPU::m_textureSize
QSize m_textureSize
Definition: mythinteropgpu.h:62
is_interlaced
bool is_interlaced(FrameScanType Scan)
Definition: videoouttypes.h:188
MythVTBInterop
Definition: mythvtbinterop.h:10
MythVideoColourSpace
MythVideoColourSpace contains a QMatrix4x4 that can convert YCbCr data to RGB.
Definition: mythvideocolourspace.h:18
MythVideoTextureOpenGL::CreateTextures
static std::vector< MythVideoTextureOpenGL * > CreateTextures(MythRenderOpenGL *Context, VideoFrameType Type, VideoFrameType Format, std::vector< QSize > Sizes, GLenum Target=QOpenGLTexture::Target2D)
Create a set of textures suitable for the given Type and Format.
Definition: mythvideotextureopengl.cpp:57
MythInteropGPU::InteropTypes
std::vector< InteropType > InteropTypes
Definition: mythinteropgpu.h:43
OpenGLLocker
Definition: mythrenderopengl.h:255