1 /*
2  * Copyright (C) 2013, Fluendo S.A.
3  *   Author: Andoni Morales <amorales@fluendo.com>
4  *
5  * Copyright (C) 2014, 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.h"
30 
31 G_DEFINE_TYPE (GstAmcSurfaceTexture, gst_amc_surface_texture, G_TYPE_OBJECT);
32 
33 static gpointer parent_class = NULL;
34 static void gst_amc_surface_texture_dispose (GObject * object);
35 
36 static gboolean
_cache_java_class(GstAmcSurfaceTextureClass * klass,GError ** err)37 _cache_java_class (GstAmcSurfaceTextureClass * klass, GError ** err)
38 {
39   JNIEnv *env;
40 
41   gst_amc_jni_initialize ();
42   env = gst_amc_jni_get_env ();
43 
44   klass->jklass =
45       gst_amc_jni_get_class (env, err, "android/graphics/SurfaceTexture");
46   if (!klass->jklass) {
47     return FALSE;
48   }
49 
50   klass->constructor =
51       gst_amc_jni_get_method_id (env, err, klass->jklass, "<init>", "(I)V");
52   if (!klass->constructor) {
53     goto error;
54   }
55 
56   klass->set_on_frame_available_listener =
57       gst_amc_jni_get_method_id (env, err, klass->jklass,
58       "setOnFrameAvailableListener",
59       "(Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;)V");
60 
61   klass->set_default_buffer_size =
62       gst_amc_jni_get_method_id (env, err, klass->jklass,
63       "setDefaultBufferSize", "(II)V");
64   if (!klass->set_default_buffer_size) {
65     goto error;
66   }
67 
68   klass->update_tex_image =
69       gst_amc_jni_get_method_id (env, err, klass->jklass, "updateTexImage",
70       "()V");
71   if (!klass->update_tex_image) {
72     goto error;
73   }
74 
75   klass->detach_from_gl_context =
76       gst_amc_jni_get_method_id (env, err, klass->jklass, "detachFromGLContext",
77       "()V");
78   if (!klass->detach_from_gl_context) {
79     goto error;
80   }
81 
82   klass->attach_to_gl_context =
83       gst_amc_jni_get_method_id (env, err, klass->jklass, "attachToGLContext",
84       "(I)V");
85   if (!klass->attach_to_gl_context) {
86     goto error;
87   }
88 
89   klass->get_transform_matrix =
90       gst_amc_jni_get_method_id (env, err, klass->jklass, "getTransformMatrix",
91       "([F)V");
92   if (!klass->get_transform_matrix) {
93     goto error;
94   }
95 
96   klass->get_timestamp =
97       gst_amc_jni_get_method_id (env, err, klass->jklass, "getTimestamp",
98       "()J");
99   if (!klass->get_timestamp) {
100     goto error;
101   }
102 
103   klass->release =
104       gst_amc_jni_get_method_id (env, err, klass->jklass, "release", "()V");
105   if (!klass->release) {
106     goto error;
107   }
108 
109   return TRUE;
110 
111 error:
112   gst_amc_jni_object_unref (env, klass->constructor);
113   return FALSE;
114 }
115 
116 static void
gst_amc_surface_texture_init(GstAmcSurfaceTexture * self)117 gst_amc_surface_texture_init (GstAmcSurfaceTexture * self)
118 {
119 }
120 
121 static void
gst_amc_surface_texture_class_init(GstAmcSurfaceTextureClass * klass)122 gst_amc_surface_texture_class_init (GstAmcSurfaceTextureClass * klass)
123 {
124   GError *err = NULL;
125   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
126 
127   parent_class = g_type_class_peek_parent (klass);
128   gobject_class->dispose = gst_amc_surface_texture_dispose;
129 
130   if (!_cache_java_class (klass, &err)) {
131     g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
132         "Could not cache java class android/graphics/SurfaceTexture: %s",
133         err->message);
134     g_clear_error (&err);
135   }
136 }
137 
138 static void
gst_amc_surface_texture_dispose(GObject * object)139 gst_amc_surface_texture_dispose (GObject * object)
140 {
141   GstAmcSurfaceTexture *self;
142   JNIEnv *env;
143   GError *err = NULL;
144 
145   self = GST_AMC_SURFACE_TEXTURE (object);
146   env = gst_amc_jni_get_env ();
147 
148   if (!gst_amc_surface_texture_release (self, &err)) {
149     GST_ERROR ("Could not release surface texture: %s", err->message);
150     g_clear_error (&err);
151   }
152 
153   if (self->jobject) {
154     gst_amc_jni_object_unref (env, self->jobject);
155   }
156   G_OBJECT_CLASS (parent_class)->dispose (object);
157 }
158 
159 GstAmcSurfaceTexture *
gst_amc_surface_texture_new(GError ** err)160 gst_amc_surface_texture_new (GError ** err)
161 {
162   GstAmcSurfaceTexture *texture = NULL;
163   GstAmcSurfaceTextureClass *klass;
164   JNIEnv *env;
165 
166   texture = g_object_new (GST_TYPE_AMC_SURFACE_TEXTURE, NULL);
167   klass = GST_AMC_SURFACE_TEXTURE_GET_CLASS (texture);
168   env = gst_amc_jni_get_env ();
169 
170   texture->texture_id = 0;
171 
172   texture->jobject = gst_amc_jni_new_object (env, err, TRUE, klass->jklass,
173       klass->constructor, texture->texture_id);
174   if (texture->jobject == NULL) {
175     goto error;
176   }
177 
178   if (!gst_amc_surface_texture_detach_from_gl_context (texture, err)) {
179     goto error;
180   }
181 
182   return texture;
183 
184 error:
185   if (texture)
186     g_object_unref (texture);
187   return NULL;
188 }
189 
190 gboolean
gst_amc_surface_texture_set_default_buffer_size(GstAmcSurfaceTexture * self,gint width,gint height,GError ** err)191 gst_amc_surface_texture_set_default_buffer_size (GstAmcSurfaceTexture * self,
192     gint width, gint height, GError ** err)
193 {
194   JNIEnv *env;
195   GstAmcSurfaceTextureClass *klass;
196 
197   env = gst_amc_jni_get_env ();
198   klass = GST_AMC_SURFACE_TEXTURE_GET_CLASS (self);
199 
200   return gst_amc_jni_call_void_method (env, err, self->jobject,
201       klass->set_default_buffer_size, width, height);
202 }
203 
204 gboolean
gst_amc_surface_texture_update_tex_image(GstAmcSurfaceTexture * self,GError ** err)205 gst_amc_surface_texture_update_tex_image (GstAmcSurfaceTexture * self,
206     GError ** err)
207 {
208   JNIEnv *env;
209   GstAmcSurfaceTextureClass *klass;
210 
211   env = gst_amc_jni_get_env ();
212   klass = GST_AMC_SURFACE_TEXTURE_GET_CLASS (self);
213 
214   return gst_amc_jni_call_void_method (env, err, self->jobject,
215       klass->update_tex_image);
216 }
217 
218 gboolean
gst_amc_surface_texture_detach_from_gl_context(GstAmcSurfaceTexture * self,GError ** err)219 gst_amc_surface_texture_detach_from_gl_context (GstAmcSurfaceTexture * self,
220     GError ** err)
221 {
222   JNIEnv *env;
223   gboolean ret;
224   GstAmcSurfaceTextureClass *klass;
225 
226   env = gst_amc_jni_get_env ();
227   klass = GST_AMC_SURFACE_TEXTURE_GET_CLASS (self);
228 
229   ret =
230       gst_amc_jni_call_void_method (env, err, self->jobject,
231       klass->detach_from_gl_context);
232   self->texture_id = 0;
233   return ret;
234 }
235 
236 gboolean
gst_amc_surface_texture_attach_to_gl_context(GstAmcSurfaceTexture * self,gint texture_id,GError ** err)237 gst_amc_surface_texture_attach_to_gl_context (GstAmcSurfaceTexture * self,
238     gint texture_id, GError ** err)
239 {
240   JNIEnv *env;
241   gboolean ret;
242   GstAmcSurfaceTextureClass *klass;
243 
244   env = gst_amc_jni_get_env ();
245   klass = GST_AMC_SURFACE_TEXTURE_GET_CLASS (self);
246 
247   ret =
248       gst_amc_jni_call_void_method (env, err, self->jobject,
249       klass->attach_to_gl_context, texture_id);
250   self->texture_id = texture_id;
251   return ret;
252 }
253 
254 gboolean
gst_amc_surface_texture_get_transform_matrix(GstAmcSurfaceTexture * self,const gfloat * matrix,GError ** err)255 gst_amc_surface_texture_get_transform_matrix (GstAmcSurfaceTexture * self,
256     const gfloat * matrix, GError ** err)
257 {
258   JNIEnv *env;
259   gboolean ret;
260   GstAmcSurfaceTextureClass *klass;
261   /* 4x4 Matrix */
262   jsize size = 16;
263   jfloatArray floatarray;
264 
265   env = gst_amc_jni_get_env ();
266   klass = GST_AMC_SURFACE_TEXTURE_GET_CLASS (self);
267 
268   floatarray = (*env)->NewFloatArray (env, size);
269   ret =
270       gst_amc_jni_call_void_method (env, err, self->jobject,
271       klass->get_transform_matrix, floatarray);
272   if (ret) {
273     (*env)->GetFloatArrayRegion (env, floatarray, 0, size, (jfloat *) matrix);
274     (*env)->DeleteLocalRef (env, floatarray);
275   }
276 
277   return ret;
278 }
279 
280 gboolean
gst_amc_surface_texture_get_timestamp(GstAmcSurfaceTexture * self,gint64 * result,GError ** err)281 gst_amc_surface_texture_get_timestamp (GstAmcSurfaceTexture * self,
282     gint64 * result, GError ** err)
283 {
284   JNIEnv *env;
285   GstAmcSurfaceTextureClass *klass;
286 
287   env = gst_amc_jni_get_env ();
288   klass = GST_AMC_SURFACE_TEXTURE_GET_CLASS (self);
289 
290   return gst_amc_jni_call_long_method (env, err, self->jobject,
291       klass->get_timestamp, result);
292 }
293 
294 gboolean
gst_amc_surface_texture_release(GstAmcSurfaceTexture * self,GError ** err)295 gst_amc_surface_texture_release (GstAmcSurfaceTexture * self, GError ** err)
296 {
297   JNIEnv *env;
298   GstAmcSurfaceTextureClass *klass;
299 
300   env = gst_amc_jni_get_env ();
301   klass = GST_AMC_SURFACE_TEXTURE_GET_CLASS (self);
302 
303   return gst_amc_jni_call_void_method (env, err, self->jobject, klass->release);
304 }
305 
306 gboolean
gst_amc_surface_texture_set_on_frame_available_listener(GstAmcSurfaceTexture * self,jobject listener,GError ** err)307 gst_amc_surface_texture_set_on_frame_available_listener (GstAmcSurfaceTexture *
308     self, jobject listener, GError ** err)
309 {
310   JNIEnv *env;
311   GstAmcSurfaceTextureClass *klass;
312 
313   env = gst_amc_jni_get_env ();
314   klass = GST_AMC_SURFACE_TEXTURE_GET_CLASS (self);
315 
316   return gst_amc_jni_call_void_method (env, err, self->jobject,
317       klass->set_on_frame_available_listener, listener);
318 }
319