MythTV  master
mythmediacodecinterop.cpp
Go to the documentation of this file.
1 // MythTV
2 #include "mythcorecontext.h"
3 #include "videocolourspace.h"
5 
6 // FFmpeg
7 extern "C" {
8 #include "libavutil/hwcontext_mediacodec.h"
9 #include "libavcodec/mediacodec.h"
10 }
11 
12 #define LOC QString("MediaCodecInterop: ")
13 
15 {
17  if (result)
18  {
19  if (result->Initialise(Size))
20  return result;
21  delete result;
22  }
23  return nullptr;
24 }
25 
27  : MythOpenGLInterop(Context, MEDIACODEC),
28  m_frameWait(),
29  m_frameWaitLock(),
30  m_colourSpaceInitialised(false),
31  m_surface(),
32  m_surfaceTexture(),
33  m_surfaceListener(),
34  m_textureTransform(nullptr),
35  m_transform()
36 {
37  jfloatArray transform = QAndroidJniEnvironment()->NewFloatArray(16);
38  m_textureTransform = jfloatArray(QAndroidJniEnvironment()->NewGlobalRef(transform));
39  QAndroidJniEnvironment()->DeleteLocalRef(transform);
40 }
41 
43 {
44  QAndroidJniEnvironment()->DeleteGlobalRef(m_textureTransform);
45 }
46 
48 {
49  return m_surface.object();
50 }
51 
52 void Java_org_mythtv_video_SurfaceTextureListener_frameAvailable(JNIEnv*, jobject, jlong Wait, jobject)
53 {
54  QWaitCondition *wait = reinterpret_cast<QWaitCondition*>(Wait);
55  if (wait)
56  wait->wakeAll();
57 }
58 
60 {
61  if (!m_context)
62  return false;
63 
64  if (!gCoreContext->IsUIThread())
65  {
66  LOG(VB_GENERAL, LOG_ERR, LOC + "Must be created in UI thread");
67  return false;
68  }
69 
70  // Lock
71  OpenGLLocker locker(m_context);
72 
73  // Create texture
74  vector<QSize> sizes;
75  sizes.push_back(Size);
76  vector<MythVideoTexture*> textures =
78  if (textures.empty())
79  {
80  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create texture");
81  return false;
82  }
83 
84  // Set the texture type
85  MythVideoTexture *texture = textures[0];
86  m_context->glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture->m_textureId);
87 
88  // Create surface
89  m_surfaceTexture = QAndroidJniObject("android/graphics/SurfaceTexture", "(I)V", texture->m_textureId);
90  m_surfaceListener = QAndroidJniObject("org/mythtv/video/SurfaceTextureListener", "(J)V", jlong(&m_frameWait));
91  if (m_surfaceTexture.isValid() && m_surfaceListener.isValid())
92  {
93  m_surfaceTexture.callMethod<void>("setOnFrameAvailableListener",
94  "(Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;)V",
95  m_surfaceListener.object());
96  m_surface = QAndroidJniObject("android/view/Surface",
97  "(Landroid/graphics/SurfaceTexture;)V",
98  m_surfaceTexture.object());
99  if (m_surface.isValid())
100  {
101  m_openglTextures.insert(DUMMY_INTEROP_ID, textures);
102  LOG(VB_GENERAL, LOG_INFO, LOC + "Created Android Surface");
103  return true;
104  }
105  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Android Surface");
106  }
107  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Android SurfaceTexture");
109  return false;
110 }
111 
113  VideoColourSpace *ColourSpace,
114  VideoFrame *Frame,
116 {
117  vector<MythVideoTexture*> result;
118  if (!Frame)
119  return result;
120 
121  // Pause frame handling - we can never release the same buffer twice
122  if (!Frame->buf)
123  {
124  if (!m_openglTextures.isEmpty())
126  return result;
127  }
128 
129  // Sanitise
130  if (!Context || !ColourSpace || !Frame || m_openglTextures.isEmpty())
131  {
132  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed");
133  return result;
134  }
135 
136  // Check colourspace on first frame
138  {
141  ColourSpace->UpdateColourSpace(Frame);
142  }
143 
144  // Retrieve buffer
145  AVMediaCodecBuffer *buffer = reinterpret_cast<AVMediaCodecBuffer*>(Frame->buf);
146  if (!buffer)
147  {
148  LOG(VB_GENERAL, LOG_ERR, LOC + "No AVMediaCodecBuffer");
149  return result;
150  }
151 
152  // Render...
153  m_frameWaitLock.lock();
154  if (av_mediacodec_release_buffer(buffer, 1) < 0)
155  LOG(VB_GENERAL, LOG_ERR , LOC + "av_mediacodec_release_buffer failed");
156 
157  // Wait for completion
158  if (!m_frameWait.wait(&m_frameWaitLock, 10))
159  LOG(VB_GENERAL, LOG_WARNING, LOC + "Timed out waiting for frame update");
160  m_frameWaitLock.unlock();
161 
162  // Ensure we don't try and release it again
163  Frame->buf = nullptr;
164 
165  // Update texture
166  m_surfaceTexture.callMethod<void>("updateTexImage");
167 
168  // Retrieve and set transform
169  m_surfaceTexture.callMethod<void>("getTransformMatrix", "([F)V", m_textureTransform);
170  QAndroidJniEnvironment()->GetFloatArrayRegion(m_textureTransform, 0, 16, m_transform.data());
171  m_openglTextures[DUMMY_INTEROP_ID][0]->m_transform = &m_transform;
172  m_openglTextures[DUMMY_INTEROP_ID][0]->m_flip = false;
173 
175 }
QAndroidJniObject m_surfaceTexture
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.
QHash< QString, Action * > Context
Definition: action.h:77
QAndroidJniObject m_surfaceListener
#define DUMMY_INTEROP_ID
#define GL_TEXTURE_EXTERNAL_OES
FrameScanType
Definition: videoouttypes.h:78
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static void DeleteTextures(MythRenderOpenGL *Context, vector< MythVideoTexture * > &Textures)
virtual vector< MythVideoTexture * > Acquire(MythRenderOpenGL *Context, VideoColourSpace *ColourSpace, VideoFrame *Frame, FrameScanType Scan) override
void Java_org_mythtv_video_SurfaceTextureListener_frameAvailable(JNIEnv *, jobject, jlong Wait, jobject)
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
#define LOC
QAndroidJniObject m_surface
void SetSupportedAttributes(PictureAttributeSupported Supported)
Enable the given set of picture attributes.
MythMediaCodecInterop(MythRenderOpenGL *Context)
MythRenderOpenGL * m_context
QHash< unsigned long long, vector< MythVideoTexture * > > m_openglTextures
bool UpdateColourSpace(const VideoFrame *Frame)
Set the current colourspace to use.
static MythMediaCodecInterop * Create(MythRenderOpenGL *Context, QSize Size)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23