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-codec.h"
28 #include "../gstamc-constants.h"
29 #include "gstamc-internal-jni.h"
30 #include "gstamcsurfacetexture-jni.h"
31 #include "gstamcsurface.h"
32
33 #define PARAMETER_KEY_REQUEST_SYNC_FRAME "request-sync"
34 #define PARAMETER_KEY_VIDEO_BITRATE "video-bitrate"
35
36 struct _GstAmcCodec
37 {
38 jobject object; /* global reference */
39
40 RealBuffer *input_buffers, *output_buffers;
41 gsize n_input_buffers, n_output_buffers;
42 GstAmcSurface *surface;
43 gboolean is_encoder;
44 };
45
46 static struct
47 {
48 jclass klass;
49 jmethodID configure;
50 jmethodID create_by_codec_name;
51 jmethodID dequeue_input_buffer;
52 jmethodID dequeue_output_buffer;
53 jmethodID flush;
54 jmethodID get_input_buffers;
55 jmethodID get_input_buffer;
56 jmethodID get_output_buffers;
57 jmethodID get_output_buffer;
58 jmethodID get_output_format;
59 jmethodID queue_input_buffer;
60 jmethodID release;
61 jmethodID release_output_buffer;
62 jmethodID start;
63 jmethodID stop;
64 jmethodID setParameters;
65 } media_codec;
66
67 static struct
68 {
69 jclass klass;
70 jmethodID constructor;
71 jfieldID flags;
72 jfieldID offset;
73 jfieldID presentation_time_us;
74 jfieldID size;
75 } media_codec_buffer_info;
76
77 static struct
78 {
79 jclass klass;
80 jmethodID constructor;
81 jmethodID putInt;
82 } bundle_class;
83
84 static struct
85 {
86 jclass klass;
87 jmethodID get_limit, get_position;
88 jmethodID set_limit, set_position;
89 jmethodID clear;
90 } java_nio_buffer;
91
92 gboolean
gst_amc_codec_static_init(void)93 gst_amc_codec_static_init (void)
94 {
95 gboolean ret = TRUE;
96 JNIEnv *env;
97 jclass tmp;
98 GError *err = NULL;
99
100 env = gst_amc_jni_get_env ();
101
102 java_nio_buffer.klass = gst_amc_jni_get_class (env, &err, "java/nio/Buffer");
103 if (!java_nio_buffer.klass) {
104 GST_ERROR ("Failed to get java.nio.Buffer class: %s", err->message);
105 g_clear_error (&err);
106 return FALSE;
107 }
108
109 java_nio_buffer.get_limit =
110 gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "limit",
111 "()I");
112 if (!java_nio_buffer.get_limit) {
113 GST_ERROR ("Failed to get java.nio.Buffer limit(): %s", err->message);
114 g_clear_error (&err);
115 return FALSE;
116 }
117
118 java_nio_buffer.get_position =
119 gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "position",
120 "()I");
121 if (!java_nio_buffer.get_position) {
122 GST_ERROR ("Failed to get java.nio.Buffer position(): %s", err->message);
123 g_clear_error (&err);
124 return FALSE;
125 }
126
127 java_nio_buffer.set_limit =
128 gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "limit",
129 "(I)Ljava/nio/Buffer;");
130 if (!java_nio_buffer.set_limit) {
131 GST_ERROR ("Failed to get java.nio.Buffer limit(): %s", err->message);
132 g_clear_error (&err);
133 return FALSE;
134 }
135
136 java_nio_buffer.set_position =
137 gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "position",
138 "(I)Ljava/nio/Buffer;");
139 if (!java_nio_buffer.set_position) {
140 GST_ERROR ("Failed to get java.nio.Buffer position(): %s", err->message);
141 g_clear_error (&err);
142 return FALSE;
143 }
144
145 java_nio_buffer.clear =
146 gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "clear",
147 "()Ljava/nio/Buffer;");
148 if (!java_nio_buffer.clear) {
149 GST_ERROR ("Failed to get java.nio.Buffer clear(): %s", err->message);
150 g_clear_error (&err);
151 return FALSE;
152 }
153
154 tmp = (*env)->FindClass (env, "android/media/MediaCodec$BufferInfo");
155 if (!tmp) {
156 ret = FALSE;
157 (*env)->ExceptionClear (env);
158 GST_ERROR ("Failed to get codec buffer info class");
159 goto done;
160 }
161 media_codec_buffer_info.klass = (*env)->NewGlobalRef (env, tmp);
162 if (!media_codec_buffer_info.klass) {
163 ret = FALSE;
164 GST_ERROR ("Failed to get codec buffer info class global reference");
165 if ((*env)->ExceptionCheck (env)) {
166 (*env)->ExceptionDescribe (env);
167 (*env)->ExceptionClear (env);
168 }
169 goto done;
170 }
171 (*env)->DeleteLocalRef (env, tmp);
172 tmp = NULL;
173
174 media_codec_buffer_info.constructor =
175 (*env)->GetMethodID (env, media_codec_buffer_info.klass, "<init>", "()V");
176 media_codec_buffer_info.flags =
177 (*env)->GetFieldID (env, media_codec_buffer_info.klass, "flags", "I");
178 media_codec_buffer_info.offset =
179 (*env)->GetFieldID (env, media_codec_buffer_info.klass, "offset", "I");
180 media_codec_buffer_info.presentation_time_us =
181 (*env)->GetFieldID (env, media_codec_buffer_info.klass,
182 "presentationTimeUs", "J");
183 media_codec_buffer_info.size =
184 (*env)->GetFieldID (env, media_codec_buffer_info.klass, "size", "I");
185 if (!media_codec_buffer_info.constructor || !media_codec_buffer_info.flags
186 || !media_codec_buffer_info.offset
187 || !media_codec_buffer_info.presentation_time_us
188 || !media_codec_buffer_info.size) {
189 ret = FALSE;
190 GST_ERROR ("Failed to get buffer info methods and fields");
191 if ((*env)->ExceptionCheck (env)) {
192 (*env)->ExceptionDescribe (env);
193 (*env)->ExceptionClear (env);
194 }
195 goto done;
196 }
197
198 tmp = (*env)->FindClass (env, "android/media/MediaCodec");
199 if (!tmp) {
200 ret = FALSE;
201 GST_ERROR ("Failed to get codec class");
202 if ((*env)->ExceptionCheck (env)) {
203 (*env)->ExceptionDescribe (env);
204 (*env)->ExceptionClear (env);
205 }
206 goto done;
207 }
208 media_codec.klass = (*env)->NewGlobalRef (env, tmp);
209 if (!media_codec.klass) {
210 ret = FALSE;
211 GST_ERROR ("Failed to get codec class global reference");
212 if ((*env)->ExceptionCheck (env)) {
213 (*env)->ExceptionDescribe (env);
214 (*env)->ExceptionClear (env);
215 }
216 goto done;
217 }
218 (*env)->DeleteLocalRef (env, tmp);
219 tmp = NULL;
220
221 media_codec.create_by_codec_name =
222 (*env)->GetStaticMethodID (env, media_codec.klass, "createByCodecName",
223 "(Ljava/lang/String;)Landroid/media/MediaCodec;");
224 media_codec.configure =
225 (*env)->GetMethodID (env, media_codec.klass, "configure",
226 "(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V");
227 media_codec.dequeue_input_buffer =
228 (*env)->GetMethodID (env, media_codec.klass, "dequeueInputBuffer",
229 "(J)I");
230 media_codec.dequeue_output_buffer =
231 (*env)->GetMethodID (env, media_codec.klass, "dequeueOutputBuffer",
232 "(Landroid/media/MediaCodec$BufferInfo;J)I");
233 media_codec.flush =
234 (*env)->GetMethodID (env, media_codec.klass, "flush", "()V");
235 media_codec.get_input_buffers =
236 (*env)->GetMethodID (env, media_codec.klass, "getInputBuffers",
237 "()[Ljava/nio/ByteBuffer;");
238 media_codec.get_output_buffers =
239 (*env)->GetMethodID (env, media_codec.klass, "getOutputBuffers",
240 "()[Ljava/nio/ByteBuffer;");
241 media_codec.get_output_format =
242 (*env)->GetMethodID (env, media_codec.klass, "getOutputFormat",
243 "()Landroid/media/MediaFormat;");
244 media_codec.queue_input_buffer =
245 (*env)->GetMethodID (env, media_codec.klass, "queueInputBuffer",
246 "(IIIJI)V");
247 media_codec.release =
248 (*env)->GetMethodID (env, media_codec.klass, "release", "()V");
249 media_codec.release_output_buffer =
250 (*env)->GetMethodID (env, media_codec.klass, "releaseOutputBuffer",
251 "(IZ)V");
252 media_codec.start =
253 (*env)->GetMethodID (env, media_codec.klass, "start", "()V");
254 media_codec.stop =
255 (*env)->GetMethodID (env, media_codec.klass, "stop", "()V");
256
257 if (!media_codec.configure ||
258 !media_codec.create_by_codec_name ||
259 !media_codec.dequeue_input_buffer ||
260 !media_codec.dequeue_output_buffer ||
261 !media_codec.flush ||
262 !media_codec.get_input_buffers ||
263 !media_codec.get_output_buffers ||
264 !media_codec.get_output_format ||
265 !media_codec.queue_input_buffer ||
266 !media_codec.release ||
267 !media_codec.release_output_buffer ||
268 !media_codec.start || !media_codec.stop) {
269 ret = FALSE;
270 GST_ERROR ("Failed to get codec methods");
271 if ((*env)->ExceptionCheck (env)) {
272 (*env)->ExceptionDescribe (env);
273 (*env)->ExceptionClear (env);
274 }
275 goto done;
276 }
277 media_codec.setParameters =
278 (*env)->GetMethodID (env, media_codec.klass, "setParameters",
279 "(Landroid/os/Bundle;)V");
280 if ((*env)->ExceptionCheck (env))
281 (*env)->ExceptionClear (env);
282
283 /* Android >= 21 */
284 media_codec.get_output_buffer =
285 (*env)->GetMethodID (env, media_codec.klass, "getOutputBuffer",
286 "(I)Ljava/nio/ByteBuffer;");
287 if ((*env)->ExceptionCheck (env))
288 (*env)->ExceptionClear (env);
289
290 /* Android >= 21 */
291 media_codec.get_input_buffer =
292 (*env)->GetMethodID (env, media_codec.klass, "getInputBuffer",
293 "(I)Ljava/nio/ByteBuffer;");
294 if ((*env)->ExceptionCheck (env))
295 (*env)->ExceptionClear (env);
296
297 if (media_codec.setParameters != NULL) {
298 /* Bundle needed for parameter setting on Android >= 19 */
299 tmp = (*env)->FindClass (env, "android/os/Bundle");
300 if (!tmp) {
301 ret = FALSE;
302 GST_ERROR ("Failed to get Bundle class");
303 if ((*env)->ExceptionCheck (env)) {
304 (*env)->ExceptionDescribe (env);
305 (*env)->ExceptionClear (env);
306 }
307 goto done;
308 }
309 bundle_class.klass = (*env)->NewGlobalRef (env, tmp);
310 if (!bundle_class.klass) {
311 ret = FALSE;
312 GST_ERROR ("Failed to get Bundle class global reference");
313 if ((*env)->ExceptionCheck (env)) {
314 (*env)->ExceptionDescribe (env);
315 (*env)->ExceptionClear (env);
316 }
317 goto done;
318 }
319 (*env)->DeleteLocalRef (env, tmp);
320 tmp = NULL;
321
322 bundle_class.constructor =
323 (*env)->GetMethodID (env, bundle_class.klass, "<init>", "()V");
324 bundle_class.putInt =
325 (*env)->GetMethodID (env, bundle_class.klass, "putInt",
326 "(Ljava/lang/String;I)V");
327 if (!bundle_class.constructor || !bundle_class.putInt) {
328 ret = FALSE;
329 GST_ERROR ("Failed to get Bundle methods");
330 if ((*env)->ExceptionCheck (env)) {
331 (*env)->ExceptionDescribe (env);
332 (*env)->ExceptionClear (env);
333 }
334 goto done;
335 }
336 }
337
338 done:
339 if (tmp)
340 (*env)->DeleteLocalRef (env, tmp);
341 tmp = NULL;
342
343 return ret;
344 }
345
346 static void
gst_amc_jni_free_buffer_array(JNIEnv * env,RealBuffer * buffers,gsize n_buffers)347 gst_amc_jni_free_buffer_array (JNIEnv * env, RealBuffer * buffers,
348 gsize n_buffers)
349 {
350 jsize i;
351
352 g_return_if_fail (buffers != NULL);
353
354 for (i = 0; i < n_buffers; i++) {
355 if (buffers[i].object)
356 gst_amc_jni_object_unref (env, buffers[i].object);
357 }
358 g_free (buffers);
359 }
360
361 static gboolean
gst_amc_jni_get_buffer_array(JNIEnv * env,GError ** err,jobject array,RealBuffer ** buffers_,gsize * n_buffers)362 gst_amc_jni_get_buffer_array (JNIEnv * env, GError ** err, jobject array,
363 RealBuffer ** buffers_, gsize * n_buffers)
364 {
365 RealBuffer **buffers = (RealBuffer **) buffers_;
366 jsize i;
367
368 *n_buffers = (*env)->GetArrayLength (env, array);
369 *buffers = g_new0 (RealBuffer, *n_buffers);
370
371 for (i = 0; i < *n_buffers; i++) {
372 jobject buffer = NULL;
373
374 buffer = (*env)->GetObjectArrayElement (env, array, i);
375 if ((*env)->ExceptionCheck (env)) {
376 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
377 GST_LIBRARY_ERROR_FAILED, "Failed to get buffer %d", i);
378 goto error;
379 }
380
381 /* NULL buffers are not a problem and are happening when we configured
382 * a surface as input/output */
383 if (!buffer)
384 continue;
385
386 (*buffers)[i].object = gst_amc_jni_object_make_global (env, buffer);
387 if (!(*buffers)[i].object) {
388 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
389 GST_LIBRARY_ERROR_FAILED,
390 "Failed to create global buffer reference %d", i);
391 goto error;
392 }
393
394 (*buffers)[i].data =
395 (*env)->GetDirectBufferAddress (env, (*buffers)[i].object);
396 if (!(*buffers)[i].data) {
397 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
398 GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address %d", i);
399 goto error;
400 }
401 (*buffers)[i].size =
402 (*env)->GetDirectBufferCapacity (env, (*buffers)[i].object);
403 }
404
405 return TRUE;
406
407 error:
408 if (*buffers)
409 gst_amc_jni_free_buffer_array (env, *buffers, *n_buffers);
410 *buffers = NULL;
411 *n_buffers = 0;
412 return FALSE;
413 }
414
415 void
gst_amc_buffer_free(GstAmcBuffer * buffer_)416 gst_amc_buffer_free (GstAmcBuffer * buffer_)
417 {
418 RealBuffer *buffer = (RealBuffer *) buffer_;
419 JNIEnv *env;
420
421 g_return_if_fail (buffer != NULL);
422
423 env = gst_amc_jni_get_env ();
424
425 if (buffer->object)
426 gst_amc_jni_object_unref (env, buffer->object);
427 g_free (buffer);
428 }
429
430 static GstAmcBuffer *
gst_amc_buffer_copy(RealBuffer * buffer)431 gst_amc_buffer_copy (RealBuffer * buffer)
432 {
433 JNIEnv *env;
434 RealBuffer *ret;
435
436 g_return_val_if_fail (buffer != NULL, NULL);
437
438 env = gst_amc_jni_get_env ();
439
440 ret = g_new0 (RealBuffer, 1);
441
442 ret->object = gst_amc_jni_object_ref (env, buffer->object);
443 ret->data = buffer->data;
444 ret->size = buffer->size;
445
446 return (GstAmcBuffer *) ret;
447 }
448
449 gboolean
gst_amc_buffer_get_position_and_limit(RealBuffer * buffer_,GError ** err,gint * position,gint * limit)450 gst_amc_buffer_get_position_and_limit (RealBuffer * buffer_, GError ** err,
451 gint * position, gint * limit)
452 {
453 RealBuffer *buffer = (RealBuffer *) buffer_;
454 JNIEnv *env;
455
456 g_return_val_if_fail (buffer != NULL, FALSE);
457 g_return_val_if_fail (buffer->object != NULL, FALSE);
458
459 env = gst_amc_jni_get_env ();
460
461 if (!gst_amc_jni_call_int_method (env, err, buffer->object,
462 java_nio_buffer.get_position, position))
463 return FALSE;
464
465 if (!gst_amc_jni_call_int_method (env, err, buffer->object,
466 java_nio_buffer.get_limit, limit))
467 return FALSE;
468
469 return TRUE;
470 }
471
472 gboolean
gst_amc_buffer_set_position_and_limit(GstAmcBuffer * buffer_,GError ** err,gint position,gint limit)473 gst_amc_buffer_set_position_and_limit (GstAmcBuffer * buffer_, GError ** err,
474 gint position, gint limit)
475 {
476 RealBuffer *buffer = (RealBuffer *) buffer_;
477 JNIEnv *env;
478 jobject tmp;
479
480 g_return_val_if_fail (buffer != NULL, FALSE);
481 g_return_val_if_fail (buffer->object != NULL, FALSE);
482
483 env = gst_amc_jni_get_env ();
484
485 if (!gst_amc_jni_call_object_method (env, err, buffer->object,
486 java_nio_buffer.set_limit, &tmp, limit))
487 return FALSE;
488
489 gst_amc_jni_object_local_unref (env, tmp);
490
491 if (!gst_amc_jni_call_object_method (env, err, buffer->object,
492 java_nio_buffer.set_position, &tmp, position))
493 return FALSE;
494
495 gst_amc_jni_object_local_unref (env, tmp);
496
497 return TRUE;
498 }
499
500 GstAmcCodec *
gst_amc_codec_new(const gchar * name,gboolean is_encoder,GError ** err)501 gst_amc_codec_new (const gchar * name, gboolean is_encoder, GError ** err)
502 {
503 JNIEnv *env;
504 GstAmcCodec *codec = NULL;
505 jstring name_str;
506 jobject object = NULL;
507
508 g_return_val_if_fail (name != NULL, NULL);
509
510 env = gst_amc_jni_get_env ();
511
512 name_str = gst_amc_jni_string_from_gchar (env, err, FALSE, name);
513 if (!name_str) {
514 goto error;
515 }
516
517 codec = g_slice_new0 (GstAmcCodec);
518 codec->is_encoder = is_encoder;
519
520 if (!gst_amc_jni_call_static_object_method (env, err, media_codec.klass,
521 media_codec.create_by_codec_name, &object, name_str))
522 goto error;
523
524 codec->object = gst_amc_jni_object_make_global (env, object);
525 object = NULL;
526
527 if (!codec->object) {
528 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
529 GST_LIBRARY_ERROR_SETTINGS, "Failed to create global codec reference");
530 goto error;
531 }
532
533 done:
534 if (name_str)
535 gst_amc_jni_object_local_unref (env, name_str);
536 name_str = NULL;
537
538 return codec;
539
540 error:
541 if (codec)
542 g_slice_free (GstAmcCodec, codec);
543 codec = NULL;
544 goto done;
545 }
546
547 void
gst_amc_codec_free(GstAmcCodec * codec)548 gst_amc_codec_free (GstAmcCodec * codec)
549 {
550 JNIEnv *env;
551
552 g_return_if_fail (codec != NULL);
553
554 env = gst_amc_jni_get_env ();
555
556 if (codec->input_buffers)
557 gst_amc_jni_free_buffer_array (env, codec->input_buffers,
558 codec->n_input_buffers);
559 codec->input_buffers = NULL;
560 codec->n_input_buffers = 0;
561
562 if (codec->output_buffers)
563 gst_amc_jni_free_buffer_array (env, codec->output_buffers,
564 codec->n_output_buffers);
565 codec->output_buffers = NULL;
566 codec->n_output_buffers = 0;
567
568 g_clear_object (&codec->surface);
569
570 gst_amc_jni_object_unref (env, codec->object);
571 g_slice_free (GstAmcCodec, codec);
572 }
573
574 gboolean
gst_amc_codec_configure(GstAmcCodec * codec,GstAmcFormat * format,GstAmcSurfaceTexture * surface,GError ** err)575 gst_amc_codec_configure (GstAmcCodec * codec, GstAmcFormat * format,
576 GstAmcSurfaceTexture * surface, GError ** err)
577 {
578 JNIEnv *env;
579 gint flags = 0;
580
581 g_return_val_if_fail (codec != NULL, FALSE);
582 g_return_val_if_fail (format != NULL, FALSE);
583 g_return_val_if_fail (surface == NULL
584 || GST_IS_AMC_SURFACE_TEXTURE_JNI (surface), FALSE);
585
586 env = gst_amc_jni_get_env ();
587
588 if (surface) {
589 g_object_unref (codec->surface);
590 codec->surface =
591 gst_amc_surface_new ((GstAmcSurfaceTextureJNI *) surface, err);
592 if (!codec->surface)
593 return FALSE;
594 }
595
596 if (codec->is_encoder)
597 flags = 1;
598
599 return gst_amc_jni_call_void_method (env, err, codec->object,
600 media_codec.configure, format->object,
601 codec->surface ? codec->surface->jobject : NULL, NULL, flags);
602 }
603
604 GstAmcFormat *
gst_amc_codec_get_output_format(GstAmcCodec * codec,GError ** err)605 gst_amc_codec_get_output_format (GstAmcCodec * codec, GError ** err)
606 {
607 JNIEnv *env;
608 GstAmcFormat *ret = NULL;
609 jobject object = NULL;
610
611 g_return_val_if_fail (codec != NULL, NULL);
612
613 env = gst_amc_jni_get_env ();
614
615 if (!gst_amc_jni_call_object_method (env, err, codec->object,
616 media_codec.get_output_format, &object))
617 goto done;
618
619 ret = g_slice_new0 (GstAmcFormat);
620
621 ret->object = gst_amc_jni_object_make_global (env, object);
622 if (!ret->object) {
623 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
624 GST_LIBRARY_ERROR_SETTINGS, "Failed to create global format reference");
625 g_slice_free (GstAmcFormat, ret);
626 ret = NULL;
627 }
628
629 done:
630
631 return ret;
632 }
633
634 static RealBuffer *
gst_amc_codec_get_input_buffers(GstAmcCodec * codec,gsize * n_buffers,GError ** err)635 gst_amc_codec_get_input_buffers (GstAmcCodec * codec, gsize * n_buffers,
636 GError ** err)
637 {
638 JNIEnv *env;
639 jobject input_buffers = NULL;
640 RealBuffer *ret = NULL;
641
642 g_return_val_if_fail (codec != NULL, NULL);
643 g_return_val_if_fail (n_buffers != NULL, NULL);
644
645 *n_buffers = 0;
646 env = gst_amc_jni_get_env ();
647
648 if (!gst_amc_jni_call_object_method (env, err, codec->object,
649 media_codec.get_input_buffers, &input_buffers))
650 goto done;
651
652 gst_amc_jni_get_buffer_array (env, err, input_buffers, &ret, n_buffers);
653
654 done:
655 if (input_buffers)
656 gst_amc_jni_object_local_unref (env, input_buffers);
657
658 return ret;
659 }
660
661 static RealBuffer *
gst_amc_codec_get_output_buffers(GstAmcCodec * codec,gsize * n_buffers,GError ** err)662 gst_amc_codec_get_output_buffers (GstAmcCodec * codec, gsize * n_buffers,
663 GError ** err)
664 {
665 JNIEnv *env;
666 jobject output_buffers = NULL;
667 RealBuffer *ret = NULL;
668
669 g_return_val_if_fail (codec != NULL, NULL);
670 g_return_val_if_fail (n_buffers != NULL, NULL);
671
672 *n_buffers = 0;
673 env = gst_amc_jni_get_env ();
674
675 if (!gst_amc_jni_call_object_method (env, err, codec->object,
676 media_codec.get_output_buffers, &output_buffers))
677 goto done;
678
679 gst_amc_jni_get_buffer_array (env, err, output_buffers, &ret, n_buffers);
680
681 done:
682 if (output_buffers)
683 gst_amc_jni_object_local_unref (env, output_buffers);
684
685 return ret;
686 }
687
688 gboolean
gst_amc_codec_start(GstAmcCodec * codec,GError ** err)689 gst_amc_codec_start (GstAmcCodec * codec, GError ** err)
690 {
691 JNIEnv *env;
692 gboolean ret;
693
694 g_return_val_if_fail (codec != NULL, FALSE);
695
696 env = gst_amc_jni_get_env ();
697 ret = gst_amc_jni_call_void_method (env, err, codec->object,
698 media_codec.start);
699 if (!ret)
700 return ret;
701
702 if (!media_codec.get_input_buffer) {
703 if (codec->input_buffers)
704 gst_amc_jni_free_buffer_array (env, codec->input_buffers,
705 codec->n_input_buffers);
706 codec->input_buffers =
707 gst_amc_codec_get_input_buffers (codec, &codec->n_input_buffers, err);
708 if (!codec->input_buffers) {
709 gst_amc_codec_stop (codec, NULL);
710 return FALSE;
711 }
712 }
713
714 return ret;
715 }
716
717 gboolean
gst_amc_codec_stop(GstAmcCodec * codec,GError ** err)718 gst_amc_codec_stop (GstAmcCodec * codec, GError ** err)
719 {
720 JNIEnv *env;
721
722 g_return_val_if_fail (codec != NULL, FALSE);
723
724 env = gst_amc_jni_get_env ();
725
726 if (codec->input_buffers)
727 gst_amc_jni_free_buffer_array (env, codec->input_buffers,
728 codec->n_input_buffers);
729 codec->input_buffers = NULL;
730 codec->n_input_buffers = 0;
731
732 if (codec->output_buffers)
733 gst_amc_jni_free_buffer_array (env, codec->output_buffers,
734 codec->n_output_buffers);
735 codec->output_buffers = NULL;
736 codec->n_output_buffers = 0;
737
738 return gst_amc_jni_call_void_method (env, err, codec->object,
739 media_codec.stop);
740 }
741
742 gboolean
gst_amc_codec_flush(GstAmcCodec * codec,GError ** err)743 gst_amc_codec_flush (GstAmcCodec * codec, GError ** err)
744 {
745 JNIEnv *env;
746
747 g_return_val_if_fail (codec != NULL, FALSE);
748
749 env = gst_amc_jni_get_env ();
750 return gst_amc_jni_call_void_method (env, err, codec->object,
751 media_codec.flush);
752 }
753
754 static gboolean
gst_amc_codec_set_parameter(GstAmcCodec * codec,JNIEnv * env,GError ** err,const gchar * key,int value)755 gst_amc_codec_set_parameter (GstAmcCodec * codec, JNIEnv * env,
756 GError ** err, const gchar * key, int value)
757 {
758 gboolean ret = FALSE;
759 jobject bundle = NULL;
760 jstring jkey = NULL;
761
762 if (media_codec.setParameters == NULL)
763 goto done; // Not available means we're on Android < 19
764
765 bundle = gst_amc_jni_new_object (env, err, FALSE, bundle_class.klass,
766 bundle_class.constructor);
767 if (!bundle)
768 goto done;
769
770 jkey = (*env)->NewStringUTF (env, key);
771 if (!gst_amc_jni_call_void_method (env, err,
772 bundle, bundle_class.putInt, jkey, value))
773 goto done;
774
775 if (!gst_amc_jni_call_void_method (env, err, codec->object,
776 media_codec.setParameters, bundle))
777 goto done;
778
779 ret = TRUE;
780 done:
781 if (jkey)
782 (*env)->DeleteLocalRef (env, jkey);
783 if (bundle)
784 (*env)->DeleteLocalRef (env, bundle);
785 return ret;
786 }
787
788 gboolean
gst_amc_codec_request_key_frame(GstAmcCodec * codec,GError ** err)789 gst_amc_codec_request_key_frame (GstAmcCodec * codec, GError ** err)
790 {
791 JNIEnv *env;
792
793 g_return_val_if_fail (codec != NULL, FALSE);
794
795 env = gst_amc_jni_get_env ();
796 return gst_amc_codec_set_parameter (codec, env, err,
797 PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
798 }
799
800 gboolean
gst_amc_codec_have_dynamic_bitrate()801 gst_amc_codec_have_dynamic_bitrate ()
802 {
803 /* Dynamic bitrate scaling is supported on Android >= 19,
804 * where the setParameters() call is available */
805 return (media_codec.setParameters != NULL);
806 }
807
808 gboolean
gst_amc_codec_set_dynamic_bitrate(GstAmcCodec * codec,GError ** err,gint bitrate)809 gst_amc_codec_set_dynamic_bitrate (GstAmcCodec * codec, GError ** err,
810 gint bitrate)
811 {
812 JNIEnv *env;
813
814 g_return_val_if_fail (codec != NULL, FALSE);
815
816 env = gst_amc_jni_get_env ();
817 return gst_amc_codec_set_parameter (codec, env, err,
818 PARAMETER_KEY_VIDEO_BITRATE, bitrate);
819 }
820
821 gboolean
gst_amc_codec_release(GstAmcCodec * codec,GError ** err)822 gst_amc_codec_release (GstAmcCodec * codec, GError ** err)
823 {
824 JNIEnv *env;
825
826 g_return_val_if_fail (codec != NULL, FALSE);
827
828 env = gst_amc_jni_get_env ();
829
830 if (codec->input_buffers)
831 gst_amc_jni_free_buffer_array (env, codec->input_buffers,
832 codec->n_input_buffers);
833 codec->input_buffers = NULL;
834 codec->n_input_buffers = 0;
835
836 if (codec->output_buffers)
837 gst_amc_jni_free_buffer_array (env, codec->output_buffers,
838 codec->n_output_buffers);
839 codec->output_buffers = NULL;
840 codec->n_output_buffers = 0;
841
842 return gst_amc_jni_call_void_method (env, err, codec->object,
843 media_codec.release);
844 }
845
846 GstAmcBuffer *
gst_amc_codec_get_output_buffer(GstAmcCodec * codec,gint index,GError ** err)847 gst_amc_codec_get_output_buffer (GstAmcCodec * codec, gint index, GError ** err)
848 {
849 JNIEnv *env;
850 jobject buffer = NULL;
851 RealBuffer *ret = NULL;
852
853 g_return_val_if_fail (codec != NULL, NULL);
854 g_return_val_if_fail (index >= 0, NULL);
855
856 env = gst_amc_jni_get_env ();
857
858 if (!media_codec.get_output_buffer) {
859 g_return_val_if_fail (index < codec->n_output_buffers && index >= 0, NULL);
860 if (codec->output_buffers[index].object)
861 return gst_amc_buffer_copy (&codec->output_buffers[index]);
862 else
863 return NULL;
864 }
865
866 if (!gst_amc_jni_call_object_method (env, err, codec->object,
867 media_codec.get_output_buffer, &buffer, index))
868 goto done;
869
870 if (buffer != NULL) {
871 ret = g_new0 (RealBuffer, 1);
872 ret->object = gst_amc_jni_object_make_global (env, buffer);
873 if (!ret->object) {
874 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
875 GST_LIBRARY_ERROR_FAILED, "Failed to create global buffer reference");
876 goto error;
877 }
878
879 ret->data = (*env)->GetDirectBufferAddress (env, ret->object);
880 if (!ret->data) {
881 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
882 GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address");
883 goto error;
884 }
885 ret->size = (*env)->GetDirectBufferCapacity (env, ret->object);
886 }
887
888 done:
889
890 return (GstAmcBuffer *) ret;
891
892 error:
893 if (ret->object)
894 gst_amc_jni_object_unref (env, ret->object);
895 g_free (ret);
896
897 return NULL;
898 }
899
900 GstAmcBuffer *
gst_amc_codec_get_input_buffer(GstAmcCodec * codec,gint index,GError ** err)901 gst_amc_codec_get_input_buffer (GstAmcCodec * codec, gint index, GError ** err)
902 {
903 JNIEnv *env;
904 jobject buffer = NULL;
905 RealBuffer *ret = NULL;
906
907 g_return_val_if_fail (codec != NULL, NULL);
908 g_return_val_if_fail (index >= 0, NULL);
909
910 env = gst_amc_jni_get_env ();
911
912 if (!media_codec.get_input_buffer) {
913 g_return_val_if_fail (index < codec->n_input_buffers && index >= 0, NULL);
914 if (codec->input_buffers[index].object)
915 return gst_amc_buffer_copy (&codec->input_buffers[index]);
916 else
917 return NULL;
918 }
919
920 if (!gst_amc_jni_call_object_method (env, err, codec->object,
921 media_codec.get_input_buffer, &buffer, index))
922 goto done;
923
924 if (buffer != NULL) {
925 ret = g_new0 (RealBuffer, 1);
926 ret->object = gst_amc_jni_object_make_global (env, buffer);
927 if (!ret->object) {
928 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
929 GST_LIBRARY_ERROR_FAILED, "Failed to create global buffer reference");
930 goto error;
931 }
932
933 ret->data = (*env)->GetDirectBufferAddress (env, ret->object);
934 if (!ret->data) {
935 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
936 GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address");
937 goto error;
938 }
939 ret->size = (*env)->GetDirectBufferCapacity (env, ret->object);
940 }
941
942 done:
943
944 return (GstAmcBuffer *) ret;
945
946 error:
947 if (ret->object)
948 gst_amc_jni_object_unref (env, ret->object);
949 g_free (ret);
950
951 return NULL;
952 }
953
954 gint
gst_amc_codec_dequeue_input_buffer(GstAmcCodec * codec,gint64 timeoutUs,GError ** err)955 gst_amc_codec_dequeue_input_buffer (GstAmcCodec * codec, gint64 timeoutUs,
956 GError ** err)
957 {
958 JNIEnv *env;
959 gint ret = G_MININT;
960
961 g_return_val_if_fail (codec != NULL, G_MININT);
962
963 env = gst_amc_jni_get_env ();
964 if (!gst_amc_jni_call_int_method (env, err, codec->object,
965 media_codec.dequeue_input_buffer, &ret, timeoutUs))
966 return G_MININT;
967
968 return ret;
969 }
970
971 static gboolean
gst_amc_codec_fill_buffer_info(JNIEnv * env,jobject buffer_info,GstAmcBufferInfo * info,GError ** err)972 gst_amc_codec_fill_buffer_info (JNIEnv * env, jobject buffer_info,
973 GstAmcBufferInfo * info, GError ** err)
974 {
975 g_return_val_if_fail (buffer_info != NULL, FALSE);
976
977 if (!gst_amc_jni_get_int_field (env, err, buffer_info,
978 media_codec_buffer_info.flags, &info->flags))
979 return FALSE;
980
981 if (!gst_amc_jni_get_int_field (env, err, buffer_info,
982 media_codec_buffer_info.offset, &info->offset))
983 return FALSE;
984
985 if (!gst_amc_jni_get_long_field (env, err, buffer_info,
986 media_codec_buffer_info.presentation_time_us,
987 &info->presentation_time_us))
988 return FALSE;
989
990 if (!gst_amc_jni_get_int_field (env, err, buffer_info,
991 media_codec_buffer_info.size, &info->size))
992 return FALSE;
993
994 return TRUE;
995 }
996
997 gint
gst_amc_codec_dequeue_output_buffer(GstAmcCodec * codec,GstAmcBufferInfo * info,gint64 timeoutUs,GError ** err)998 gst_amc_codec_dequeue_output_buffer (GstAmcCodec * codec,
999 GstAmcBufferInfo * info, gint64 timeoutUs, GError ** err)
1000 {
1001 JNIEnv *env;
1002 gint ret = G_MININT;
1003 jobject info_o = NULL;
1004
1005 g_return_val_if_fail (codec != NULL, G_MININT);
1006
1007 env = gst_amc_jni_get_env ();
1008
1009 info_o =
1010 gst_amc_jni_new_object (env, err, FALSE, media_codec_buffer_info.klass,
1011 media_codec_buffer_info.constructor);
1012 if (!info_o)
1013 goto done;
1014
1015 if (!gst_amc_jni_call_int_method (env, err, codec->object,
1016 media_codec.dequeue_output_buffer, &ret, info_o, timeoutUs)) {
1017 ret = G_MININT;
1018 goto done;
1019 }
1020
1021 if (ret == INFO_OUTPUT_BUFFERS_CHANGED || ret == INFO_OUTPUT_FORMAT_CHANGED
1022 || (ret >= 0 && !codec->output_buffers
1023 && !media_codec.get_output_buffer)) {
1024 if (!media_codec.get_output_buffer) {
1025 if (codec->output_buffers)
1026 gst_amc_jni_free_buffer_array (env, codec->output_buffers,
1027 codec->n_output_buffers);
1028 codec->output_buffers =
1029 gst_amc_codec_get_output_buffers (codec,
1030 &codec->n_output_buffers, err);
1031 if (!codec->output_buffers) {
1032 ret = G_MININT;
1033 goto done;
1034 }
1035 }
1036 if (ret == INFO_OUTPUT_BUFFERS_CHANGED) {
1037 gst_amc_jni_object_local_unref (env, info_o);
1038 return gst_amc_codec_dequeue_output_buffer (codec, info, timeoutUs, err);
1039 }
1040 } else if (ret < 0) {
1041 goto done;
1042 }
1043
1044 if (ret >= 0 && !gst_amc_codec_fill_buffer_info (env, info_o, info, err)) {
1045 ret = G_MININT;
1046 goto done;
1047 }
1048
1049 done:
1050 if (info_o)
1051 gst_amc_jni_object_local_unref (env, info_o);
1052 info_o = NULL;
1053
1054 return ret;
1055 }
1056
1057 gboolean
gst_amc_codec_queue_input_buffer(GstAmcCodec * codec,gint index,const GstAmcBufferInfo * info,GError ** err)1058 gst_amc_codec_queue_input_buffer (GstAmcCodec * codec, gint index,
1059 const GstAmcBufferInfo * info, GError ** err)
1060 {
1061 JNIEnv *env;
1062
1063 g_return_val_if_fail (codec != NULL, FALSE);
1064 g_return_val_if_fail (info != NULL, FALSE);
1065
1066 env = gst_amc_jni_get_env ();
1067 return gst_amc_jni_call_void_method (env, err, codec->object,
1068 media_codec.queue_input_buffer, index, info->offset, info->size,
1069 info->presentation_time_us, info->flags);
1070 }
1071
1072 gboolean
gst_amc_codec_release_output_buffer(GstAmcCodec * codec,gint index,gboolean render,GError ** err)1073 gst_amc_codec_release_output_buffer (GstAmcCodec * codec, gint index,
1074 gboolean render, GError ** err)
1075 {
1076 JNIEnv *env;
1077
1078 g_return_val_if_fail (codec != NULL, FALSE);
1079
1080 env = gst_amc_jni_get_env ();
1081 return gst_amc_jni_call_void_method (env, err, codec->object,
1082 media_codec.release_output_buffer, index, render);
1083 }
1084
1085 GstAmcSurfaceTexture *
gst_amc_codec_new_surface_texture(GError ** err)1086 gst_amc_codec_new_surface_texture (GError ** err)
1087 {
1088 return (GstAmcSurfaceTexture *) gst_amc_surface_texture_jni_new (err);
1089 }
1090