1 /*
2 * Copyright (C) 2012,2018 Collabora Ltd.
3 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
4 * Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "../gstjniutils.h"
27 #include "../gstamc-format.h"
28 #include "gstamc-internal-jni.h"
29
30 static struct
31 {
32 jclass klass;
33 jmethodID create_audio_format;
34 jmethodID create_video_format;
35 jmethodID to_string;
36 jmethodID get_float;
37 jmethodID set_float;
38 jmethodID get_integer;
39 jmethodID set_integer;
40 jmethodID get_string;
41 jmethodID set_string;
42 jmethodID get_byte_buffer;
43 jmethodID set_byte_buffer;
44 } media_format;
45
46 gboolean
gst_amc_format_static_init(void)47 gst_amc_format_static_init (void)
48 {
49 gboolean ret = TRUE;
50 JNIEnv *env;
51 jclass tmp;
52
53 env = gst_amc_jni_get_env ();
54
55 tmp = (*env)->FindClass (env, "android/media/MediaFormat");
56 if (!tmp) {
57 ret = FALSE;
58 GST_ERROR ("Failed to get format class");
59 if ((*env)->ExceptionCheck (env)) {
60 (*env)->ExceptionDescribe (env);
61 (*env)->ExceptionClear (env);
62 }
63 goto done;
64 }
65 media_format.klass = (*env)->NewGlobalRef (env, tmp);
66 if (!media_format.klass) {
67 ret = FALSE;
68 GST_ERROR ("Failed to get format class global reference");
69 if ((*env)->ExceptionCheck (env)) {
70 (*env)->ExceptionDescribe (env);
71 (*env)->ExceptionClear (env);
72 }
73 goto done;
74 }
75 (*env)->DeleteLocalRef (env, tmp);
76 tmp = NULL;
77
78 media_format.create_audio_format =
79 (*env)->GetStaticMethodID (env, media_format.klass, "createAudioFormat",
80 "(Ljava/lang/String;II)Landroid/media/MediaFormat;");
81 media_format.create_video_format =
82 (*env)->GetStaticMethodID (env, media_format.klass, "createVideoFormat",
83 "(Ljava/lang/String;II)Landroid/media/MediaFormat;");
84 media_format.to_string =
85 (*env)->GetMethodID (env, media_format.klass, "toString",
86 "()Ljava/lang/String;");
87 media_format.get_float =
88 (*env)->GetMethodID (env, media_format.klass, "getFloat",
89 "(Ljava/lang/String;)F");
90 media_format.set_float =
91 (*env)->GetMethodID (env, media_format.klass, "setFloat",
92 "(Ljava/lang/String;F)V");
93 media_format.get_integer =
94 (*env)->GetMethodID (env, media_format.klass, "getInteger",
95 "(Ljava/lang/String;)I");
96 media_format.set_integer =
97 (*env)->GetMethodID (env, media_format.klass, "setInteger",
98 "(Ljava/lang/String;I)V");
99 media_format.get_string =
100 (*env)->GetMethodID (env, media_format.klass, "getString",
101 "(Ljava/lang/String;)Ljava/lang/String;");
102 media_format.set_string =
103 (*env)->GetMethodID (env, media_format.klass, "setString",
104 "(Ljava/lang/String;Ljava/lang/String;)V");
105 media_format.get_byte_buffer =
106 (*env)->GetMethodID (env, media_format.klass, "getByteBuffer",
107 "(Ljava/lang/String;)Ljava/nio/ByteBuffer;");
108 media_format.set_byte_buffer =
109 (*env)->GetMethodID (env, media_format.klass, "setByteBuffer",
110 "(Ljava/lang/String;Ljava/nio/ByteBuffer;)V");
111 if (!media_format.create_audio_format || !media_format.create_video_format
112 || !media_format.get_float || !media_format.set_float
113 || !media_format.get_integer || !media_format.set_integer
114 || !media_format.get_string || !media_format.set_string
115 || !media_format.get_byte_buffer || !media_format.set_byte_buffer) {
116 ret = FALSE;
117 GST_ERROR ("Failed to get format methods");
118 if ((*env)->ExceptionCheck (env)) {
119 (*env)->ExceptionDescribe (env);
120 (*env)->ExceptionClear (env);
121 }
122 goto done;
123 }
124
125 done:
126 if (tmp)
127 (*env)->DeleteLocalRef (env, tmp);
128 tmp = NULL;
129
130 return ret;
131 }
132
133 GstAmcFormat *
gst_amc_format_new_audio(const gchar * mime,gint sample_rate,gint channels,GError ** err)134 gst_amc_format_new_audio (const gchar * mime, gint sample_rate, gint channels,
135 GError ** err)
136 {
137 JNIEnv *env;
138 GstAmcFormat *format = NULL;
139 jstring mime_str;
140
141 g_return_val_if_fail (mime != NULL, NULL);
142
143 env = gst_amc_jni_get_env ();
144
145 mime_str = gst_amc_jni_string_from_gchar (env, err, FALSE, mime);
146 if (!mime_str)
147 goto error;
148
149 format = g_slice_new0 (GstAmcFormat);
150 format->object =
151 gst_amc_jni_new_object_from_static (env, err, TRUE, media_format.klass,
152 media_format.create_audio_format, mime_str, sample_rate, channels);
153 if (!format->object)
154 goto error;
155
156 done:
157 if (mime_str)
158 gst_amc_jni_object_local_unref (env, mime_str);
159 mime_str = NULL;
160
161 return format;
162
163 error:
164 if (format)
165 g_slice_free (GstAmcFormat, format);
166 format = NULL;
167 goto done;
168 }
169
170 GstAmcFormat *
gst_amc_format_new_video(const gchar * mime,gint width,gint height,GError ** err)171 gst_amc_format_new_video (const gchar * mime, gint width, gint height,
172 GError ** err)
173 {
174 JNIEnv *env;
175 GstAmcFormat *format = NULL;
176 jstring mime_str;
177
178 g_return_val_if_fail (mime != NULL, NULL);
179
180 env = gst_amc_jni_get_env ();
181
182 mime_str = gst_amc_jni_string_from_gchar (env, err, FALSE, mime);
183 if (!mime_str)
184 goto error;
185
186 format = g_slice_new0 (GstAmcFormat);
187 format->object =
188 gst_amc_jni_new_object_from_static (env, err, TRUE, media_format.klass,
189 media_format.create_video_format, mime_str, width, height);
190 if (!format->object)
191 goto error;
192
193 done:
194 if (mime_str)
195 gst_amc_jni_object_local_unref (env, mime_str);
196 mime_str = NULL;
197
198 return format;
199
200 error:
201 if (format)
202 g_slice_free (GstAmcFormat, format);
203 format = NULL;
204 goto done;
205 }
206
207 void
gst_amc_format_free(GstAmcFormat * format)208 gst_amc_format_free (GstAmcFormat * format)
209 {
210 JNIEnv *env;
211
212 g_return_if_fail (format != NULL);
213
214 env = gst_amc_jni_get_env ();
215 gst_amc_jni_object_unref (env, format->object);
216 g_slice_free (GstAmcFormat, format);
217 }
218
219 gchar *
gst_amc_format_to_string(GstAmcFormat * format,GError ** err)220 gst_amc_format_to_string (GstAmcFormat * format, GError ** err)
221 {
222 JNIEnv *env;
223 jstring v_str = NULL;
224 gchar *ret = NULL;
225
226 g_return_val_if_fail (format != NULL, FALSE);
227
228 env = gst_amc_jni_get_env ();
229
230 if (!gst_amc_jni_call_object_method (env, err, format->object,
231 media_format.to_string, &v_str))
232 goto done;
233 ret = gst_amc_jni_string_to_gchar (env, v_str, TRUE);
234
235 done:
236
237 return ret;
238 }
239
240 gboolean
gst_amc_format_get_float(GstAmcFormat * format,const gchar * key,gfloat * value,GError ** err)241 gst_amc_format_get_float (GstAmcFormat * format, const gchar * key,
242 gfloat * value, GError ** err)
243 {
244 JNIEnv *env;
245 gboolean ret = FALSE;
246 jstring key_str = NULL;
247
248 g_return_val_if_fail (format != NULL, FALSE);
249 g_return_val_if_fail (key != NULL, FALSE);
250 g_return_val_if_fail (value != NULL, FALSE);
251
252 *value = 0;
253 env = gst_amc_jni_get_env ();
254
255 key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
256 if (!key_str)
257 goto done;
258
259 if (!gst_amc_jni_call_float_method (env, err, format->object,
260 media_format.get_float, value, key_str))
261 goto done;
262 ret = TRUE;
263
264 done:
265 if (key_str)
266 gst_amc_jni_object_local_unref (env, key_str);
267
268 return ret;
269 }
270
271 gboolean
gst_amc_format_set_float(GstAmcFormat * format,const gchar * key,gfloat value,GError ** err)272 gst_amc_format_set_float (GstAmcFormat * format, const gchar * key,
273 gfloat value, GError ** err)
274 {
275 JNIEnv *env;
276 jstring key_str = NULL;
277 gboolean ret = FALSE;
278
279 g_return_val_if_fail (format != NULL, FALSE);
280 g_return_val_if_fail (key != NULL, FALSE);
281
282 env = gst_amc_jni_get_env ();
283
284 key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
285 if (!key_str)
286 goto done;
287
288 if (!gst_amc_jni_call_void_method (env, err, format->object,
289 media_format.set_float, key_str, value))
290 goto done;
291
292 ret = TRUE;
293
294 done:
295 if (key_str)
296 gst_amc_jni_object_local_unref (env, key_str);
297
298 return ret;
299 }
300
301 gboolean
gst_amc_format_get_int(GstAmcFormat * format,const gchar * key,gint * value,GError ** err)302 gst_amc_format_get_int (GstAmcFormat * format, const gchar * key, gint * value,
303 GError ** err)
304 {
305 JNIEnv *env;
306 gboolean ret = FALSE;
307 jstring key_str = NULL;
308
309 g_return_val_if_fail (format != NULL, FALSE);
310 g_return_val_if_fail (key != NULL, FALSE);
311 g_return_val_if_fail (value != NULL, FALSE);
312
313 *value = 0;
314 env = gst_amc_jni_get_env ();
315
316 key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
317 if (!key_str)
318 goto done;
319
320 if (!gst_amc_jni_call_int_method (env, err, format->object,
321 media_format.get_integer, value, key_str))
322 goto done;
323 ret = TRUE;
324
325 done:
326 if (key_str)
327 gst_amc_jni_object_local_unref (env, key_str);
328
329 return ret;
330
331 }
332
333 gboolean
gst_amc_format_set_int(GstAmcFormat * format,const gchar * key,gint value,GError ** err)334 gst_amc_format_set_int (GstAmcFormat * format, const gchar * key, gint value,
335 GError ** err)
336 {
337 JNIEnv *env;
338 jstring key_str = NULL;
339 gboolean ret = FALSE;
340
341 g_return_val_if_fail (format != NULL, FALSE);
342 g_return_val_if_fail (key != NULL, FALSE);
343
344 env = gst_amc_jni_get_env ();
345
346 key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
347 if (!key_str)
348 goto done;
349
350 if (!gst_amc_jni_call_void_method (env, err, format->object,
351 media_format.set_integer, key_str, value))
352 goto done;
353
354 ret = TRUE;
355
356 done:
357 if (key_str)
358 gst_amc_jni_object_local_unref (env, key_str);
359
360 return ret;
361 }
362
363 gboolean
gst_amc_format_get_string(GstAmcFormat * format,const gchar * key,gchar ** value,GError ** err)364 gst_amc_format_get_string (GstAmcFormat * format, const gchar * key,
365 gchar ** value, GError ** err)
366 {
367 JNIEnv *env;
368 gboolean ret = FALSE;
369 jstring key_str = NULL;
370 jstring v_str = NULL;
371
372 g_return_val_if_fail (format != NULL, FALSE);
373 g_return_val_if_fail (key != NULL, FALSE);
374 g_return_val_if_fail (value != NULL, FALSE);
375
376 *value = 0;
377 env = gst_amc_jni_get_env ();
378
379 key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
380 if (!key_str)
381 goto done;
382
383 if (!gst_amc_jni_call_object_method (env, err, format->object,
384 media_format.get_string, &v_str, key_str))
385 goto done;
386
387 *value = gst_amc_jni_string_to_gchar (env, v_str, TRUE);
388
389 ret = TRUE;
390
391 done:
392 if (key_str)
393 gst_amc_jni_object_local_unref (env, key_str);
394
395 return ret;
396 }
397
398 gboolean
gst_amc_format_set_string(GstAmcFormat * format,const gchar * key,const gchar * value,GError ** err)399 gst_amc_format_set_string (GstAmcFormat * format, const gchar * key,
400 const gchar * value, GError ** err)
401 {
402 JNIEnv *env;
403 jstring key_str = NULL;
404 jstring v_str = NULL;
405 gboolean ret = FALSE;
406
407 g_return_val_if_fail (format != NULL, FALSE);
408 g_return_val_if_fail (key != NULL, FALSE);
409 g_return_val_if_fail (value != NULL, FALSE);
410
411 env = gst_amc_jni_get_env ();
412
413 key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
414 if (!key_str)
415 goto done;
416
417 v_str = gst_amc_jni_string_from_gchar (env, err, FALSE, value);
418 if (!v_str)
419 goto done;
420
421 if (!gst_amc_jni_call_void_method (env, err, format->object,
422 media_format.set_string, key_str, v_str))
423 goto done;
424
425 ret = TRUE;
426
427 done:
428 if (key_str)
429 gst_amc_jni_object_local_unref (env, key_str);
430 if (v_str)
431 gst_amc_jni_object_local_unref (env, v_str);
432
433 return ret;
434 }
435
436 gboolean
gst_amc_format_get_buffer(GstAmcFormat * format,const gchar * key,guint8 ** data,gsize * size,GError ** err)437 gst_amc_format_get_buffer (GstAmcFormat * format, const gchar * key,
438 guint8 ** data, gsize * size, GError ** err)
439 {
440 JNIEnv *env;
441 gboolean ret = FALSE;
442 jstring key_str = NULL;
443 jobject v = NULL;
444 RealBuffer buf = { 0, };
445 gint position = 0, limit = 0;
446
447 g_return_val_if_fail (format != NULL, FALSE);
448 g_return_val_if_fail (key != NULL, FALSE);
449 g_return_val_if_fail (data != NULL, FALSE);
450 g_return_val_if_fail (size != NULL, FALSE);
451
452 *data = NULL;
453 *size = 0;
454 env = gst_amc_jni_get_env ();
455
456 key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
457 if (!key_str)
458 goto done;
459
460 if (!gst_amc_jni_call_object_method (env, err, format->object,
461 media_format.get_byte_buffer, &v, key_str))
462 goto done;
463
464 *data = (*env)->GetDirectBufferAddress (env, v);
465 if (*data == NULL) {
466 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
467 GST_LIBRARY_ERROR_FAILED, "Failed get buffer address");
468 goto done;
469 }
470 *size = (*env)->GetDirectBufferCapacity (env, v);
471
472 buf.object = v;
473 buf.data = *data;
474 buf.size = *size;
475 gst_amc_buffer_get_position_and_limit (&buf, NULL, &position, &limit);
476 *size = limit;
477
478 *data = g_memdup2 (*data + position, limit);
479
480 ret = TRUE;
481
482 done:
483 if (key_str)
484 gst_amc_jni_object_local_unref (env, key_str);
485 if (v)
486 gst_amc_jni_object_local_unref (env, v);
487
488 return ret;
489 }
490
491 gboolean
gst_amc_format_set_buffer(GstAmcFormat * format,const gchar * key,guint8 * data,gsize size,GError ** err)492 gst_amc_format_set_buffer (GstAmcFormat * format, const gchar * key,
493 guint8 * data, gsize size, GError ** err)
494 {
495 JNIEnv *env;
496 jstring key_str = NULL;
497 jobject v = NULL;
498 gboolean ret = FALSE;
499 RealBuffer buf = { 0, };
500
501 g_return_val_if_fail (format != NULL, FALSE);
502 g_return_val_if_fail (key != NULL, FALSE);
503 g_return_val_if_fail (data != NULL, FALSE);
504
505 env = gst_amc_jni_get_env ();
506
507 key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
508 if (!key_str)
509 goto done;
510
511 /* FIXME: The memory must remain valid until the codec is stopped */
512 v = (*env)->NewDirectByteBuffer (env, data, size);
513 if (!v) {
514 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
515 GST_LIBRARY_ERROR_FAILED, "Failed create Java byte buffer");
516 goto done;
517 }
518
519 buf.object = v;
520 buf.data = data;
521 buf.size = size;
522
523 gst_amc_buffer_set_position_and_limit ((GstAmcBuffer *) & buf, NULL, 0, size);
524
525 if (!gst_amc_jni_call_void_method (env, err, format->object,
526 media_format.set_byte_buffer, key_str, v))
527 goto done;
528
529 ret = TRUE;
530
531 done:
532 if (key_str)
533 gst_amc_jni_object_local_unref (env, key_str);
534 if (v)
535 gst_amc_jni_object_local_unref (env, v);
536
537 return ret;
538 }
539