• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013, Fluendo S.A.
3  *   Author: Andoni Morales <amorales@fluendo.com>
4  *
5  * Copyright (C) 2014,2018 Collabora Ltd.
6  *   Author: Matthieu Bouron <matthieu.bouron@collabora.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation
11  * version 2.1 of the License.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include "gstjniutils.h"
29 #include "gstamcsurfacetexture-jni.h"
30 
31 struct _GstAmcSurfaceTextureJNI
32 {
33   GstAmcSurfaceTexture parent_instance;
34   jobject jobject;
35   gint texture_id;
36 
37   jobject listener;
38   jmethodID set_context_id;
39   GstAmcSurfaceTextureOnFrameAvailableCallback callback;
40   gpointer user_data;
41 };
42 
43 static struct
44 {
45   jclass jklass;
46   jmethodID constructor;
47   jmethodID set_on_frame_available_listener;
48   jmethodID update_tex_image;
49   jmethodID detach_from_gl_context;
50   jmethodID attach_to_gl_context;
51   jmethodID get_transform_matrix;
52   jmethodID get_timestamp;
53   jmethodID release;
54 } surface_texture;
55 
56 
57 G_DEFINE_TYPE (GstAmcSurfaceTextureJNI, gst_amc_surface_texture_jni,
58     GST_TYPE_AMC_SURFACE_TEXTURE);
59 
60 gboolean
gst_amc_surface_texture_static_init(void)61 gst_amc_surface_texture_static_init (void)
62 {
63   JNIEnv *env;
64   GError *err = NULL;
65 
66   env = gst_amc_jni_get_env ();
67 
68   surface_texture.jklass = gst_amc_jni_get_class (env, &err,
69       "android/graphics/SurfaceTexture");
70   if (!surface_texture.jklass) {
71     GST_ERROR ("Failed to get android.graphics.SurfaceTexture class: %s",
72         err->message);
73     g_clear_error (&err);
74     return FALSE;
75   }
76 
77   surface_texture.constructor =
78       gst_amc_jni_get_method_id (env, &err, surface_texture.jklass, "<init>",
79       "(I)V");
80   if (!surface_texture.constructor) {
81     goto error;
82   }
83 
84   surface_texture.set_on_frame_available_listener =
85       gst_amc_jni_get_method_id (env, &err, surface_texture.jklass,
86       "setOnFrameAvailableListener",
87       "(Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;)V");
88   if (!surface_texture.set_on_frame_available_listener) {
89     goto error;
90   }
91 
92   surface_texture.update_tex_image =
93       gst_amc_jni_get_method_id (env, &err, surface_texture.jklass,
94       "updateTexImage", "()V");
95   if (!surface_texture.update_tex_image) {
96     goto error;
97   }
98 
99   surface_texture.detach_from_gl_context =
100       gst_amc_jni_get_method_id (env, &err, surface_texture.jklass,
101       "detachFromGLContext", "()V");
102   if (!surface_texture.detach_from_gl_context) {
103     goto error;
104   }
105 
106   surface_texture.attach_to_gl_context =
107       gst_amc_jni_get_method_id (env, &err, surface_texture.jklass,
108       "attachToGLContext", "(I)V");
109   if (!surface_texture.attach_to_gl_context) {
110     goto error;
111   }
112 
113   surface_texture.get_transform_matrix =
114       gst_amc_jni_get_method_id (env, &err, surface_texture.jklass,
115       "getTransformMatrix", "([F)V");
116   if (!surface_texture.get_transform_matrix) {
117     goto error;
118   }
119 
120   surface_texture.get_timestamp =
121       gst_amc_jni_get_method_id (env, &err, surface_texture.jklass,
122       "getTimestamp", "()J");
123   if (!surface_texture.get_timestamp) {
124     goto error;
125   }
126 
127   surface_texture.release =
128       gst_amc_jni_get_method_id (env, &err, surface_texture.jklass, "release",
129       "()V");
130   if (!surface_texture.release) {
131     goto error;
132   }
133 
134   return TRUE;
135 
136 error:
137   GST_ERROR ("Failed to get android.graphics.SurfaceTexture methods: %s",
138       err->message);
139   g_clear_error (&err);
140   gst_amc_jni_object_unref (env, surface_texture.constructor);
141   return FALSE;
142 }
143 
144 static gboolean
gst_amc_surface_texture_jni_update_tex_image(GstAmcSurfaceTexture * base,GError ** err)145 gst_amc_surface_texture_jni_update_tex_image (GstAmcSurfaceTexture * base,
146     GError ** err)
147 {
148   GstAmcSurfaceTextureJNI *self = GST_AMC_SURFACE_TEXTURE_JNI (base);
149   JNIEnv *env;
150 
151   env = gst_amc_jni_get_env ();
152 
153   return gst_amc_jni_call_void_method (env, err, self->jobject,
154       surface_texture.update_tex_image);
155 }
156 
157 static gboolean
gst_amc_surface_texture_jni_detach_from_gl_context(GstAmcSurfaceTexture * base,GError ** err)158 gst_amc_surface_texture_jni_detach_from_gl_context (GstAmcSurfaceTexture * base,
159     GError ** err)
160 {
161   GstAmcSurfaceTextureJNI *self = GST_AMC_SURFACE_TEXTURE_JNI (base);
162   JNIEnv *env;
163   gboolean ret;
164 
165   env = gst_amc_jni_get_env ();
166 
167   ret =
168       gst_amc_jni_call_void_method (env, err, self->jobject,
169       surface_texture.detach_from_gl_context);
170   self->texture_id = 0;
171   return ret;
172 }
173 
174 static gboolean
gst_amc_surface_texture_jni_attach_to_gl_context(GstAmcSurfaceTexture * base,gint texture_id,GError ** err)175 gst_amc_surface_texture_jni_attach_to_gl_context (GstAmcSurfaceTexture * base,
176     gint texture_id, GError ** err)
177 {
178   GstAmcSurfaceTextureJNI *self = GST_AMC_SURFACE_TEXTURE_JNI (base);
179   JNIEnv *env;
180   gboolean ret;
181 
182   env = gst_amc_jni_get_env ();
183 
184   ret =
185       gst_amc_jni_call_void_method (env, err, self->jobject,
186       surface_texture.attach_to_gl_context, texture_id);
187   self->texture_id = texture_id;
188   return ret;
189 }
190 
191 static gboolean
gst_amc_surface_texture_jni_get_transform_matrix(GstAmcSurfaceTexture * base,gfloat * matrix,GError ** err)192 gst_amc_surface_texture_jni_get_transform_matrix (GstAmcSurfaceTexture * base,
193     gfloat * matrix, GError ** err)
194 {
195   GstAmcSurfaceTextureJNI *self = GST_AMC_SURFACE_TEXTURE_JNI (base);
196   JNIEnv *env;
197   gboolean ret;
198   /* 4x4 Matrix */
199   jsize size = 16;
200   jfloatArray floatarray;
201 
202   env = gst_amc_jni_get_env ();
203 
204   floatarray = (*env)->NewFloatArray (env, size);
205   ret =
206       gst_amc_jni_call_void_method (env, err, self->jobject,
207       surface_texture.get_transform_matrix, floatarray);
208   if (ret) {
209     (*env)->GetFloatArrayRegion (env, floatarray, 0, size, (jfloat *) matrix);
210     (*env)->DeleteLocalRef (env, floatarray);
211   }
212 
213   return ret;
214 }
215 
216 static gboolean
gst_amc_surface_texture_jni_get_timestamp(GstAmcSurfaceTexture * base,gint64 * result,GError ** err)217 gst_amc_surface_texture_jni_get_timestamp (GstAmcSurfaceTexture * base,
218     gint64 * result, GError ** err)
219 {
220   GstAmcSurfaceTextureJNI *self = GST_AMC_SURFACE_TEXTURE_JNI (base);
221   JNIEnv *env;
222 
223   env = gst_amc_jni_get_env ();
224 
225   return gst_amc_jni_call_long_method (env, err, self->jobject,
226       surface_texture.get_timestamp, result);
227 }
228 
229 static gboolean
gst_amc_surface_texture_jni_release(GstAmcSurfaceTexture * base,GError ** err)230 gst_amc_surface_texture_jni_release (GstAmcSurfaceTexture * base, GError ** err)
231 {
232   GstAmcSurfaceTextureJNI *self = GST_AMC_SURFACE_TEXTURE_JNI (base);
233   JNIEnv *env;
234 
235   env = gst_amc_jni_get_env ();
236 
237   return gst_amc_jni_call_void_method (env, err, self->jobject,
238       surface_texture.release);
239 }
240 
241 static void
on_frame_available_cb(JNIEnv * env,jobject thiz,long long context,jobject surfaceTexture)242 on_frame_available_cb (JNIEnv * env, jobject thiz,
243     long long context, jobject surfaceTexture)
244 {
245   GstAmcSurfaceTextureJNI *self = JLONG_TO_GPOINTER (context);
246 
247   self->callback (GST_AMC_SURFACE_TEXTURE (self), self->user_data);
248 }
249 
250 static gboolean
create_listener(GstAmcSurfaceTextureJNI * self,JNIEnv * env,GError ** err)251 create_listener (GstAmcSurfaceTextureJNI * self, JNIEnv * env, GError ** err)
252 {
253   jclass listener_cls = NULL;
254   jmethodID constructor_id = 0;
255 
256   JNINativeMethod amcOnFrameAvailableListener = {
257     "native_onFrameAvailable",
258     "(JLandroid/graphics/SurfaceTexture;)V",
259     (void *) on_frame_available_cb,
260   };
261 
262   listener_cls =
263       gst_amc_jni_get_application_class (env,
264       "org/freedesktop/gstreamer/androidmedia/GstAmcOnFrameAvailableListener",
265       err);
266   if (!listener_cls) {
267     return FALSE;
268   }
269 
270   (*env)->RegisterNatives (env, listener_cls, &amcOnFrameAvailableListener, 1);
271   if ((*env)->ExceptionCheck (env)) {
272     gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
273         GST_LIBRARY_ERROR_FAILED, "Failed to register native methods");
274     goto done;
275   }
276 
277   constructor_id =
278       gst_amc_jni_get_method_id (env, err, listener_cls, "<init>", "()V");
279   if (!constructor_id) {
280     goto done;
281   }
282 
283   self->set_context_id =
284       gst_amc_jni_get_method_id (env, err, listener_cls, "setContext", "(J)V");
285   if (!self->set_context_id) {
286     goto done;
287   }
288 
289   self->listener =
290       gst_amc_jni_new_object (env, err, TRUE, listener_cls, constructor_id);
291   if (!self->listener) {
292     goto done;
293   }
294 
295   if (!gst_amc_jni_call_void_method (env, err, self->listener,
296           self->set_context_id, GPOINTER_TO_JLONG (self))) {
297     gst_amc_jni_object_unref (env, self->listener);
298     self->listener = NULL;
299   }
300 
301 done:
302   gst_amc_jni_object_unref (env, listener_cls);
303 
304   return self->listener != NULL;
305 }
306 
307 static gboolean
remove_listener(GstAmcSurfaceTextureJNI * self,JNIEnv * env,GError ** err)308 remove_listener (GstAmcSurfaceTextureJNI * self, JNIEnv * env, GError ** err)
309 {
310   if (self->listener) {
311     if (!gst_amc_jni_call_void_method (env, err, self->listener,
312             self->set_context_id, GPOINTER_TO_JLONG (NULL)))
313       return FALSE;
314 
315     gst_amc_jni_object_unref (env, self->listener);
316     self->listener = NULL;
317   }
318 
319   return TRUE;
320 }
321 
322 static gboolean
gst_amc_surface_texture_jni_set_on_frame_available_callback(GstAmcSurfaceTexture * base,GstAmcSurfaceTextureOnFrameAvailableCallback callback,gpointer user_data,GError ** err)323     gst_amc_surface_texture_jni_set_on_frame_available_callback
324     (GstAmcSurfaceTexture * base,
325     GstAmcSurfaceTextureOnFrameAvailableCallback callback, gpointer user_data,
326     GError ** err)
327 {
328   GstAmcSurfaceTextureJNI *self = GST_AMC_SURFACE_TEXTURE_JNI (base);
329   JNIEnv *env;
330   GError *local_error = NULL;
331 
332   env = gst_amc_jni_get_env ();
333 
334   if (!remove_listener (self, env, err))
335     return FALSE;
336 
337   self->callback = callback;
338   self->user_data = user_data;
339   if (callback == NULL)
340     return TRUE;
341 
342   if (!create_listener (self, env, &local_error)) {
343     GST_ERROR ("Could not create listener: %s", local_error->message);
344     g_propagate_error (err, local_error);
345     return FALSE;
346   }
347 
348   if (!gst_amc_jni_call_void_method (env, err, self->jobject,
349           surface_texture.set_on_frame_available_listener, self->listener)) {
350     remove_listener (self, env, NULL);
351     return FALSE;
352   }
353 
354   return TRUE;
355 }
356 
357 static void
gst_amc_surface_texture_jni_dispose(GObject * object)358 gst_amc_surface_texture_jni_dispose (GObject * object)
359 {
360   GstAmcSurfaceTextureJNI *self = GST_AMC_SURFACE_TEXTURE_JNI (object);
361   JNIEnv *env;
362   GError *err = NULL;
363 
364   env = gst_amc_jni_get_env ();
365 
366   if (!gst_amc_surface_texture_jni_release (GST_AMC_SURFACE_TEXTURE (self),
367           &err)) {
368     GST_ERROR ("Could not release surface texture: %s", err->message);
369     g_clear_error (&err);
370   }
371 
372   remove_listener (self, env, NULL);
373 
374   if (self->jobject) {
375     gst_amc_jni_object_unref (env, self->jobject);
376   }
377 
378   G_OBJECT_CLASS (gst_amc_surface_texture_jni_parent_class)->dispose (object);
379 }
380 
381 static void
gst_amc_surface_texture_jni_class_init(GstAmcSurfaceTextureJNIClass * klass)382 gst_amc_surface_texture_jni_class_init (GstAmcSurfaceTextureJNIClass * klass)
383 {
384   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
385   GstAmcSurfaceTextureClass *surface_texture_class =
386       GST_AMC_SURFACE_TEXTURE_CLASS (klass);
387 
388   gobject_class->dispose = gst_amc_surface_texture_jni_dispose;
389 
390   surface_texture_class->update_tex_image =
391       gst_amc_surface_texture_jni_update_tex_image;
392   surface_texture_class->detach_from_gl_context =
393       gst_amc_surface_texture_jni_detach_from_gl_context;
394   surface_texture_class->attach_to_gl_context =
395       gst_amc_surface_texture_jni_attach_to_gl_context;
396   surface_texture_class->get_transform_matrix =
397       gst_amc_surface_texture_jni_get_transform_matrix;
398   surface_texture_class->get_timestamp =
399       gst_amc_surface_texture_jni_get_timestamp;
400   surface_texture_class->release = gst_amc_surface_texture_jni_release;
401   surface_texture_class->set_on_frame_available_callback =
402       gst_amc_surface_texture_jni_set_on_frame_available_callback;
403 }
404 
405 static void
gst_amc_surface_texture_jni_init(GstAmcSurfaceTextureJNI * self)406 gst_amc_surface_texture_jni_init (GstAmcSurfaceTextureJNI * self)
407 {
408 }
409 
410 GstAmcSurfaceTextureJNI *
gst_amc_surface_texture_jni_new(GError ** err)411 gst_amc_surface_texture_jni_new (GError ** err)
412 {
413   GstAmcSurfaceTextureJNI *self = NULL;
414   JNIEnv *env;
415 
416   self = g_object_new (GST_TYPE_AMC_SURFACE_TEXTURE_JNI, NULL);
417   env = gst_amc_jni_get_env ();
418 
419   self->texture_id = 0;
420 
421   self->jobject =
422       gst_amc_jni_new_object (env, err, TRUE, surface_texture.jklass,
423       surface_texture.constructor, self->texture_id);
424   if (self->jobject == NULL) {
425     goto error;
426   }
427 
428   if (!gst_amc_surface_texture_jni_detach_from_gl_context ((GstAmcSurfaceTexture
429               *) self, err)) {
430     goto error;
431   }
432 
433   return self;
434 
435 error:
436   if (self)
437     g_object_unref (self);
438   return NULL;
439 }
440 
441 jobject
gst_amc_surface_texture_jni_get_jobject(GstAmcSurfaceTextureJNI * self)442 gst_amc_surface_texture_jni_get_jobject (GstAmcSurfaceTextureJNI * self)
443 {
444   return self->jobject;
445 }
446