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