• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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