1 /*
2  * Copyright (C) 2012, 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 #ifdef HAVE_ORC
27 #include <orc/orc.h>
28 #else
29 #define orc_memcpy memcpy
30 #endif
31 
32 #include "gstahcsrc.h"
33 #include "gstahssrc.h"
34 
35 #include "gstamc.h"
36 #include "gstamc-constants.h"
37 
38 #include "gstamcvideodec.h"
39 #include "gstamcvideoenc.h"
40 #include "gstamcaudiodec.h"
41 #include "gstjniutils.h"
42 
43 #include <gst/gst.h>
44 #include <gst/video/video.h>
45 #include <gst/audio/audio.h>
46 #include <string.h>
47 
48 GST_DEBUG_CATEGORY (gst_amc_debug);
49 #define GST_CAT_DEFAULT gst_amc_debug
50 
51 GQuark gst_amc_codec_info_quark = 0;
52 
53 static GQueue codec_infos = G_QUEUE_INIT;
54 #ifdef GST_AMC_IGNORE_UNKNOWN_COLOR_FORMATS
55 static gboolean ignore_unknown_color_formats = TRUE;
56 #else
57 static gboolean ignore_unknown_color_formats = FALSE;
58 #endif
59 
60 static gboolean accepted_color_formats (GstAmcCodecType * type,
61     gboolean is_encoder);
62 
63 /* Global cached references */
64 static struct
65 {
66   jclass klass;
67   jmethodID constructor;
68 } java_string;
69 static struct
70 {
71   jclass klass;
72   jmethodID configure;
73   jmethodID create_by_codec_name;
74   jmethodID dequeue_input_buffer;
75   jmethodID dequeue_output_buffer;
76   jmethodID flush;
77   jmethodID get_input_buffers;
78   jmethodID get_input_buffer;
79   jmethodID get_output_buffers;
80   jmethodID get_output_buffer;
81   jmethodID get_output_format;
82   jmethodID queue_input_buffer;
83   jmethodID release;
84   jmethodID release_output_buffer;
85   jmethodID start;
86   jmethodID stop;
87 } media_codec;
88 static struct
89 {
90   jclass klass;
91   jmethodID constructor;
92   jfieldID flags;
93   jfieldID offset;
94   jfieldID presentation_time_us;
95   jfieldID size;
96 } media_codec_buffer_info;
97 static struct
98 {
99   jclass klass;
100   jmethodID create_audio_format;
101   jmethodID create_video_format;
102   jmethodID to_string;
103   jmethodID contains_key;
104   jmethodID get_float;
105   jmethodID set_float;
106   jmethodID get_integer;
107   jmethodID set_integer;
108   jmethodID get_string;
109   jmethodID set_string;
110   jmethodID get_byte_buffer;
111   jmethodID set_byte_buffer;
112 } media_format;
113 
114 static GstAmcBuffer *gst_amc_codec_get_input_buffers (GstAmcCodec * codec,
115     gsize * n_buffers, GError ** err);
116 static GstAmcBuffer *gst_amc_codec_get_output_buffers (GstAmcCodec * codec,
117     gsize * n_buffers, GError ** err);
118 
119 GstAmcCodec *
gst_amc_codec_new(const gchar * name,GError ** err)120 gst_amc_codec_new (const gchar * name, GError ** err)
121 {
122   JNIEnv *env;
123   GstAmcCodec *codec = NULL;
124   jstring name_str;
125   jobject object = NULL;
126 
127   g_return_val_if_fail (name != NULL, NULL);
128 
129   env = gst_amc_jni_get_env ();
130 
131   name_str = gst_amc_jni_string_from_gchar (env, err, FALSE, name);
132   if (!name_str) {
133     goto error;
134   }
135 
136   codec = g_slice_new0 (GstAmcCodec);
137 
138   if (!gst_amc_jni_call_static_object_method (env, err, media_codec.klass,
139           media_codec.create_by_codec_name, &object, name_str))
140     goto error;
141 
142   codec->object = gst_amc_jni_object_make_global (env, object);
143   object = NULL;
144 
145   if (!codec->object) {
146     gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
147         GST_LIBRARY_ERROR_SETTINGS, "Failed to create global codec reference");
148     goto error;
149   }
150 
151 done:
152   if (name_str)
153     gst_amc_jni_object_local_unref (env, name_str);
154   name_str = NULL;
155 
156   return codec;
157 
158 error:
159   if (codec)
160     g_slice_free (GstAmcCodec, codec);
161   codec = NULL;
162   goto done;
163 }
164 
165 void
gst_amc_codec_free(GstAmcCodec * codec)166 gst_amc_codec_free (GstAmcCodec * codec)
167 {
168   JNIEnv *env;
169 
170   g_return_if_fail (codec != NULL);
171 
172   env = gst_amc_jni_get_env ();
173 
174   if (codec->input_buffers)
175     gst_amc_jni_free_buffer_array (env, codec->input_buffers,
176         codec->n_input_buffers);
177   codec->input_buffers = NULL;
178   codec->n_input_buffers = 0;
179 
180   if (codec->output_buffers)
181     gst_amc_jni_free_buffer_array (env, codec->output_buffers,
182         codec->n_output_buffers);
183   codec->output_buffers = NULL;
184   codec->n_output_buffers = 0;
185 
186   gst_amc_jni_object_unref (env, codec->object);
187   g_slice_free (GstAmcCodec, codec);
188 }
189 
190 gboolean
gst_amc_codec_configure(GstAmcCodec * codec,GstAmcFormat * format,jobject surface,gint flags,GError ** err)191 gst_amc_codec_configure (GstAmcCodec * codec, GstAmcFormat * format,
192     jobject surface, gint flags, GError ** err)
193 {
194   JNIEnv *env;
195 
196   g_return_val_if_fail (codec != NULL, FALSE);
197   g_return_val_if_fail (format != NULL, FALSE);
198 
199   env = gst_amc_jni_get_env ();
200   return gst_amc_jni_call_void_method (env, err, codec->object,
201       media_codec.configure, format->object, surface, NULL, flags);
202 }
203 
204 GstAmcFormat *
gst_amc_codec_get_output_format(GstAmcCodec * codec,GError ** err)205 gst_amc_codec_get_output_format (GstAmcCodec * codec, GError ** err)
206 {
207   JNIEnv *env;
208   GstAmcFormat *ret = NULL;
209   jobject object = NULL;
210 
211   g_return_val_if_fail (codec != NULL, NULL);
212 
213   env = gst_amc_jni_get_env ();
214 
215   if (!gst_amc_jni_call_object_method (env, err, codec->object,
216           media_codec.get_output_format, &object))
217     goto done;
218 
219   ret = g_slice_new0 (GstAmcFormat);
220 
221   ret->object = gst_amc_jni_object_make_global (env, object);
222   if (!ret->object) {
223     gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
224         GST_LIBRARY_ERROR_SETTINGS, "Failed to create global format reference");
225     g_slice_free (GstAmcFormat, ret);
226     ret = NULL;
227   }
228 
229 done:
230 
231   return ret;
232 }
233 
234 gboolean
gst_amc_codec_start(GstAmcCodec * codec,GError ** err)235 gst_amc_codec_start (GstAmcCodec * codec, GError ** err)
236 {
237   JNIEnv *env;
238   gboolean ret;
239 
240   g_return_val_if_fail (codec != NULL, FALSE);
241 
242   env = gst_amc_jni_get_env ();
243   ret = gst_amc_jni_call_void_method (env, err, codec->object,
244       media_codec.start);
245   if (!ret)
246     return ret;
247 
248   if (!media_codec.get_input_buffer) {
249     if (codec->input_buffers)
250       gst_amc_jni_free_buffer_array (env, codec->input_buffers,
251           codec->n_input_buffers);
252     codec->input_buffers =
253         gst_amc_codec_get_input_buffers (codec, &codec->n_input_buffers, err);
254     if (!codec->input_buffers) {
255       gst_amc_codec_stop (codec, NULL);
256       return FALSE;
257     }
258   }
259 
260   return ret;
261 }
262 
263 gboolean
gst_amc_codec_stop(GstAmcCodec * codec,GError ** err)264 gst_amc_codec_stop (GstAmcCodec * codec, GError ** err)
265 {
266   JNIEnv *env;
267 
268   g_return_val_if_fail (codec != NULL, FALSE);
269 
270   env = gst_amc_jni_get_env ();
271 
272   if (codec->input_buffers)
273     gst_amc_jni_free_buffer_array (env, codec->input_buffers,
274         codec->n_input_buffers);
275   codec->input_buffers = NULL;
276   codec->n_input_buffers = 0;
277 
278   if (codec->output_buffers)
279     gst_amc_jni_free_buffer_array (env, codec->output_buffers,
280         codec->n_output_buffers);
281   codec->output_buffers = NULL;
282   codec->n_output_buffers = 0;
283 
284   return gst_amc_jni_call_void_method (env, err, codec->object,
285       media_codec.stop);
286 }
287 
288 gboolean
gst_amc_codec_flush(GstAmcCodec * codec,GError ** err)289 gst_amc_codec_flush (GstAmcCodec * codec, GError ** err)
290 {
291   JNIEnv *env;
292 
293   g_return_val_if_fail (codec != NULL, FALSE);
294 
295   env = gst_amc_jni_get_env ();
296   return gst_amc_jni_call_void_method (env, err, codec->object,
297       media_codec.flush);
298 }
299 
300 gboolean
gst_amc_codec_release(GstAmcCodec * codec,GError ** err)301 gst_amc_codec_release (GstAmcCodec * codec, GError ** err)
302 {
303   JNIEnv *env;
304 
305   g_return_val_if_fail (codec != NULL, FALSE);
306 
307   env = gst_amc_jni_get_env ();
308 
309   if (codec->input_buffers)
310     gst_amc_jni_free_buffer_array (env, codec->input_buffers,
311         codec->n_input_buffers);
312   codec->input_buffers = NULL;
313   codec->n_input_buffers = 0;
314 
315   if (codec->output_buffers)
316     gst_amc_jni_free_buffer_array (env, codec->output_buffers,
317         codec->n_output_buffers);
318   codec->output_buffers = NULL;
319   codec->n_output_buffers = 0;
320 
321   return gst_amc_jni_call_void_method (env, err, codec->object,
322       media_codec.release);
323 }
324 
325 static GstAmcBuffer *
gst_amc_codec_get_output_buffers(GstAmcCodec * codec,gsize * n_buffers,GError ** err)326 gst_amc_codec_get_output_buffers (GstAmcCodec * codec, gsize * n_buffers,
327     GError ** err)
328 {
329   JNIEnv *env;
330   jobject output_buffers = NULL;
331   GstAmcBuffer *ret = NULL;
332 
333   g_return_val_if_fail (codec != NULL, NULL);
334   g_return_val_if_fail (n_buffers != NULL, NULL);
335 
336   *n_buffers = 0;
337   env = gst_amc_jni_get_env ();
338 
339   if (!gst_amc_jni_call_object_method (env, err, codec->object,
340           media_codec.get_output_buffers, &output_buffers))
341     goto done;
342 
343   gst_amc_jni_get_buffer_array (env, err, output_buffers, &ret, n_buffers);
344 
345 done:
346   if (output_buffers)
347     gst_amc_jni_object_local_unref (env, output_buffers);
348 
349   return ret;
350 }
351 
352 GstAmcBuffer *
gst_amc_codec_get_output_buffer(GstAmcCodec * codec,gint index,GError ** err)353 gst_amc_codec_get_output_buffer (GstAmcCodec * codec, gint index, GError ** err)
354 {
355   JNIEnv *env;
356   jobject buffer = NULL;
357   GstAmcBuffer *ret = NULL;
358 
359   g_return_val_if_fail (codec != NULL, NULL);
360   g_return_val_if_fail (index >= 0, NULL);
361 
362   env = gst_amc_jni_get_env ();
363 
364   if (!media_codec.get_output_buffer) {
365     g_return_val_if_fail (index < codec->n_output_buffers && index >= 0, NULL);
366     if (codec->output_buffers[index].object)
367       return gst_amc_buffer_copy (&codec->output_buffers[index]);
368     else
369       return NULL;
370   }
371 
372   if (!gst_amc_jni_call_object_method (env, err, codec->object,
373           media_codec.get_output_buffer, &buffer, index))
374     goto done;
375 
376   if (buffer != NULL) {
377     ret = g_new0 (GstAmcBuffer, 1);
378     ret->object = gst_amc_jni_object_make_global (env, buffer);
379     if (!ret->object) {
380       gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
381           GST_LIBRARY_ERROR_FAILED, "Failed to create global buffer reference");
382       goto error;
383     }
384 
385     ret->data = (*env)->GetDirectBufferAddress (env, ret->object);
386     if (!ret->data) {
387       gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
388           GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address");
389       goto error;
390     }
391     ret->size = (*env)->GetDirectBufferCapacity (env, ret->object);
392   }
393 
394 done:
395 
396   return ret;
397 
398 error:
399   if (ret->object)
400     gst_amc_jni_object_unref (env, ret->object);
401   g_free (ret);
402 
403   return NULL;
404 }
405 
406 static GstAmcBuffer *
gst_amc_codec_get_input_buffers(GstAmcCodec * codec,gsize * n_buffers,GError ** err)407 gst_amc_codec_get_input_buffers (GstAmcCodec * codec, gsize * n_buffers,
408     GError ** err)
409 {
410   JNIEnv *env;
411   jobject input_buffers = NULL;
412   GstAmcBuffer *ret = NULL;
413 
414   g_return_val_if_fail (codec != NULL, NULL);
415   g_return_val_if_fail (n_buffers != NULL, NULL);
416 
417   *n_buffers = 0;
418   env = gst_amc_jni_get_env ();
419 
420   if (!gst_amc_jni_call_object_method (env, err, codec->object,
421           media_codec.get_input_buffers, &input_buffers))
422     goto done;
423 
424   gst_amc_jni_get_buffer_array (env, err, input_buffers, &ret, n_buffers);
425 
426 done:
427   if (input_buffers)
428     gst_amc_jni_object_local_unref (env, input_buffers);
429 
430   return ret;
431 }
432 
433 GstAmcBuffer *
gst_amc_codec_get_input_buffer(GstAmcCodec * codec,gint index,GError ** err)434 gst_amc_codec_get_input_buffer (GstAmcCodec * codec, gint index, GError ** err)
435 {
436   JNIEnv *env;
437   jobject buffer = NULL;
438   GstAmcBuffer *ret = NULL;
439 
440   g_return_val_if_fail (codec != NULL, NULL);
441   g_return_val_if_fail (index >= 0, NULL);
442 
443   env = gst_amc_jni_get_env ();
444 
445   if (!media_codec.get_input_buffer) {
446     g_return_val_if_fail (index < codec->n_input_buffers && index >= 0, NULL);
447     if (codec->input_buffers[index].object)
448       return gst_amc_buffer_copy (&codec->input_buffers[index]);
449     else
450       return NULL;
451   }
452 
453   if (!gst_amc_jni_call_object_method (env, err, codec->object,
454           media_codec.get_input_buffer, &buffer, index))
455     goto done;
456 
457   if (buffer != NULL) {
458     ret = g_new0 (GstAmcBuffer, 1);
459     ret->object = gst_amc_jni_object_make_global (env, buffer);
460     if (!ret->object) {
461       gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
462           GST_LIBRARY_ERROR_FAILED, "Failed to create global buffer reference");
463       goto error;
464     }
465 
466     ret->data = (*env)->GetDirectBufferAddress (env, ret->object);
467     if (!ret->data) {
468       gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
469           GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address");
470       goto error;
471     }
472     ret->size = (*env)->GetDirectBufferCapacity (env, ret->object);
473   }
474 
475 done:
476 
477   return ret;
478 
479 error:
480   if (ret->object)
481     gst_amc_jni_object_unref (env, ret->object);
482   g_free (ret);
483 
484   return NULL;
485 }
486 
487 gint
gst_amc_codec_dequeue_input_buffer(GstAmcCodec * codec,gint64 timeoutUs,GError ** err)488 gst_amc_codec_dequeue_input_buffer (GstAmcCodec * codec, gint64 timeoutUs,
489     GError ** err)
490 {
491   JNIEnv *env;
492   gint ret = G_MININT;
493 
494   g_return_val_if_fail (codec != NULL, G_MININT);
495 
496   env = gst_amc_jni_get_env ();
497   if (!gst_amc_jni_call_int_method (env, err, codec->object,
498           media_codec.dequeue_input_buffer, &ret, timeoutUs))
499     return G_MININT;
500 
501   return ret;
502 }
503 
504 static gboolean
gst_amc_codec_fill_buffer_info(JNIEnv * env,jobject buffer_info,GstAmcBufferInfo * info,GError ** err)505 gst_amc_codec_fill_buffer_info (JNIEnv * env, jobject buffer_info,
506     GstAmcBufferInfo * info, GError ** err)
507 {
508   g_return_val_if_fail (buffer_info != NULL, FALSE);
509 
510   if (!gst_amc_jni_get_int_field (env, err, buffer_info,
511           media_codec_buffer_info.flags, &info->flags))
512     return FALSE;
513 
514   if (!gst_amc_jni_get_int_field (env, err, buffer_info,
515           media_codec_buffer_info.offset, &info->offset))
516     return FALSE;
517 
518   if (!gst_amc_jni_get_long_field (env, err, buffer_info,
519           media_codec_buffer_info.presentation_time_us,
520           &info->presentation_time_us))
521     return FALSE;
522 
523   if (!gst_amc_jni_get_int_field (env, err, buffer_info,
524           media_codec_buffer_info.size, &info->size))
525     return FALSE;
526 
527   return TRUE;
528 }
529 
530 gint
gst_amc_codec_dequeue_output_buffer(GstAmcCodec * codec,GstAmcBufferInfo * info,gint64 timeoutUs,GError ** err)531 gst_amc_codec_dequeue_output_buffer (GstAmcCodec * codec,
532     GstAmcBufferInfo * info, gint64 timeoutUs, GError ** err)
533 {
534   JNIEnv *env;
535   gint ret = G_MININT;
536   jobject info_o = NULL;
537 
538   g_return_val_if_fail (codec != NULL, G_MININT);
539 
540   env = gst_amc_jni_get_env ();
541 
542   info_o =
543       gst_amc_jni_new_object (env, err, FALSE, media_codec_buffer_info.klass,
544       media_codec_buffer_info.constructor);
545   if (!info_o)
546     goto done;
547 
548   if (!gst_amc_jni_call_int_method (env, err, codec->object,
549           media_codec.dequeue_output_buffer, &ret, info_o, timeoutUs)) {
550     ret = G_MININT;
551     goto done;
552   }
553 
554   if (ret == INFO_OUTPUT_BUFFERS_CHANGED || ret == INFO_OUTPUT_FORMAT_CHANGED
555       || (ret >= 0 && !codec->output_buffers
556           && !media_codec.get_output_buffer)) {
557     if (!media_codec.get_output_buffer) {
558       if (codec->output_buffers)
559         gst_amc_jni_free_buffer_array (env, codec->output_buffers,
560             codec->n_output_buffers);
561       codec->output_buffers =
562           gst_amc_codec_get_output_buffers (codec,
563           &codec->n_output_buffers, err);
564       if (!codec->output_buffers) {
565         ret = G_MININT;
566         goto done;
567       }
568     }
569     if (ret == INFO_OUTPUT_BUFFERS_CHANGED) {
570       gst_amc_jni_object_local_unref (env, info_o);
571       return gst_amc_codec_dequeue_output_buffer (codec, info, timeoutUs, err);
572     }
573   } else if (ret < 0) {
574     goto done;
575   }
576 
577   if (ret >= 0 && !gst_amc_codec_fill_buffer_info (env, info_o, info, err)) {
578     ret = G_MININT;
579     goto done;
580   }
581 
582 done:
583   if (info_o)
584     gst_amc_jni_object_local_unref (env, info_o);
585   info_o = NULL;
586 
587   return ret;
588 }
589 
590 gboolean
gst_amc_codec_queue_input_buffer(GstAmcCodec * codec,gint index,const GstAmcBufferInfo * info,GError ** err)591 gst_amc_codec_queue_input_buffer (GstAmcCodec * codec, gint index,
592     const GstAmcBufferInfo * info, GError ** err)
593 {
594   JNIEnv *env;
595 
596   g_return_val_if_fail (codec != NULL, FALSE);
597   g_return_val_if_fail (info != NULL, FALSE);
598 
599   env = gst_amc_jni_get_env ();
600   return gst_amc_jni_call_void_method (env, err, codec->object,
601       media_codec.queue_input_buffer, index, info->offset, info->size,
602       info->presentation_time_us, info->flags);
603 }
604 
605 gboolean
gst_amc_codec_release_output_buffer(GstAmcCodec * codec,gint index,gboolean render,GError ** err)606 gst_amc_codec_release_output_buffer (GstAmcCodec * codec, gint index,
607     gboolean render, GError ** err)
608 {
609   JNIEnv *env;
610 
611   g_return_val_if_fail (codec != NULL, FALSE);
612 
613   env = gst_amc_jni_get_env ();
614   return gst_amc_jni_call_void_method (env, err, codec->object,
615       media_codec.release_output_buffer, index, render);
616 }
617 
618 GstAmcFormat *
gst_amc_format_new_audio(const gchar * mime,gint sample_rate,gint channels,GError ** err)619 gst_amc_format_new_audio (const gchar * mime, gint sample_rate, gint channels,
620     GError ** err)
621 {
622   JNIEnv *env;
623   GstAmcFormat *format = NULL;
624   jstring mime_str;
625 
626   g_return_val_if_fail (mime != NULL, NULL);
627 
628   env = gst_amc_jni_get_env ();
629 
630   mime_str = gst_amc_jni_string_from_gchar (env, err, FALSE, mime);
631   if (!mime_str)
632     goto error;
633 
634   format = g_slice_new0 (GstAmcFormat);
635   format->object =
636       gst_amc_jni_new_object_from_static (env, err, TRUE, media_format.klass,
637       media_format.create_audio_format, mime_str, sample_rate, channels);
638   if (!format->object)
639     goto error;
640 
641 done:
642   if (mime_str)
643     gst_amc_jni_object_local_unref (env, mime_str);
644   mime_str = NULL;
645 
646   return format;
647 
648 error:
649   if (format)
650     g_slice_free (GstAmcFormat, format);
651   format = NULL;
652   goto done;
653 }
654 
655 GstAmcFormat *
gst_amc_format_new_video(const gchar * mime,gint width,gint height,GError ** err)656 gst_amc_format_new_video (const gchar * mime, gint width, gint height,
657     GError ** err)
658 {
659   JNIEnv *env;
660   GstAmcFormat *format = NULL;
661   jstring mime_str;
662 
663   g_return_val_if_fail (mime != NULL, NULL);
664 
665   env = gst_amc_jni_get_env ();
666 
667   mime_str = gst_amc_jni_string_from_gchar (env, err, FALSE, mime);
668   if (!mime_str)
669     goto error;
670 
671   format = g_slice_new0 (GstAmcFormat);
672   format->object =
673       gst_amc_jni_new_object_from_static (env, err, TRUE, media_format.klass,
674       media_format.create_video_format, mime_str, width, height);
675   if (!format->object)
676     goto error;
677 
678 done:
679   if (mime_str)
680     gst_amc_jni_object_local_unref (env, mime_str);
681   mime_str = NULL;
682 
683   return format;
684 
685 error:
686   if (format)
687     g_slice_free (GstAmcFormat, format);
688   format = NULL;
689   goto done;
690 }
691 
692 void
gst_amc_format_free(GstAmcFormat * format)693 gst_amc_format_free (GstAmcFormat * format)
694 {
695   JNIEnv *env;
696 
697   g_return_if_fail (format != NULL);
698 
699   env = gst_amc_jni_get_env ();
700   gst_amc_jni_object_unref (env, format->object);
701   g_slice_free (GstAmcFormat, format);
702 }
703 
704 gchar *
gst_amc_format_to_string(GstAmcFormat * format,GError ** err)705 gst_amc_format_to_string (GstAmcFormat * format, GError ** err)
706 {
707   JNIEnv *env;
708   jstring v_str = NULL;
709   gchar *ret = NULL;
710 
711   g_return_val_if_fail (format != NULL, FALSE);
712 
713   env = gst_amc_jni_get_env ();
714 
715   if (!gst_amc_jni_call_object_method (env, err, format->object,
716           media_format.to_string, &v_str))
717     goto done;
718   ret = gst_amc_jni_string_to_gchar (env, v_str, TRUE);
719 
720 done:
721 
722   return ret;
723 }
724 
725 gboolean
gst_amc_format_contains_key(GstAmcFormat * format,const gchar * key,GError ** err)726 gst_amc_format_contains_key (GstAmcFormat * format, const gchar * key,
727     GError ** err)
728 {
729   JNIEnv *env;
730   gboolean ret = FALSE;
731   jstring key_str = NULL;
732 
733   g_return_val_if_fail (format != NULL, FALSE);
734   g_return_val_if_fail (key != NULL, FALSE);
735 
736   env = gst_amc_jni_get_env ();
737 
738   key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
739   if (!key_str)
740     goto done;
741 
742   if (!gst_amc_jni_call_boolean_method (env, err, format->object,
743           media_format.contains_key, &ret, key_str))
744     goto done;
745 
746 done:
747   if (key_str)
748     gst_amc_jni_object_local_unref (env, key_str);
749 
750   return ret;
751 }
752 
753 gboolean
gst_amc_format_get_float(GstAmcFormat * format,const gchar * key,gfloat * value,GError ** err)754 gst_amc_format_get_float (GstAmcFormat * format, const gchar * key,
755     gfloat * value, GError ** err)
756 {
757   JNIEnv *env;
758   gboolean ret = FALSE;
759   jstring key_str = NULL;
760 
761   g_return_val_if_fail (format != NULL, FALSE);
762   g_return_val_if_fail (key != NULL, FALSE);
763   g_return_val_if_fail (value != NULL, FALSE);
764 
765   *value = 0;
766   env = gst_amc_jni_get_env ();
767 
768   key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
769   if (!key_str)
770     goto done;
771 
772   if (!gst_amc_jni_call_float_method (env, err, format->object,
773           media_format.get_float, value, key_str))
774     goto done;
775   ret = TRUE;
776 
777 done:
778   if (key_str)
779     gst_amc_jni_object_local_unref (env, key_str);
780 
781   return ret;
782 }
783 
784 gboolean
gst_amc_format_set_float(GstAmcFormat * format,const gchar * key,gfloat value,GError ** err)785 gst_amc_format_set_float (GstAmcFormat * format, const gchar * key,
786     gfloat value, GError ** err)
787 {
788   JNIEnv *env;
789   jstring key_str = NULL;
790   gboolean ret = FALSE;
791 
792   g_return_val_if_fail (format != NULL, FALSE);
793   g_return_val_if_fail (key != NULL, FALSE);
794 
795   env = gst_amc_jni_get_env ();
796 
797   key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
798   if (!key_str)
799     goto done;
800 
801   if (!gst_amc_jni_call_void_method (env, err, format->object,
802           media_format.set_float, key_str, value))
803     goto done;
804 
805   ret = TRUE;
806 
807 done:
808   if (key_str)
809     gst_amc_jni_object_local_unref (env, key_str);
810 
811   return ret;
812 }
813 
814 gboolean
gst_amc_format_get_int(GstAmcFormat * format,const gchar * key,gint * value,GError ** err)815 gst_amc_format_get_int (GstAmcFormat * format, const gchar * key, gint * value,
816     GError ** err)
817 {
818   JNIEnv *env;
819   gboolean ret = FALSE;
820   jstring key_str = NULL;
821 
822   g_return_val_if_fail (format != NULL, FALSE);
823   g_return_val_if_fail (key != NULL, FALSE);
824   g_return_val_if_fail (value != NULL, FALSE);
825 
826   *value = 0;
827   env = gst_amc_jni_get_env ();
828 
829   key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
830   if (!key_str)
831     goto done;
832 
833   if (!gst_amc_jni_call_int_method (env, err, format->object,
834           media_format.get_integer, value, key_str))
835     goto done;
836   ret = TRUE;
837 
838 done:
839   if (key_str)
840     gst_amc_jni_object_local_unref (env, key_str);
841 
842   return ret;
843 
844 }
845 
846 gboolean
gst_amc_format_set_int(GstAmcFormat * format,const gchar * key,gint value,GError ** err)847 gst_amc_format_set_int (GstAmcFormat * format, const gchar * key, gint value,
848     GError ** err)
849 {
850   JNIEnv *env;
851   jstring key_str = NULL;
852   gboolean ret = FALSE;
853 
854   g_return_val_if_fail (format != NULL, FALSE);
855   g_return_val_if_fail (key != NULL, FALSE);
856 
857   env = gst_amc_jni_get_env ();
858 
859   key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
860   if (!key_str)
861     goto done;
862 
863   if (!gst_amc_jni_call_void_method (env, err, format->object,
864           media_format.set_integer, key_str, value))
865     goto done;
866 
867   ret = TRUE;
868 
869 done:
870   if (key_str)
871     gst_amc_jni_object_local_unref (env, key_str);
872 
873   return ret;
874 }
875 
876 gboolean
gst_amc_format_get_string(GstAmcFormat * format,const gchar * key,gchar ** value,GError ** err)877 gst_amc_format_get_string (GstAmcFormat * format, const gchar * key,
878     gchar ** value, GError ** err)
879 {
880   JNIEnv *env;
881   gboolean ret = FALSE;
882   jstring key_str = NULL;
883   jstring v_str = NULL;
884 
885   g_return_val_if_fail (format != NULL, FALSE);
886   g_return_val_if_fail (key != NULL, FALSE);
887   g_return_val_if_fail (value != NULL, FALSE);
888 
889   *value = 0;
890   env = gst_amc_jni_get_env ();
891 
892   key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
893   if (!key_str)
894     goto done;
895 
896   if (!gst_amc_jni_call_object_method (env, err, format->object,
897           media_format.get_string, &v_str, key_str))
898     goto done;
899 
900   *value = gst_amc_jni_string_to_gchar (env, v_str, TRUE);
901 
902   ret = TRUE;
903 
904 done:
905   if (key_str)
906     gst_amc_jni_object_local_unref (env, key_str);
907 
908   return ret;
909 }
910 
911 gboolean
gst_amc_format_set_string(GstAmcFormat * format,const gchar * key,const gchar * value,GError ** err)912 gst_amc_format_set_string (GstAmcFormat * format, const gchar * key,
913     const gchar * value, GError ** err)
914 {
915   JNIEnv *env;
916   jstring key_str = NULL;
917   jstring v_str = NULL;
918   gboolean ret = FALSE;
919 
920   g_return_val_if_fail (format != NULL, FALSE);
921   g_return_val_if_fail (key != NULL, FALSE);
922   g_return_val_if_fail (value != NULL, FALSE);
923 
924   env = gst_amc_jni_get_env ();
925 
926   key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
927   if (!key_str)
928     goto done;
929 
930   v_str = gst_amc_jni_string_from_gchar (env, err, FALSE, value);
931   if (!v_str)
932     goto done;
933 
934   if (!gst_amc_jni_call_void_method (env, err, format->object,
935           media_format.set_string, key_str, v_str))
936     goto done;
937 
938   ret = TRUE;
939 
940 done:
941   if (key_str)
942     gst_amc_jni_object_local_unref (env, key_str);
943   if (v_str)
944     gst_amc_jni_object_local_unref (env, v_str);
945 
946   return ret;
947 }
948 
949 gboolean
gst_amc_format_get_buffer(GstAmcFormat * format,const gchar * key,guint8 ** data,gsize * size,GError ** err)950 gst_amc_format_get_buffer (GstAmcFormat * format, const gchar * key,
951     guint8 ** data, gsize * size, GError ** err)
952 {
953   JNIEnv *env;
954   gboolean ret = FALSE;
955   jstring key_str = NULL;
956   jobject v = NULL;
957   GstAmcBuffer buf = { 0, };
958   gint position = 0, limit = 0;
959 
960   g_return_val_if_fail (format != NULL, FALSE);
961   g_return_val_if_fail (key != NULL, FALSE);
962   g_return_val_if_fail (data != NULL, FALSE);
963   g_return_val_if_fail (size != NULL, FALSE);
964 
965   *data = NULL;
966   *size = 0;
967   env = gst_amc_jni_get_env ();
968 
969   key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
970   if (!key_str)
971     goto done;
972 
973   if (!gst_amc_jni_call_object_method (env, err, format->object,
974           media_format.get_byte_buffer, &v, key_str))
975     goto done;
976 
977   *data = (*env)->GetDirectBufferAddress (env, v);
978   if (*data == NULL) {
979     gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
980         GST_LIBRARY_ERROR_FAILED, "Failed get buffer address");
981     goto done;
982   }
983   *size = (*env)->GetDirectBufferCapacity (env, v);
984 
985   buf.object = v;
986   buf.data = *data;
987   buf.size = *size;
988   gst_amc_buffer_get_position_and_limit (&buf, NULL, &position, &limit);
989   *size = limit;
990 
991   *data = g_memdup (*data + position, limit);
992 
993   ret = TRUE;
994 
995 done:
996   if (key_str)
997     gst_amc_jni_object_local_unref (env, key_str);
998   if (v)
999     gst_amc_jni_object_local_unref (env, v);
1000 
1001   return ret;
1002 }
1003 
1004 gboolean
gst_amc_format_set_buffer(GstAmcFormat * format,const gchar * key,guint8 * data,gsize size,GError ** err)1005 gst_amc_format_set_buffer (GstAmcFormat * format, const gchar * key,
1006     guint8 * data, gsize size, GError ** err)
1007 {
1008   JNIEnv *env;
1009   jstring key_str = NULL;
1010   jobject v = NULL;
1011   gboolean ret = FALSE;
1012   GstAmcBuffer buf = { 0, };
1013 
1014   g_return_val_if_fail (format != NULL, FALSE);
1015   g_return_val_if_fail (key != NULL, FALSE);
1016   g_return_val_if_fail (data != NULL, FALSE);
1017 
1018   env = gst_amc_jni_get_env ();
1019 
1020   key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key);
1021   if (!key_str)
1022     goto done;
1023 
1024   /* FIXME: The memory must remain valid until the codec is stopped */
1025   v = (*env)->NewDirectByteBuffer (env, data, size);
1026   if (!v) {
1027     gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
1028         GST_LIBRARY_ERROR_FAILED, "Failed create Java byte buffer");
1029     goto done;
1030   }
1031 
1032   buf.object = v;
1033   buf.data = data;
1034   buf.size = size;
1035 
1036   gst_amc_buffer_set_position_and_limit (&buf, NULL, 0, size);
1037 
1038   if (!gst_amc_jni_call_void_method (env, err, format->object,
1039           media_format.set_byte_buffer, key_str, v))
1040     goto done;
1041 
1042   ret = TRUE;
1043 
1044 done:
1045   if (key_str)
1046     gst_amc_jni_object_local_unref (env, key_str);
1047   if (v)
1048     gst_amc_jni_object_local_unref (env, v);
1049 
1050   return ret;
1051 }
1052 
1053 static gboolean
get_java_classes(void)1054 get_java_classes (void)
1055 {
1056   gboolean ret = TRUE;
1057   JNIEnv *env;
1058   jclass tmp;
1059 
1060   GST_DEBUG ("Retrieving Java classes");
1061 
1062   env = gst_amc_jni_get_env ();
1063 
1064   tmp = (*env)->FindClass (env, "java/lang/String");
1065   if (!tmp) {
1066     ret = FALSE;
1067     GST_ERROR ("Failed to get string class");
1068     if ((*env)->ExceptionCheck (env)) {
1069       (*env)->ExceptionDescribe (env);
1070       (*env)->ExceptionClear (env);
1071     }
1072     goto done;
1073   }
1074   java_string.klass = (*env)->NewGlobalRef (env, tmp);
1075   if (!java_string.klass) {
1076     ret = FALSE;
1077     GST_ERROR ("Failed to get string class global reference");
1078     if ((*env)->ExceptionCheck (env)) {
1079       (*env)->ExceptionDescribe (env);
1080       (*env)->ExceptionClear (env);
1081     }
1082     goto done;
1083   }
1084   (*env)->DeleteLocalRef (env, tmp);
1085   tmp = NULL;
1086 
1087   java_string.constructor =
1088       (*env)->GetMethodID (env, java_string.klass, "<init>", "([C)V");
1089   if (!java_string.constructor) {
1090     ret = FALSE;
1091     GST_ERROR ("Failed to get string methods");
1092     if ((*env)->ExceptionCheck (env)) {
1093       (*env)->ExceptionDescribe (env);
1094       (*env)->ExceptionClear (env);
1095     }
1096     goto done;
1097   }
1098 
1099   tmp = (*env)->FindClass (env, "android/media/MediaCodec");
1100   if (!tmp) {
1101     ret = FALSE;
1102     GST_ERROR ("Failed to get codec class");
1103     if ((*env)->ExceptionCheck (env)) {
1104       (*env)->ExceptionDescribe (env);
1105       (*env)->ExceptionClear (env);
1106     }
1107     goto done;
1108   }
1109   media_codec.klass = (*env)->NewGlobalRef (env, tmp);
1110   if (!media_codec.klass) {
1111     ret = FALSE;
1112     GST_ERROR ("Failed to get codec class global reference");
1113     if ((*env)->ExceptionCheck (env)) {
1114       (*env)->ExceptionDescribe (env);
1115       (*env)->ExceptionClear (env);
1116     }
1117     goto done;
1118   }
1119   (*env)->DeleteLocalRef (env, tmp);
1120   tmp = NULL;
1121 
1122   media_codec.create_by_codec_name =
1123       (*env)->GetStaticMethodID (env, media_codec.klass, "createByCodecName",
1124       "(Ljava/lang/String;)Landroid/media/MediaCodec;");
1125   media_codec.configure =
1126       (*env)->GetMethodID (env, media_codec.klass, "configure",
1127       "(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V");
1128   media_codec.dequeue_input_buffer =
1129       (*env)->GetMethodID (env, media_codec.klass, "dequeueInputBuffer",
1130       "(J)I");
1131   media_codec.dequeue_output_buffer =
1132       (*env)->GetMethodID (env, media_codec.klass, "dequeueOutputBuffer",
1133       "(Landroid/media/MediaCodec$BufferInfo;J)I");
1134   media_codec.flush =
1135       (*env)->GetMethodID (env, media_codec.klass, "flush", "()V");
1136   media_codec.get_input_buffers =
1137       (*env)->GetMethodID (env, media_codec.klass, "getInputBuffers",
1138       "()[Ljava/nio/ByteBuffer;");
1139   media_codec.get_output_buffers =
1140       (*env)->GetMethodID (env, media_codec.klass, "getOutputBuffers",
1141       "()[Ljava/nio/ByteBuffer;");
1142   media_codec.get_output_format =
1143       (*env)->GetMethodID (env, media_codec.klass, "getOutputFormat",
1144       "()Landroid/media/MediaFormat;");
1145   media_codec.queue_input_buffer =
1146       (*env)->GetMethodID (env, media_codec.klass, "queueInputBuffer",
1147       "(IIIJI)V");
1148   media_codec.release =
1149       (*env)->GetMethodID (env, media_codec.klass, "release", "()V");
1150   media_codec.release_output_buffer =
1151       (*env)->GetMethodID (env, media_codec.klass, "releaseOutputBuffer",
1152       "(IZ)V");
1153   media_codec.start =
1154       (*env)->GetMethodID (env, media_codec.klass, "start", "()V");
1155   media_codec.stop =
1156       (*env)->GetMethodID (env, media_codec.klass, "stop", "()V");
1157 
1158   if (!media_codec.configure ||
1159       !media_codec.create_by_codec_name ||
1160       !media_codec.dequeue_input_buffer ||
1161       !media_codec.dequeue_output_buffer ||
1162       !media_codec.flush ||
1163       !media_codec.get_input_buffers ||
1164       !media_codec.get_output_buffers ||
1165       !media_codec.get_output_format ||
1166       !media_codec.queue_input_buffer ||
1167       !media_codec.release ||
1168       !media_codec.release_output_buffer ||
1169       !media_codec.start || !media_codec.stop) {
1170     ret = FALSE;
1171     GST_ERROR ("Failed to get codec methods");
1172     if ((*env)->ExceptionCheck (env)) {
1173       (*env)->ExceptionDescribe (env);
1174       (*env)->ExceptionClear (env);
1175     }
1176     goto done;
1177   }
1178 
1179   /* Android >= 21 */
1180   media_codec.get_output_buffer =
1181       (*env)->GetMethodID (env, media_codec.klass, "getOutputBuffer",
1182       "(I)Ljava/nio/ByteBuffer;");
1183   if ((*env)->ExceptionCheck (env))
1184     (*env)->ExceptionClear (env);
1185 
1186   /* Android >= 21 */
1187   media_codec.get_input_buffer =
1188       (*env)->GetMethodID (env, media_codec.klass, "getInputBuffer",
1189       "(I)Ljava/nio/ByteBuffer;");
1190   if ((*env)->ExceptionCheck (env))
1191     (*env)->ExceptionClear (env);
1192 
1193   tmp = (*env)->FindClass (env, "android/media/MediaCodec$BufferInfo");
1194   if (!tmp) {
1195     ret = FALSE;
1196     (*env)->ExceptionClear (env);
1197     GST_ERROR ("Failed to get codec buffer info class");
1198     goto done;
1199   }
1200   media_codec_buffer_info.klass = (*env)->NewGlobalRef (env, tmp);
1201   if (!media_codec_buffer_info.klass) {
1202     ret = FALSE;
1203     GST_ERROR ("Failed to get codec buffer info class global reference");
1204     if ((*env)->ExceptionCheck (env)) {
1205       (*env)->ExceptionDescribe (env);
1206       (*env)->ExceptionClear (env);
1207     }
1208     goto done;
1209   }
1210   (*env)->DeleteLocalRef (env, tmp);
1211   tmp = NULL;
1212 
1213   media_codec_buffer_info.constructor =
1214       (*env)->GetMethodID (env, media_codec_buffer_info.klass, "<init>", "()V");
1215   media_codec_buffer_info.flags =
1216       (*env)->GetFieldID (env, media_codec_buffer_info.klass, "flags", "I");
1217   media_codec_buffer_info.offset =
1218       (*env)->GetFieldID (env, media_codec_buffer_info.klass, "offset", "I");
1219   media_codec_buffer_info.presentation_time_us =
1220       (*env)->GetFieldID (env, media_codec_buffer_info.klass,
1221       "presentationTimeUs", "J");
1222   media_codec_buffer_info.size =
1223       (*env)->GetFieldID (env, media_codec_buffer_info.klass, "size", "I");
1224   if (!media_codec_buffer_info.constructor || !media_codec_buffer_info.flags
1225       || !media_codec_buffer_info.offset
1226       || !media_codec_buffer_info.presentation_time_us
1227       || !media_codec_buffer_info.size) {
1228     ret = FALSE;
1229     GST_ERROR ("Failed to get buffer info methods and fields");
1230     if ((*env)->ExceptionCheck (env)) {
1231       (*env)->ExceptionDescribe (env);
1232       (*env)->ExceptionClear (env);
1233     }
1234     goto done;
1235   }
1236 
1237   tmp = (*env)->FindClass (env, "android/media/MediaFormat");
1238   if (!tmp) {
1239     ret = FALSE;
1240     GST_ERROR ("Failed to get format class");
1241     if ((*env)->ExceptionCheck (env)) {
1242       (*env)->ExceptionDescribe (env);
1243       (*env)->ExceptionClear (env);
1244     }
1245     goto done;
1246   }
1247   media_format.klass = (*env)->NewGlobalRef (env, tmp);
1248   if (!media_format.klass) {
1249     ret = FALSE;
1250     GST_ERROR ("Failed to get format class global reference");
1251     if ((*env)->ExceptionCheck (env)) {
1252       (*env)->ExceptionDescribe (env);
1253       (*env)->ExceptionClear (env);
1254     }
1255     goto done;
1256   }
1257   (*env)->DeleteLocalRef (env, tmp);
1258   tmp = NULL;
1259 
1260   media_format.create_audio_format =
1261       (*env)->GetStaticMethodID (env, media_format.klass, "createAudioFormat",
1262       "(Ljava/lang/String;II)Landroid/media/MediaFormat;");
1263   media_format.create_video_format =
1264       (*env)->GetStaticMethodID (env, media_format.klass, "createVideoFormat",
1265       "(Ljava/lang/String;II)Landroid/media/MediaFormat;");
1266   media_format.to_string =
1267       (*env)->GetMethodID (env, media_format.klass, "toString",
1268       "()Ljava/lang/String;");
1269   media_format.contains_key =
1270       (*env)->GetMethodID (env, media_format.klass, "containsKey",
1271       "(Ljava/lang/String;)Z");
1272   media_format.get_float =
1273       (*env)->GetMethodID (env, media_format.klass, "getFloat",
1274       "(Ljava/lang/String;)F");
1275   media_format.set_float =
1276       (*env)->GetMethodID (env, media_format.klass, "setFloat",
1277       "(Ljava/lang/String;F)V");
1278   media_format.get_integer =
1279       (*env)->GetMethodID (env, media_format.klass, "getInteger",
1280       "(Ljava/lang/String;)I");
1281   media_format.set_integer =
1282       (*env)->GetMethodID (env, media_format.klass, "setInteger",
1283       "(Ljava/lang/String;I)V");
1284   media_format.get_string =
1285       (*env)->GetMethodID (env, media_format.klass, "getString",
1286       "(Ljava/lang/String;)Ljava/lang/String;");
1287   media_format.set_string =
1288       (*env)->GetMethodID (env, media_format.klass, "setString",
1289       "(Ljava/lang/String;Ljava/lang/String;)V");
1290   media_format.get_byte_buffer =
1291       (*env)->GetMethodID (env, media_format.klass, "getByteBuffer",
1292       "(Ljava/lang/String;)Ljava/nio/ByteBuffer;");
1293   media_format.set_byte_buffer =
1294       (*env)->GetMethodID (env, media_format.klass, "setByteBuffer",
1295       "(Ljava/lang/String;Ljava/nio/ByteBuffer;)V");
1296   if (!media_format.create_audio_format || !media_format.create_video_format
1297       || !media_format.contains_key || !media_format.get_float
1298       || !media_format.set_float || !media_format.get_integer
1299       || !media_format.set_integer || !media_format.get_string
1300       || !media_format.set_string || !media_format.get_byte_buffer
1301       || !media_format.set_byte_buffer) {
1302     ret = FALSE;
1303     GST_ERROR ("Failed to get format methods");
1304     if ((*env)->ExceptionCheck (env)) {
1305       (*env)->ExceptionDescribe (env);
1306       (*env)->ExceptionClear (env);
1307     }
1308     goto done;
1309   }
1310 
1311 done:
1312   if (tmp)
1313     (*env)->DeleteLocalRef (env, tmp);
1314   tmp = NULL;
1315 
1316   return ret;
1317 }
1318 
1319 static gboolean
scan_codecs(GstPlugin * plugin)1320 scan_codecs (GstPlugin * plugin)
1321 {
1322   gboolean ret = TRUE;
1323   JNIEnv *env;
1324   jclass codec_list_class = NULL;
1325   jmethodID get_codec_count_id, get_codec_info_at_id;
1326   jint codec_count, i;
1327   const GstStructure *cache_data;
1328 
1329   GST_DEBUG ("Scanning codecs");
1330 
1331   if ((cache_data = gst_plugin_get_cache_data (plugin))) {
1332     const GValue *arr = gst_structure_get_value (cache_data, "codecs");
1333     guint i, n;
1334 
1335     GST_DEBUG ("Getting codecs from cache");
1336     n = gst_value_array_get_size (arr);
1337     for (i = 0; i < n; i++) {
1338       const GValue *cv = gst_value_array_get_value (arr, i);
1339       const GstStructure *cs = gst_value_get_structure (cv);
1340       const gchar *name;
1341       gboolean is_encoder;
1342       const GValue *starr;
1343       guint j, n2;
1344       GstAmcCodecInfo *gst_codec_info;
1345 
1346       gst_codec_info = g_new0 (GstAmcCodecInfo, 1);
1347 
1348       name = gst_structure_get_string (cs, "name");
1349       gst_structure_get_boolean (cs, "is-encoder", &is_encoder);
1350       gst_codec_info->name = g_strdup (name);
1351       gst_codec_info->is_encoder = is_encoder;
1352 
1353       starr = gst_structure_get_value (cs, "supported-types");
1354       n2 = gst_value_array_get_size (starr);
1355 
1356       gst_codec_info->n_supported_types = n2;
1357       gst_codec_info->supported_types = g_new0 (GstAmcCodecType, n2);
1358 
1359       for (j = 0; j < n2; j++) {
1360         const GValue *stv = gst_value_array_get_value (starr, j);
1361         const GstStructure *sts = gst_value_get_structure (stv);
1362         const gchar *mime;
1363         const GValue *cfarr;
1364         const GValue *plarr;
1365         guint k, n3;
1366         GstAmcCodecType *gst_codec_type = &gst_codec_info->supported_types[j];
1367 
1368         mime = gst_structure_get_string (sts, "mime");
1369         gst_codec_type->mime = g_strdup (mime);
1370 
1371         cfarr = gst_structure_get_value (sts, "color-formats");
1372         n3 = gst_value_array_get_size (cfarr);
1373 
1374         gst_codec_type->n_color_formats = n3;
1375         gst_codec_type->color_formats = g_new0 (gint, n3);
1376 
1377         for (k = 0; k < n3; k++) {
1378           const GValue *cfv = gst_value_array_get_value (cfarr, k);
1379           gint cf = g_value_get_int (cfv);
1380 
1381           gst_codec_type->color_formats[k] = cf;
1382         }
1383 
1384         plarr = gst_structure_get_value (sts, "profile-levels");
1385         n3 = gst_value_array_get_size (plarr);
1386 
1387         gst_codec_type->n_profile_levels = n3;
1388         gst_codec_type->profile_levels =
1389             g_malloc0 (sizeof (gst_codec_type->profile_levels[0]) * n3);
1390 
1391         for (k = 0; k < n3; k++) {
1392           const GValue *plv = gst_value_array_get_value (plarr, k);
1393           const GValue *p, *l;
1394 
1395           p = gst_value_array_get_value (plv, 0);
1396           l = gst_value_array_get_value (plv, 1);
1397           gst_codec_type->profile_levels[k].profile = g_value_get_int (p);
1398           gst_codec_type->profile_levels[k].level = g_value_get_int (l);
1399         }
1400       }
1401 
1402       g_queue_push_tail (&codec_infos, gst_codec_info);
1403     }
1404 
1405     return TRUE;
1406   }
1407 
1408   env = gst_amc_jni_get_env ();
1409 
1410   codec_list_class = (*env)->FindClass (env, "android/media/MediaCodecList");
1411   if (!codec_list_class) {
1412     ret = FALSE;
1413     GST_ERROR ("Failed to get codec list class");
1414     if ((*env)->ExceptionCheck (env)) {
1415       (*env)->ExceptionDescribe (env);
1416       (*env)->ExceptionClear (env);
1417     }
1418     goto done;
1419   }
1420 
1421   get_codec_count_id =
1422       (*env)->GetStaticMethodID (env, codec_list_class, "getCodecCount", "()I");
1423   get_codec_info_at_id =
1424       (*env)->GetStaticMethodID (env, codec_list_class, "getCodecInfoAt",
1425       "(I)Landroid/media/MediaCodecInfo;");
1426   if (!get_codec_count_id || !get_codec_info_at_id) {
1427     ret = FALSE;
1428     GST_ERROR ("Failed to get codec list method IDs");
1429     if ((*env)->ExceptionCheck (env)) {
1430       (*env)->ExceptionDescribe (env);
1431       (*env)->ExceptionClear (env);
1432     }
1433     goto done;
1434   }
1435 
1436   codec_count =
1437       (*env)->CallStaticIntMethod (env, codec_list_class, get_codec_count_id);
1438   if ((*env)->ExceptionCheck (env)) {
1439     ret = FALSE;
1440     GST_ERROR ("Failed to get number of available codecs");
1441     (*env)->ExceptionDescribe (env);
1442     (*env)->ExceptionClear (env);
1443     goto done;
1444   }
1445 
1446   GST_INFO ("Found %d available codecs", codec_count);
1447 
1448   for (i = 0; i < codec_count; i++) {
1449     GstAmcCodecInfo *gst_codec_info;
1450     jobject codec_info = NULL;
1451     jclass codec_info_class = NULL;
1452     jmethodID get_capabilities_for_type_id, get_name_id;
1453     jmethodID get_supported_types_id, is_encoder_id;
1454     jobject name = NULL;
1455     const gchar *name_str = NULL;
1456     jboolean is_encoder;
1457     jarray supported_types = NULL;
1458     jsize n_supported_types;
1459     jsize j;
1460     gboolean valid_codec = TRUE;
1461 
1462     gst_codec_info = g_new0 (GstAmcCodecInfo, 1);
1463 
1464     codec_info =
1465         (*env)->CallStaticObjectMethod (env, codec_list_class,
1466         get_codec_info_at_id, i);
1467     if ((*env)->ExceptionCheck (env) || !codec_info) {
1468       GST_ERROR ("Failed to get codec info %d", i);
1469       if ((*env)->ExceptionCheck (env)) {
1470         (*env)->ExceptionDescribe (env);
1471         (*env)->ExceptionClear (env);
1472       }
1473       valid_codec = FALSE;
1474       goto next_codec;
1475     }
1476 
1477     codec_info_class = (*env)->GetObjectClass (env, codec_info);
1478     if (!codec_list_class) {
1479       GST_ERROR ("Failed to get codec info class");
1480       if ((*env)->ExceptionCheck (env)) {
1481         (*env)->ExceptionDescribe (env);
1482         (*env)->ExceptionClear (env);
1483       }
1484       valid_codec = FALSE;
1485       goto next_codec;
1486     }
1487 
1488     get_capabilities_for_type_id =
1489         (*env)->GetMethodID (env, codec_info_class, "getCapabilitiesForType",
1490         "(Ljava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;");
1491     get_name_id =
1492         (*env)->GetMethodID (env, codec_info_class, "getName",
1493         "()Ljava/lang/String;");
1494     get_supported_types_id =
1495         (*env)->GetMethodID (env, codec_info_class, "getSupportedTypes",
1496         "()[Ljava/lang/String;");
1497     is_encoder_id =
1498         (*env)->GetMethodID (env, codec_info_class, "isEncoder", "()Z");
1499     if (!get_capabilities_for_type_id || !get_name_id
1500         || !get_supported_types_id || !is_encoder_id) {
1501       GST_ERROR ("Failed to get codec info method IDs");
1502       if ((*env)->ExceptionCheck (env)) {
1503         (*env)->ExceptionDescribe (env);
1504         (*env)->ExceptionClear (env);
1505       }
1506       valid_codec = FALSE;
1507       goto next_codec;
1508     }
1509 
1510     name = (*env)->CallObjectMethod (env, codec_info, get_name_id);
1511     if ((*env)->ExceptionCheck (env)) {
1512       GST_ERROR ("Failed to get codec name");
1513       (*env)->ExceptionDescribe (env);
1514       (*env)->ExceptionClear (env);
1515       valid_codec = FALSE;
1516       goto next_codec;
1517     }
1518     name_str = (*env)->GetStringUTFChars (env, name, NULL);
1519     if ((*env)->ExceptionCheck (env)) {
1520       GST_ERROR ("Failed to convert codec name to UTF8");
1521       (*env)->ExceptionDescribe (env);
1522       (*env)->ExceptionClear (env);
1523       valid_codec = FALSE;
1524       goto next_codec;
1525     }
1526 
1527     GST_INFO ("Checking codec '%s'", name_str);
1528 
1529     /* Compatibility codec names */
1530     if (strcmp (name_str, "AACEncoder") == 0 ||
1531         strcmp (name_str, "OMX.google.raw.decoder") == 0) {
1532       GST_INFO ("Skipping compatibility codec '%s'", name_str);
1533       valid_codec = FALSE;
1534       goto next_codec;
1535     }
1536 
1537     if (g_str_has_suffix (name_str, ".secure")) {
1538       GST_INFO ("Skipping DRM codec '%s'", name_str);
1539       valid_codec = FALSE;
1540       goto next_codec;
1541     }
1542 
1543     /* FIXME: Non-Google codecs usually just don't work and hang forever
1544      * or crash when not used from a process that started the Java
1545      * VM via the non-public AndroidRuntime class. Can we somehow
1546      * initialize all this?
1547      */
1548     if (gst_amc_jni_is_vm_started () &&
1549         !g_str_has_prefix (name_str, "OMX.google.")) {
1550       GST_INFO ("Skipping non-Google codec '%s' in standalone mode", name_str);
1551       valid_codec = FALSE;
1552       goto next_codec;
1553     }
1554 
1555     if (g_str_has_prefix (name_str, "OMX.ARICENT.")) {
1556       GST_INFO ("Skipping possible broken codec '%s'", name_str);
1557       valid_codec = FALSE;
1558       goto next_codec;
1559     }
1560 
1561     /* FIXME:
1562      *   - Vorbis: Generates clicks for multi-channel streams
1563      *   - *Law: Generates output with too low frequencies
1564      */
1565     if (strcmp (name_str, "OMX.google.vorbis.decoder") == 0 ||
1566         strcmp (name_str, "OMX.google.g711.alaw.decoder") == 0 ||
1567         strcmp (name_str, "OMX.google.g711.mlaw.decoder") == 0) {
1568       GST_INFO ("Skipping known broken codec '%s'", name_str);
1569       valid_codec = FALSE;
1570       goto next_codec;
1571     }
1572     gst_codec_info->name = g_strdup (name_str);
1573 
1574     is_encoder = (*env)->CallBooleanMethod (env, codec_info, is_encoder_id);
1575     if ((*env)->ExceptionCheck (env)) {
1576       GST_ERROR ("Failed to detect if codec is an encoder");
1577       (*env)->ExceptionDescribe (env);
1578       (*env)->ExceptionClear (env);
1579       valid_codec = FALSE;
1580       goto next_codec;
1581     }
1582     gst_codec_info->is_encoder = is_encoder;
1583     gst_codec_info->gl_output_only = FALSE;
1584 
1585     supported_types =
1586         (*env)->CallObjectMethod (env, codec_info, get_supported_types_id);
1587     if ((*env)->ExceptionCheck (env)) {
1588       GST_ERROR ("Failed to get supported types");
1589       (*env)->ExceptionDescribe (env);
1590       (*env)->ExceptionClear (env);
1591       valid_codec = FALSE;
1592       goto next_codec;
1593     }
1594 
1595     n_supported_types = (*env)->GetArrayLength (env, supported_types);
1596     if ((*env)->ExceptionCheck (env)) {
1597       GST_ERROR ("Failed to get supported types array length");
1598       (*env)->ExceptionDescribe (env);
1599       (*env)->ExceptionClear (env);
1600       valid_codec = FALSE;
1601       goto next_codec;
1602     }
1603 
1604     GST_INFO ("Codec '%s' has %d supported types", name_str, n_supported_types);
1605 
1606     gst_codec_info->supported_types =
1607         g_new0 (GstAmcCodecType, n_supported_types);
1608     gst_codec_info->n_supported_types = n_supported_types;
1609 
1610     if (n_supported_types == 0) {
1611       valid_codec = FALSE;
1612       GST_ERROR ("Codec has no supported types");
1613       goto next_codec;
1614     }
1615 
1616     for (j = 0; j < n_supported_types; j++) {
1617       GstAmcCodecType *gst_codec_type;
1618       jobject supported_type = NULL;
1619       const gchar *supported_type_str = NULL;
1620       jobject capabilities = NULL;
1621       jclass capabilities_class = NULL;
1622       jfieldID profile_levels_id, color_formats_id;
1623       jobject profile_levels = NULL;
1624       jobject color_formats = NULL;
1625       jint *color_formats_elems = NULL;
1626       jsize n_elems, k;
1627 
1628       gst_codec_type = &gst_codec_info->supported_types[j];
1629 
1630       supported_type = (*env)->GetObjectArrayElement (env, supported_types, j);
1631       if ((*env)->ExceptionCheck (env)) {
1632         GST_ERROR ("Failed to get %d-th supported type", j);
1633         (*env)->ExceptionDescribe (env);
1634         (*env)->ExceptionClear (env);
1635         valid_codec = FALSE;
1636         goto next_supported_type;
1637       }
1638 
1639       supported_type_str =
1640           (*env)->GetStringUTFChars (env, supported_type, NULL);
1641       if ((*env)->ExceptionCheck (env) || !supported_type_str) {
1642         GST_ERROR ("Failed to convert supported type to UTF8");
1643         (*env)->ExceptionDescribe (env);
1644         (*env)->ExceptionClear (env);
1645         valid_codec = FALSE;
1646         goto next_supported_type;
1647       }
1648 
1649       GST_INFO ("Supported type '%s'", supported_type_str);
1650       gst_codec_type->mime = g_strdup (supported_type_str);
1651 
1652       capabilities =
1653           (*env)->CallObjectMethod (env, codec_info,
1654           get_capabilities_for_type_id, supported_type);
1655       if ((*env)->ExceptionCheck (env)) {
1656         GST_ERROR ("Failed to get capabilities for supported type");
1657         (*env)->ExceptionDescribe (env);
1658         (*env)->ExceptionClear (env);
1659         valid_codec = FALSE;
1660         goto next_supported_type;
1661       }
1662 
1663       capabilities_class = (*env)->GetObjectClass (env, capabilities);
1664       if (!capabilities_class) {
1665         GST_ERROR ("Failed to get capabilities class");
1666         (*env)->ExceptionDescribe (env);
1667         (*env)->ExceptionClear (env);
1668         valid_codec = FALSE;
1669         goto next_supported_type;
1670       }
1671 
1672       color_formats_id =
1673           (*env)->GetFieldID (env, capabilities_class, "colorFormats", "[I");
1674       profile_levels_id =
1675           (*env)->GetFieldID (env, capabilities_class, "profileLevels",
1676           "[Landroid/media/MediaCodecInfo$CodecProfileLevel;");
1677       if (!color_formats_id || !profile_levels_id) {
1678         GST_ERROR ("Failed to get capabilities field IDs");
1679         (*env)->ExceptionDescribe (env);
1680         (*env)->ExceptionClear (env);
1681         valid_codec = FALSE;
1682         goto next_supported_type;
1683       }
1684 
1685       if (g_str_has_prefix (gst_codec_type->mime, "video/")) {
1686         color_formats =
1687             (*env)->GetObjectField (env, capabilities, color_formats_id);
1688         if ((*env)->ExceptionCheck (env)) {
1689           GST_ERROR ("Failed to get color formats");
1690           (*env)->ExceptionDescribe (env);
1691           (*env)->ExceptionClear (env);
1692           valid_codec = FALSE;
1693           goto next_supported_type;
1694         }
1695 
1696         n_elems = (*env)->GetArrayLength (env, color_formats);
1697         if ((*env)->ExceptionCheck (env)) {
1698           GST_ERROR ("Failed to get color formats array length");
1699           (*env)->ExceptionDescribe (env);
1700           (*env)->ExceptionClear (env);
1701           valid_codec = FALSE;
1702           goto next_supported_type;
1703         }
1704         gst_codec_type->n_color_formats = n_elems;
1705         gst_codec_type->color_formats = g_new0 (gint, n_elems);
1706         color_formats_elems =
1707             (*env)->GetIntArrayElements (env, color_formats, NULL);
1708         if ((*env)->ExceptionCheck (env)) {
1709           GST_ERROR ("Failed to get color format elements");
1710           (*env)->ExceptionDescribe (env);
1711           (*env)->ExceptionClear (env);
1712           valid_codec = FALSE;
1713           goto next_supported_type;
1714         }
1715 
1716         for (k = 0; k < n_elems; k++) {
1717           GST_INFO ("Color format %d: 0x%x", k, color_formats_elems[k]);
1718           gst_codec_type->color_formats[k] = color_formats_elems[k];
1719         }
1720 
1721         if (!n_elems) {
1722           GST_ERROR ("No supported color formats for video codec");
1723           valid_codec = FALSE;
1724           goto next_supported_type;
1725         }
1726 
1727         if (!accepted_color_formats (gst_codec_type, is_encoder)) {
1728           if (!ignore_unknown_color_formats) {
1729             gst_codec_info->gl_output_only = TRUE;
1730             GST_WARNING
1731                 ("%s %s has unknown color formats, only direct rendering will be supported",
1732                 gst_codec_type->mime, is_encoder ? "encoder" : "decoder");
1733           }
1734         }
1735       }
1736 
1737       profile_levels =
1738           (*env)->GetObjectField (env, capabilities, profile_levels_id);
1739       if ((*env)->ExceptionCheck (env)) {
1740         GST_ERROR ("Failed to get profile/levels");
1741         (*env)->ExceptionDescribe (env);
1742         (*env)->ExceptionClear (env);
1743         valid_codec = FALSE;
1744         goto next_supported_type;
1745       }
1746 
1747       n_elems = (*env)->GetArrayLength (env, profile_levels);
1748       if ((*env)->ExceptionCheck (env)) {
1749         GST_ERROR ("Failed to get profile/levels array length");
1750         (*env)->ExceptionDescribe (env);
1751         (*env)->ExceptionClear (env);
1752         valid_codec = FALSE;
1753         goto next_supported_type;
1754       }
1755       gst_codec_type->n_profile_levels = n_elems;
1756       gst_codec_type->profile_levels =
1757           g_malloc0 (sizeof (gst_codec_type->profile_levels[0]) * n_elems);
1758       for (k = 0; k < n_elems; k++) {
1759         jobject profile_level = NULL;
1760         jclass profile_level_class = NULL;
1761         jfieldID level_id, profile_id;
1762         jint level, profile;
1763 
1764         profile_level = (*env)->GetObjectArrayElement (env, profile_levels, k);
1765         if ((*env)->ExceptionCheck (env)) {
1766           GST_ERROR ("Failed to get %d-th profile/level", k);
1767           (*env)->ExceptionDescribe (env);
1768           (*env)->ExceptionClear (env);
1769           valid_codec = FALSE;
1770           goto next_profile_level;
1771         }
1772 
1773         profile_level_class = (*env)->GetObjectClass (env, profile_level);
1774         if (!profile_level_class) {
1775           GST_ERROR ("Failed to get profile/level class");
1776           (*env)->ExceptionDescribe (env);
1777           (*env)->ExceptionClear (env);
1778           valid_codec = FALSE;
1779           goto next_profile_level;
1780         }
1781 
1782         level_id = (*env)->GetFieldID (env, profile_level_class, "level", "I");
1783         profile_id =
1784             (*env)->GetFieldID (env, profile_level_class, "profile", "I");
1785         if (!level_id || !profile_id) {
1786           GST_ERROR ("Failed to get profile/level field IDs");
1787           (*env)->ExceptionDescribe (env);
1788           (*env)->ExceptionClear (env);
1789           valid_codec = FALSE;
1790           goto next_profile_level;
1791         }
1792 
1793         level = (*env)->GetIntField (env, profile_level, level_id);
1794         if ((*env)->ExceptionCheck (env)) {
1795           GST_ERROR ("Failed to get level");
1796           (*env)->ExceptionDescribe (env);
1797           (*env)->ExceptionClear (env);
1798           valid_codec = FALSE;
1799           goto next_profile_level;
1800         }
1801         GST_INFO ("Level %d: 0x%08x", k, level);
1802         gst_codec_type->profile_levels[k].level = level;
1803 
1804         profile = (*env)->GetIntField (env, profile_level, profile_id);
1805         if ((*env)->ExceptionCheck (env)) {
1806           GST_ERROR ("Failed to get profile");
1807           (*env)->ExceptionDescribe (env);
1808           (*env)->ExceptionClear (env);
1809           valid_codec = FALSE;
1810           goto next_profile_level;
1811         }
1812         GST_INFO ("Profile %d: 0x%08x", k, profile);
1813         gst_codec_type->profile_levels[k].profile = profile;
1814 
1815       next_profile_level:
1816         if (profile_level)
1817           (*env)->DeleteLocalRef (env, profile_level);
1818         profile_level = NULL;
1819         if (profile_level_class)
1820           (*env)->DeleteLocalRef (env, profile_level_class);
1821         profile_level_class = NULL;
1822         if (!valid_codec)
1823           break;
1824       }
1825 
1826     next_supported_type:
1827       if (color_formats_elems)
1828         (*env)->ReleaseIntArrayElements (env, color_formats,
1829             color_formats_elems, JNI_ABORT);
1830       color_formats_elems = NULL;
1831       if (color_formats)
1832         (*env)->DeleteLocalRef (env, color_formats);
1833       color_formats = NULL;
1834       if (profile_levels)
1835         (*env)->DeleteLocalRef (env, profile_levels);
1836       color_formats = NULL;
1837       if (capabilities)
1838         (*env)->DeleteLocalRef (env, capabilities);
1839       capabilities = NULL;
1840       if (capabilities_class)
1841         (*env)->DeleteLocalRef (env, capabilities_class);
1842       capabilities_class = NULL;
1843       if (supported_type_str)
1844         (*env)->ReleaseStringUTFChars (env, supported_type, supported_type_str);
1845       supported_type_str = NULL;
1846       if (supported_type)
1847         (*env)->DeleteLocalRef (env, supported_type);
1848       supported_type = NULL;
1849       if (!valid_codec)
1850         break;
1851     }
1852 
1853     /* We need at least a valid supported type */
1854     if (valid_codec) {
1855       GList *l;
1856 
1857       for (l = codec_infos.head; l; l = l->next) {
1858         GstAmcCodecInfo *tmp = l->data;
1859 
1860         if (strcmp (tmp->name, gst_codec_info->name) == 0
1861             && ! !tmp->is_encoder == ! !gst_codec_info->is_encoder) {
1862           gint m = tmp->n_supported_types, n;
1863 
1864           GST_LOG ("Successfully scanned codec '%s', appending to existing",
1865               name_str);
1866 
1867           tmp->gl_output_only |= gst_codec_info->gl_output_only;
1868           tmp->n_supported_types += gst_codec_info->n_supported_types;
1869           tmp->supported_types =
1870               g_realloc (tmp->supported_types,
1871               tmp->n_supported_types * sizeof (GstAmcCodecType));
1872 
1873           for (n = 0; n < gst_codec_info->n_supported_types; n++, m++) {
1874             tmp->supported_types[m] = gst_codec_info->supported_types[n];
1875           }
1876           g_free (gst_codec_info->supported_types);
1877           g_free (gst_codec_info->name);
1878           g_free (gst_codec_info);
1879           gst_codec_info = NULL;
1880 
1881           break;
1882         }
1883       }
1884 
1885       /* Found no existing codec with this name */
1886       if (l == NULL) {
1887         GST_LOG ("Successfully scanned codec '%s'", name_str);
1888         g_queue_push_tail (&codec_infos, gst_codec_info);
1889         gst_codec_info = NULL;
1890       }
1891     }
1892 
1893     /* Clean up of all local references we got */
1894   next_codec:
1895     if (name_str)
1896       (*env)->ReleaseStringUTFChars (env, name, name_str);
1897     name_str = NULL;
1898     if (name)
1899       (*env)->DeleteLocalRef (env, name);
1900     name = NULL;
1901     if (supported_types)
1902       (*env)->DeleteLocalRef (env, supported_types);
1903     supported_types = NULL;
1904     if (codec_info)
1905       (*env)->DeleteLocalRef (env, codec_info);
1906     codec_info = NULL;
1907     if (codec_info_class)
1908       (*env)->DeleteLocalRef (env, codec_info_class);
1909     codec_info_class = NULL;
1910     if (gst_codec_info) {
1911       gint j;
1912 
1913       for (j = 0; j < gst_codec_info->n_supported_types; j++) {
1914         GstAmcCodecType *gst_codec_type = &gst_codec_info->supported_types[j];
1915 
1916         g_free (gst_codec_type->mime);
1917         g_free (gst_codec_type->color_formats);
1918         g_free (gst_codec_type->profile_levels);
1919       }
1920       g_free (gst_codec_info->supported_types);
1921       g_free (gst_codec_info->name);
1922       g_free (gst_codec_info);
1923     }
1924     gst_codec_info = NULL;
1925     valid_codec = TRUE;
1926   }
1927 
1928   ret = codec_infos.length != 0;
1929 
1930   /* If successful we store a cache of the codec information in
1931    * the registry. Otherwise we would always load all codecs during
1932    * plugin initialization which can take quite some time (because
1933    * of hardware) and also loads lots of shared libraries (which
1934    * number is limited by 64 in Android).
1935    */
1936   if (ret) {
1937     GstStructure *new_cache_data = gst_structure_new_empty ("gst-amc-cache");
1938     GList *l;
1939     GValue arr = { 0, };
1940 
1941     g_value_init (&arr, GST_TYPE_ARRAY);
1942 
1943     for (l = codec_infos.head; l; l = l->next) {
1944       GstAmcCodecInfo *gst_codec_info = l->data;
1945       GValue cv = { 0, };
1946       GstStructure *cs = gst_structure_new_empty ("gst-amc-codec");
1947       GValue starr = { 0, };
1948       gint i;
1949 
1950       gst_structure_set (cs, "name", G_TYPE_STRING, gst_codec_info->name,
1951           "is-encoder", G_TYPE_BOOLEAN, gst_codec_info->is_encoder, NULL);
1952 
1953       g_value_init (&starr, GST_TYPE_ARRAY);
1954 
1955       for (i = 0; i < gst_codec_info->n_supported_types; i++) {
1956         GstAmcCodecType *gst_codec_type = &gst_codec_info->supported_types[i];
1957         GstStructure *sts = gst_structure_new_empty ("gst-amc-supported-type");
1958         GValue stv = { 0, };
1959         GValue tmparr = { 0, };
1960         gint j;
1961 
1962         gst_structure_set (sts, "mime", G_TYPE_STRING, gst_codec_type->mime,
1963             NULL);
1964 
1965         g_value_init (&tmparr, GST_TYPE_ARRAY);
1966         for (j = 0; j < gst_codec_type->n_color_formats; j++) {
1967           GValue tmp = { 0, };
1968 
1969           g_value_init (&tmp, G_TYPE_INT);
1970           g_value_set_int (&tmp, gst_codec_type->color_formats[j]);
1971           gst_value_array_append_value (&tmparr, &tmp);
1972           g_value_unset (&tmp);
1973         }
1974         gst_structure_set_value (sts, "color-formats", &tmparr);
1975         g_value_unset (&tmparr);
1976 
1977         g_value_init (&tmparr, GST_TYPE_ARRAY);
1978         for (j = 0; j < gst_codec_type->n_profile_levels; j++) {
1979           GValue tmparr2 = { 0, };
1980           GValue tmp = { 0, };
1981 
1982           g_value_init (&tmparr2, GST_TYPE_ARRAY);
1983           g_value_init (&tmp, G_TYPE_INT);
1984           g_value_set_int (&tmp, gst_codec_type->profile_levels[j].profile);
1985           gst_value_array_append_value (&tmparr2, &tmp);
1986           g_value_set_int (&tmp, gst_codec_type->profile_levels[j].level);
1987           gst_value_array_append_value (&tmparr2, &tmp);
1988           gst_value_array_append_value (&tmparr, &tmparr2);
1989           g_value_unset (&tmp);
1990           g_value_unset (&tmparr2);
1991         }
1992         gst_structure_set_value (sts, "profile-levels", &tmparr);
1993 
1994         g_value_init (&stv, GST_TYPE_STRUCTURE);
1995         gst_value_set_structure (&stv, sts);
1996         gst_value_array_append_value (&starr, &stv);
1997         g_value_unset (&tmparr);
1998         gst_structure_free (sts);
1999       }
2000 
2001       gst_structure_set_value (cs, "supported-types", &starr);
2002       g_value_unset (&starr);
2003 
2004       g_value_init (&cv, GST_TYPE_STRUCTURE);
2005       gst_value_set_structure (&cv, cs);
2006       gst_value_array_append_value (&arr, &cv);
2007       g_value_unset (&cv);
2008       gst_structure_free (cs);
2009     }
2010 
2011     gst_structure_set_value (new_cache_data, "codecs", &arr);
2012     g_value_unset (&arr);
2013 
2014     gst_plugin_set_cache_data (plugin, new_cache_data);
2015   }
2016 
2017 done:
2018   if (codec_list_class)
2019     (*env)->DeleteLocalRef (env, codec_list_class);
2020 
2021   return ret;
2022 }
2023 
2024 static const struct
2025 {
2026   gint color_format;
2027   GstVideoFormat video_format;
2028 } color_format_mapping_table[] = {
2029   {
2030   COLOR_FormatYUV420Planar, GST_VIDEO_FORMAT_I420}, {
2031   COLOR_FormatYUV420Flexible, GST_VIDEO_FORMAT_I420}, {
2032   COLOR_FormatYUV420SemiPlanar, GST_VIDEO_FORMAT_NV12}, {
2033   COLOR_TI_FormatYUV420PackedSemiPlanar, GST_VIDEO_FORMAT_NV12}, {
2034   COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced, GST_VIDEO_FORMAT_NV12}, {
2035   COLOR_INTEL_FormatYUV420PackedSemiPlanar, GST_VIDEO_FORMAT_NV12}, {
2036   COLOR_INTEL_FormatYUV420PackedSemiPlanar_Tiled, GST_VIDEO_FORMAT_NV12}, {
2037   COLOR_QCOM_FormatYUV420SemiPlanar, GST_VIDEO_FORMAT_NV12}, {
2038   COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka, GST_VIDEO_FORMAT_NV12}, {
2039   COLOR_QCOM_FormatYVU420SemiPlanar32m, GST_VIDEO_FORMAT_NV12}, {
2040   COLOR_QCOM_FormatYVU420SemiPlanar32mMultiView, GST_VIDEO_FORMAT_NV12}, {
2041   COLOR_OMX_SEC_FormatNV12Tiled, GST_VIDEO_FORMAT_NV12}, {
2042   COLOR_FormatYCbYCr, GST_VIDEO_FORMAT_YUY2}, {
2043   COLOR_FormatYV12, GST_VIDEO_FORMAT_YV12}
2044 };
2045 
2046 static gboolean
accepted_color_formats(GstAmcCodecType * type,gboolean is_encoder)2047 accepted_color_formats (GstAmcCodecType * type, gboolean is_encoder)
2048 {
2049   gint i, j;
2050   gint accepted = 0, all = type->n_color_formats;
2051 
2052   for (i = 0; i < type->n_color_formats; i++) {
2053     gboolean found = FALSE;
2054     /* We ignore this one */
2055     if (type->color_formats[i] == COLOR_FormatAndroidOpaque) {
2056       all--;
2057       continue;
2058     }
2059 
2060     for (j = 0; j < G_N_ELEMENTS (color_format_mapping_table); j++) {
2061       if (color_format_mapping_table[j].color_format == type->color_formats[i]) {
2062         found = TRUE;
2063         accepted++;
2064         break;
2065       }
2066     }
2067 
2068     if (!found) {
2069       GST_ERROR ("Unknown color format 0x%x, ignoring", type->color_formats[i]);
2070     }
2071   }
2072 
2073   if (is_encoder)
2074     return accepted > 0;
2075   else
2076     return accepted == all && all > 0;
2077 }
2078 
2079 GstVideoFormat
gst_amc_color_format_to_video_format(const GstAmcCodecInfo * codec_info,const gchar * mime,gint color_format)2080 gst_amc_color_format_to_video_format (const GstAmcCodecInfo * codec_info,
2081     const gchar * mime, gint color_format)
2082 {
2083   gint i;
2084 
2085   if (color_format == COLOR_FormatYCbYCr) {
2086     if (strcmp (codec_info->name, "OMX.k3.video.decoder.avc") == 0) {
2087       GST_INFO
2088           ("OMX.k3.video.decoder.avc: COLOR_FormatYCbYCr is actually GST_VIDEO_FORMAT_NV12.");
2089       return GST_VIDEO_FORMAT_NV12;
2090     }
2091 
2092     /* FIXME COLOR_FormatYCbYCr doesn't work properly for OMX.k3.video.encoder.avc temporarily. */
2093     if (strcmp (codec_info->name, "OMX.k3.video.encoder.avc") == 0) {
2094       GST_INFO
2095           ("OMX.k3.video.encoder.avc: COLOR_FormatYCbYCr is not supported yet.");
2096       return GST_VIDEO_FORMAT_UNKNOWN;
2097     }
2098 
2099     /* FIXME COLOR_FormatYCbYCr is not supported in gst_amc_color_format_info_set yet, mask it. */
2100     return GST_VIDEO_FORMAT_UNKNOWN;
2101   }
2102 
2103   if (color_format == COLOR_FormatYUV420SemiPlanar) {
2104     if (strcmp (codec_info->name, "OMX.k3.video.encoder.avc") == 0) {
2105       GST_INFO
2106           ("OMX.k3.video.encoder.avc: COLOR_FormatYUV420SemiPlanar is actually GST_VIDEO_FORMAT_NV21.");
2107       return GST_VIDEO_FORMAT_NV21;
2108     }
2109   }
2110 
2111   for (i = 0; i < G_N_ELEMENTS (color_format_mapping_table); i++) {
2112     if (color_format_mapping_table[i].color_format == color_format)
2113       return color_format_mapping_table[i].video_format;
2114   }
2115 
2116   return GST_VIDEO_FORMAT_UNKNOWN;
2117 }
2118 
2119 gint
gst_amc_video_format_to_color_format(const GstAmcCodecInfo * codec_info,const gchar * mime,GstVideoFormat video_format)2120 gst_amc_video_format_to_color_format (const GstAmcCodecInfo * codec_info,
2121     const gchar * mime, GstVideoFormat video_format)
2122 {
2123   const GstAmcCodecType *codec_type = NULL;
2124   gint i, j;
2125 
2126   for (i = 0; i < codec_info->n_supported_types; i++) {
2127     if (strcmp (codec_info->supported_types[i].mime, mime) == 0) {
2128       codec_type = &codec_info->supported_types[i];
2129       break;
2130     }
2131   }
2132 
2133   if (!codec_type)
2134     return -1;
2135 
2136   if (video_format == GST_VIDEO_FORMAT_NV12) {
2137     if (strcmp (codec_info->name, "OMX.k3.video.decoder.avc") == 0) {
2138       GST_INFO
2139           ("OMX.k3.video.decoder.avc: GST_VIDEO_FORMAT_NV12 is reported as COLOR_FormatYCbYCr.");
2140 
2141       return COLOR_FormatYCbYCr;
2142     }
2143   }
2144 
2145   if (video_format == GST_VIDEO_FORMAT_NV21) {
2146     if (strcmp (codec_info->name, "OMX.k3.video.encoder.avc") == 0) {
2147       GST_INFO
2148           ("OMX.k3.video.encoder.avc: GST_VIDEO_FORMAT_NV21 is reported as COLOR_FormatYUV420SemiPlanar.");
2149 
2150       return COLOR_FormatYUV420SemiPlanar;
2151     }
2152   }
2153 
2154   for (i = 0; i < G_N_ELEMENTS (color_format_mapping_table); i++) {
2155     if (color_format_mapping_table[i].video_format == video_format) {
2156       gint color_format = color_format_mapping_table[i].color_format;
2157 
2158       for (j = 0; j < codec_type->n_color_formats; j++)
2159         if (color_format == codec_type->color_formats[j])
2160           return color_format;
2161     }
2162   }
2163 
2164   return -1;
2165 }
2166 
2167 /*
2168  * The format is called QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka.
2169  * Which is actually NV12 (interleaved U&V).
2170  */
2171 #define TILE_WIDTH 64
2172 #define TILE_HEIGHT 32
2173 #define TILE_SIZE (TILE_WIDTH * TILE_HEIGHT)
2174 #define TILE_GROUP_SIZE (4 * TILE_SIZE)
2175 
2176 /* get frame tile coordinate. XXX: nothing to be understood here, don't try. */
2177 static size_t
tile_pos(size_t x,size_t y,size_t w,size_t h)2178 tile_pos (size_t x, size_t y, size_t w, size_t h)
2179 {
2180   size_t flim = x + (y & ~1) * w;
2181 
2182   if (y & 1) {
2183     flim += (x & ~3) + 2;
2184   } else if ((h & 1) == 0 || y != (h - 1)) {
2185     flim += (x + 2) & ~3;
2186   }
2187 
2188   return flim;
2189 }
2190 
2191 gboolean
gst_amc_color_format_info_set(GstAmcColorFormatInfo * color_format_info,const GstAmcCodecInfo * codec_info,const gchar * mime,gint color_format,gint width,gint height,gint stride,gint slice_height,gint crop_left,gint crop_right,gint crop_top,gint crop_bottom)2192 gst_amc_color_format_info_set (GstAmcColorFormatInfo * color_format_info,
2193     const GstAmcCodecInfo * codec_info, const gchar * mime, gint color_format,
2194     gint width, gint height, gint stride, gint slice_height, gint crop_left,
2195     gint crop_right, gint crop_top, gint crop_bottom)
2196 {
2197   gint frame_size = 0;
2198 
2199   if (color_format == COLOR_FormatYCbYCr) {
2200     if (strcmp (codec_info->name, "OMX.k3.video.decoder.avc") == 0)
2201       color_format = COLOR_FormatYUV420SemiPlanar;
2202   }
2203 
2204   /* Samsung Galaxy S3 seems to report wrong strides.
2205    * I.e. BigBuckBunny 854x480 H264 reports a stride of 864 when it is
2206    * actually 854, so we use width instead of stride here.
2207    * This is obviously bound to break in the future. */
2208   if (g_str_has_prefix (codec_info->name, "OMX.SEC.")) {
2209     stride = width;
2210   }
2211 
2212   if (strcmp (codec_info->name, "OMX.k3.video.decoder.avc") == 0) {
2213     stride = width;
2214     slice_height = height;
2215   }
2216 
2217   if (slice_height == 0) {
2218     /* NVidia Tegra 3 on Nexus 7 does not set this */
2219     if (g_str_has_prefix (codec_info->name, "OMX.Nvidia."))
2220       slice_height = GST_ROUND_UP_16 (height);
2221   }
2222 
2223   if (width == 0 || height == 0) {
2224     GST_ERROR ("Width or height is 0");
2225     return FALSE;
2226   }
2227 
2228   switch (color_format) {
2229     case COLOR_FormatYUV420Planar:
2230     case COLOR_FormatYUV420Flexible:{
2231     case COLOR_FormatYV12:
2232       if (stride == 0 || slice_height == 0) {
2233         GST_ERROR ("Stride or slice height is 0");
2234         return FALSE;
2235       }
2236 
2237       frame_size =
2238           stride * slice_height + 2 * ((stride + 1) / 2) * ((slice_height +
2239               1) / 2);
2240       break;
2241     }
2242     case COLOR_INTEL_FormatYUV420PackedSemiPlanar:
2243     case COLOR_INTEL_FormatYUV420PackedSemiPlanar_Tiled:
2244       if (stride == 0) {
2245         GST_ERROR ("Stride is 0");
2246         return FALSE;
2247       }
2248       if (slice_height <= 0)
2249         slice_height = height;
2250 
2251       frame_size =
2252           stride * (slice_height - crop_top / 2) +
2253           (GST_ROUND_UP_2 (stride) * ((slice_height + 1) / 2));
2254       break;
2255 
2256     case COLOR_TI_FormatYUV420PackedSemiPlanar:
2257     case COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced:{
2258       if (stride == 0 || slice_height == 0) {
2259         GST_ERROR ("Stride or slice height is 0");
2260         return FALSE;
2261       }
2262 
2263       frame_size =
2264           stride * (slice_height - crop_top / 2) +
2265           (GST_ROUND_UP_2 (stride) * ((slice_height + 1) / 2));
2266       break;
2267     }
2268     case COLOR_QCOM_FormatYUV420SemiPlanar:
2269     case COLOR_QCOM_FormatYVU420SemiPlanar32m:
2270     case COLOR_QCOM_FormatYVU420SemiPlanar32mMultiView:
2271     case COLOR_FormatYUV420SemiPlanar:{
2272       if (stride == 0 || slice_height == 0) {
2273         GST_ERROR ("Stride or slice height is 0");
2274         return FALSE;
2275       }
2276 
2277       frame_size = stride * slice_height + stride * ((slice_height + 1) / 2);
2278       break;
2279     }
2280     case COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka:{
2281       const size_t tile_w = (width - 1) / TILE_WIDTH + 1;
2282       const size_t tile_w_align = (tile_w + 1) & ~1;
2283       const size_t tile_h_luma = (height - 1) / TILE_HEIGHT + 1;
2284       frame_size =
2285           tile_pos (tile_w, tile_h_luma, tile_w_align, tile_h_luma) * TILE_SIZE;
2286       break;
2287     }
2288     default:
2289       GST_ERROR ("Unsupported color format %d", color_format);
2290       return FALSE;
2291       break;
2292   }
2293 
2294   color_format_info->color_format = color_format;
2295   color_format_info->width = width;
2296   color_format_info->height = height;
2297   color_format_info->stride = stride;
2298   color_format_info->slice_height = slice_height;
2299   color_format_info->crop_left = crop_left;
2300   color_format_info->crop_right = crop_right;
2301   color_format_info->crop_top = crop_top;
2302   color_format_info->crop_bottom = crop_bottom;
2303   color_format_info->frame_size = frame_size;
2304 
2305   return TRUE;
2306 }
2307 
2308 /* The weird handling of cropping, alignment and everything is taken from
2309  * platform/frameworks/media/libstagefright/colorconversion/ColorConversion.cpp
2310  */
2311 gboolean
gst_amc_color_format_copy(GstAmcColorFormatInfo * cinfo,GstAmcBuffer * cbuffer,const GstAmcBufferInfo * cbuffer_info,GstVideoInfo * vinfo,GstBuffer * vbuffer,GstAmcColorFormatCopyDirection direction)2312 gst_amc_color_format_copy (GstAmcColorFormatInfo * cinfo,
2313     GstAmcBuffer * cbuffer, const GstAmcBufferInfo * cbuffer_info,
2314     GstVideoInfo * vinfo, GstBuffer * vbuffer,
2315     GstAmcColorFormatCopyDirection direction)
2316 {
2317   gboolean ret = FALSE;
2318   guint8 *cptr = NULL, *vptr = NULL;
2319   guint8 **src, **dest;
2320 
2321   if (direction == COLOR_FORMAT_COPY_OUT) {
2322     src = &cptr;
2323     dest = &vptr;
2324   } else {
2325     src = &vptr;
2326     dest = &cptr;
2327   }
2328 
2329   /* Same video format */
2330   if (cbuffer_info->size == gst_buffer_get_size (vbuffer)) {
2331     GstMapInfo minfo;
2332 
2333     GST_DEBUG ("Buffer sizes equal, doing fast copy");
2334     gst_buffer_map (vbuffer, &minfo, GST_MAP_WRITE);
2335 
2336     cptr = cbuffer->data + cbuffer_info->offset;
2337     vptr = minfo.data;
2338     orc_memcpy (*dest, *src, cbuffer_info->size);
2339 
2340     gst_buffer_unmap (vbuffer, &minfo);
2341     ret = TRUE;
2342     goto done;
2343   }
2344 
2345   GST_DEBUG ("Sizes not equal (%d vs %" G_GSIZE_FORMAT
2346       "), doing slow line-by-line copying", cbuffer_info->size,
2347       gst_buffer_get_size (vbuffer));
2348 
2349   /* Different video format, try to convert */
2350   switch (cinfo->color_format) {
2351     case COLOR_FormatYUV420Planar:{
2352       GstVideoFrame vframe;
2353       gint i, j, height;
2354       gint stride, slice_height;
2355       gint c_stride, v_stride;
2356       gint row_length;
2357 
2358       stride = cinfo->stride;
2359       slice_height = cinfo->slice_height;
2360       g_assert (stride > 0 && slice_height > 0);
2361 
2362       gst_video_frame_map (&vframe, vinfo, vbuffer, GST_MAP_WRITE);
2363 
2364       for (i = 0; i < 3; i++) {
2365         if (i == 0) {
2366           c_stride = stride;
2367           v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i);
2368         } else {
2369           c_stride = (stride + 1) / 2;
2370           v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i);
2371         }
2372 
2373         cptr = cbuffer->data + cbuffer_info->offset;
2374 
2375         if (i == 0) {
2376           cptr += cinfo->crop_top * stride;
2377           cptr += cinfo->crop_left;
2378           row_length = cinfo->width;
2379         } else if (i > 0) {
2380           /* skip the Y plane */
2381           cptr += slice_height * stride;
2382 
2383           /* crop_top/crop_left divided by two
2384            * because one byte of the U/V planes
2385            * corresponds to two pixels horizontally/vertically */
2386           cptr += cinfo->crop_top / 2 * c_stride;
2387           cptr += cinfo->crop_left / 2;
2388           row_length = (cinfo->width + 1) / 2;
2389         }
2390         if (i == 2) {
2391           /* skip the U plane */
2392           cptr += ((slice_height + 1) / 2) * ((stride + 1) / 2);
2393         }
2394 
2395         vptr = GST_VIDEO_FRAME_COMP_DATA (&vframe, i);
2396         height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i);
2397 
2398         for (j = 0; j < height; j++) {
2399           orc_memcpy (*dest, *src, row_length);
2400           cptr += c_stride;
2401           vptr += v_stride;
2402         }
2403       }
2404       gst_video_frame_unmap (&vframe);
2405       ret = TRUE;
2406       break;
2407     }
2408     case COLOR_TI_FormatYUV420PackedSemiPlanar:
2409     case COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced:{
2410       gint i, j, height;
2411       gint c_stride, v_stride;
2412       gint row_length;
2413       GstVideoFrame vframe;
2414 
2415       /* This should always be set */
2416       g_assert (cinfo->stride > 0 && cinfo->slice_height > 0);
2417 
2418       /* FIXME: This does not work for odd widths or heights
2419        * but might as well be a bug in the codec */
2420       gst_video_frame_map (&vframe, vinfo, vbuffer, GST_MAP_WRITE);
2421       for (i = 0; i < 2; i++) {
2422         if (i == 0) {
2423           c_stride = cinfo->stride;
2424           v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i);
2425         } else {
2426           c_stride = GST_ROUND_UP_2 (cinfo->stride);
2427           v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i);
2428         }
2429 
2430         cptr = cbuffer->data + cbuffer_info->offset;
2431         if (i == 0) {
2432           row_length = cinfo->width;
2433         } else if (i == 1) {
2434           cptr += (cinfo->slice_height - cinfo->crop_top / 2) * cinfo->stride;
2435           row_length = GST_ROUND_UP_2 (cinfo->width);
2436         }
2437 
2438         vptr = GST_VIDEO_FRAME_COMP_DATA (&vframe, i);
2439         height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i);
2440 
2441         for (j = 0; j < height; j++) {
2442           orc_memcpy (*dest, *src, row_length);
2443           cptr += c_stride;
2444           vptr += v_stride;
2445         }
2446       }
2447       gst_video_frame_unmap (&vframe);
2448       ret = TRUE;
2449       break;
2450     }
2451     case COLOR_QCOM_FormatYUV420SemiPlanar:
2452     case COLOR_QCOM_FormatYVU420SemiPlanar32m:
2453     case COLOR_QCOM_FormatYVU420SemiPlanar32mMultiView:
2454     case COLOR_FormatYUV420SemiPlanar:{
2455       gint i, j, height;
2456       gint c_stride, v_stride;
2457       gint row_length;
2458       GstVideoFrame vframe;
2459 
2460       /* This should always be set */
2461       g_assert (cinfo->stride > 0 && cinfo->slice_height > 0);
2462 
2463       gst_video_frame_map (&vframe, vinfo, vbuffer, GST_MAP_WRITE);
2464 
2465       for (i = 0; i < 2; i++) {
2466         c_stride = cinfo->stride;
2467         v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i);
2468 
2469         cptr = cbuffer->data + cbuffer_info->offset;
2470         if (i == 0) {
2471           cptr += cinfo->crop_top * cinfo->stride;
2472           cptr += cinfo->crop_left;
2473           row_length = cinfo->width;
2474         } else if (i == 1) {
2475           cptr += cinfo->slice_height * cinfo->stride;
2476           cptr += cinfo->crop_top * cinfo->stride;
2477           cptr += cinfo->crop_left;
2478           row_length = cinfo->width;
2479         }
2480 
2481         vptr = GST_VIDEO_FRAME_COMP_DATA (&vframe, i);
2482         height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i);
2483 
2484         for (j = 0; j < height; j++) {
2485           orc_memcpy (*dest, *src, row_length);
2486           cptr += c_stride;
2487           vptr += v_stride;
2488         }
2489       }
2490       gst_video_frame_unmap (&vframe);
2491       ret = TRUE;
2492       break;
2493     }
2494       /* FIXME: This should be in libgstvideo as MT12 or similar, see v4l2 */
2495     case COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka:{
2496       GstVideoFrame vframe;
2497       gint width = cinfo->width;
2498       gint height = cinfo->height;
2499       gint v_luma_stride, v_chroma_stride;
2500       guint8 *cdata = cbuffer->data + cbuffer_info->offset;
2501       guint8 *v_luma, *v_chroma;
2502       gint y;
2503       const size_t tile_w = (width - 1) / TILE_WIDTH + 1;
2504       const size_t tile_w_align = (tile_w + 1) & ~1;
2505       const size_t tile_h_luma = (height - 1) / TILE_HEIGHT + 1;
2506       const size_t tile_h_chroma = (height / 2 - 1) / TILE_HEIGHT + 1;
2507       size_t luma_size = tile_w_align * tile_h_luma * TILE_SIZE;
2508 
2509       gst_video_frame_map (&vframe, vinfo, vbuffer, GST_MAP_WRITE);
2510       v_luma = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0);
2511       v_chroma = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 1);
2512       v_luma_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 0);
2513       v_chroma_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 1);
2514 
2515       if ((luma_size % TILE_GROUP_SIZE) != 0)
2516         luma_size = (((luma_size - 1) / TILE_GROUP_SIZE) + 1) * TILE_GROUP_SIZE;
2517 
2518       for (y = 0; y < tile_h_luma; y++) {
2519         size_t row_width = width;
2520         gint x;
2521 
2522         for (x = 0; x < tile_w; x++) {
2523           size_t tile_width = row_width;
2524           size_t tile_height = height;
2525           gint luma_idx;
2526           gint chroma_idx;
2527           /* luma source pointer for this tile */
2528           uint8_t *c_luma =
2529               cdata + tile_pos (x, y, tile_w_align, tile_h_luma) * TILE_SIZE;
2530 
2531           /* chroma source pointer for this tile */
2532           uint8_t *c_chroma =
2533               cdata + luma_size + tile_pos (x, y / 2, tile_w_align,
2534               tile_h_chroma) * TILE_SIZE;
2535           if (y & 1)
2536             c_chroma += TILE_SIZE / 2;
2537 
2538           /* account for right columns */
2539           if (tile_width > TILE_WIDTH)
2540             tile_width = TILE_WIDTH;
2541 
2542           /* account for bottom rows */
2543           if (tile_height > TILE_HEIGHT)
2544             tile_height = TILE_HEIGHT;
2545 
2546           /* vptr luma memory index for this tile */
2547           luma_idx = y * TILE_HEIGHT * v_luma_stride + x * TILE_WIDTH;
2548 
2549           /* vptr chroma memory index for this tile */
2550           /* XXX: remove divisions */
2551           chroma_idx = y * TILE_HEIGHT / 2 * v_chroma_stride + x * TILE_WIDTH;
2552 
2553           tile_height /= 2;     // we copy 2 luma lines at once
2554           while (tile_height--) {
2555             vptr = v_luma + luma_idx;
2556             cptr = c_luma;
2557             memcpy (*dest, *src, tile_width);
2558             c_luma += TILE_WIDTH;
2559             luma_idx += v_luma_stride;
2560 
2561             vptr = v_luma + luma_idx;
2562             cptr = c_luma;
2563             memcpy (*dest, *src, tile_width);
2564             c_luma += TILE_WIDTH;
2565             luma_idx += v_luma_stride;
2566 
2567             vptr = v_chroma + chroma_idx;
2568             cptr = c_chroma;
2569             memcpy (*dest, *src, tile_width);
2570             c_chroma += TILE_WIDTH;
2571             chroma_idx += v_chroma_stride;
2572           }
2573           row_width -= TILE_WIDTH;
2574         }
2575         height -= TILE_HEIGHT;
2576       }
2577       gst_video_frame_unmap (&vframe);
2578       ret = TRUE;
2579       break;
2580 
2581     }
2582     default:
2583       GST_ERROR ("Unsupported color format %d", cinfo->color_format);
2584       goto done;
2585       break;
2586   }
2587 
2588 done:
2589   return ret;
2590 }
2591 
2592 static const struct
2593 {
2594   gint id;
2595   const gchar *str;
2596 } hevc_profile_mapping_table[] = {
2597   {
2598   HEVCProfileMain, "main"}, {
2599   HEVCProfileMain10, "main-10"}
2600 };
2601 
2602 const gchar *
gst_amc_hevc_profile_to_string(gint profile)2603 gst_amc_hevc_profile_to_string (gint profile)
2604 {
2605   gint i;
2606 
2607   for (i = 0; i < G_N_ELEMENTS (hevc_profile_mapping_table); i++) {
2608     if (hevc_profile_mapping_table[i].id == profile) {
2609       return hevc_profile_mapping_table[i].str;
2610     }
2611   }
2612 
2613   return NULL;
2614 }
2615 
2616 gint
gst_amc_hevc_profile_from_string(const gchar * profile)2617 gst_amc_hevc_profile_from_string (const gchar * profile)
2618 {
2619   gint i;
2620 
2621   g_return_val_if_fail (profile != NULL, -1);
2622 
2623   for (i = 0; i < G_N_ELEMENTS (hevc_profile_mapping_table); i++) {
2624     if (strcmp (hevc_profile_mapping_table[i].str, profile) == 0)
2625       return hevc_profile_mapping_table[i].id;
2626   }
2627 
2628   return -1;
2629 }
2630 
2631 static const struct
2632 {
2633   gint id;
2634   const gchar *tier_str;
2635   const gchar *level_str;
2636 } hevc_tier_level_mapping_table[] = {
2637   {
2638   HEVCMainTierLevel1, "main", "1"}, {
2639   HEVCMainTierLevel2, "main", "2"}, {
2640   HEVCMainTierLevel21, "main", "2.1"}, {
2641   HEVCMainTierLevel3, "main", "3"}, {
2642   HEVCMainTierLevel31, "main", "3.1"}, {
2643   HEVCMainTierLevel4, "main", "4"}, {
2644   HEVCMainTierLevel41, "main", "4.1"}, {
2645   HEVCMainTierLevel5, "main", "5"}, {
2646   HEVCMainTierLevel51, "main", "5.1"}, {
2647   HEVCMainTierLevel52, "main", "5.2"}, {
2648   HEVCMainTierLevel6, "main", "6"}, {
2649   HEVCMainTierLevel61, "main", "6.1"}, {
2650   HEVCMainTierLevel62, "main", "6.2"}, {
2651   HEVCHighTierLevel1, "high", "1"}, {
2652   HEVCHighTierLevel2, "high", "2"}, {
2653   HEVCHighTierLevel21, "high", "2.1"}, {
2654   HEVCHighTierLevel3, "high", "3"}, {
2655   HEVCHighTierLevel31, "high", "3.1"}, {
2656   HEVCHighTierLevel4, "high", "4"}, {
2657   HEVCHighTierLevel41, "high", "4.1"}, {
2658   HEVCHighTierLevel5, "high", "5"}, {
2659   HEVCHighTierLevel51, "high", "5.1"}, {
2660   HEVCHighTierLevel52, "high", "5.2"}, {
2661   HEVCHighTierLevel6, "high", "6"}, {
2662   HEVCHighTierLevel61, "high", "6.1"}
2663 };
2664 
2665 const gchar *
gst_amc_hevc_tier_level_to_string(gint tier_level,const gchar ** tier)2666 gst_amc_hevc_tier_level_to_string (gint tier_level, const gchar ** tier)
2667 {
2668   gint i;
2669 
2670   for (i = 0; i < G_N_ELEMENTS (hevc_tier_level_mapping_table); i++) {
2671     if (hevc_tier_level_mapping_table[i].id == tier_level)
2672       *tier = hevc_tier_level_mapping_table[i].tier_str;
2673     return hevc_tier_level_mapping_table[i].level_str;
2674   }
2675 
2676   return NULL;
2677 }
2678 
2679 gint
gst_amc_hevc_tier_level_from_string(const gchar * tier,const gchar * level)2680 gst_amc_hevc_tier_level_from_string (const gchar * tier, const gchar * level)
2681 {
2682   gint i;
2683 
2684   g_return_val_if_fail (level != NULL, -1);
2685 
2686   for (i = 0; i < G_N_ELEMENTS (hevc_tier_level_mapping_table); i++) {
2687     if (strcmp (hevc_tier_level_mapping_table[i].tier_str, tier) == 0 &&
2688         strcmp (hevc_tier_level_mapping_table[i].level_str, level) == 0)
2689       return hevc_tier_level_mapping_table[i].id;
2690   }
2691 
2692   return -1;
2693 }
2694 
2695 static const struct
2696 {
2697   gint id;
2698   const gchar *str;
2699   const gchar *alt_str;
2700 } avc_profile_mapping_table[] = {
2701   {
2702   AVCProfileBaseline, "baseline", "constrained-baseline"}, {
2703   AVCProfileMain, "main", NULL}, {
2704   AVCProfileExtended, "extended", NULL}, {
2705   AVCProfileHigh, "high"}, {
2706   AVCProfileHigh10, "high-10", "high-10-intra"}, {
2707   AVCProfileHigh422, "high-4:2:2", "high-4:2:2-intra"}, {
2708   AVCProfileHigh444, "high-4:4:4", "high-4:4:4-intra"}
2709 };
2710 
2711 const gchar *
gst_amc_avc_profile_to_string(gint profile,const gchar ** alternative)2712 gst_amc_avc_profile_to_string (gint profile, const gchar ** alternative)
2713 {
2714   gint i;
2715 
2716   for (i = 0; i < G_N_ELEMENTS (avc_profile_mapping_table); i++) {
2717     if (avc_profile_mapping_table[i].id == profile) {
2718       *alternative = avc_profile_mapping_table[i].alt_str;
2719       return avc_profile_mapping_table[i].str;
2720     }
2721   }
2722 
2723   return NULL;
2724 }
2725 
2726 gint
gst_amc_avc_profile_from_string(const gchar * profile)2727 gst_amc_avc_profile_from_string (const gchar * profile)
2728 {
2729   gint i;
2730 
2731   g_return_val_if_fail (profile != NULL, -1);
2732 
2733   for (i = 0; i < G_N_ELEMENTS (avc_profile_mapping_table); i++) {
2734     if (strcmp (avc_profile_mapping_table[i].str, profile) == 0 ||
2735         (avc_profile_mapping_table[i].alt_str &&
2736             strcmp (avc_profile_mapping_table[i].alt_str, profile) == 0))
2737       return avc_profile_mapping_table[i].id;
2738   }
2739 
2740   return -1;
2741 }
2742 
2743 static const struct
2744 {
2745   gint id;
2746   const gchar *str;
2747 } avc_level_mapping_table[] = {
2748   {
2749   AVCLevel1, "1"}, {
2750   AVCLevel1b, "1b"}, {
2751   AVCLevel11, "1.1"}, {
2752   AVCLevel12, "1.2"}, {
2753   AVCLevel13, "1.3"}, {
2754   AVCLevel2, "2"}, {
2755   AVCLevel21, "2.1"}, {
2756   AVCLevel22, "2.2"}, {
2757   AVCLevel3, "3"}, {
2758   AVCLevel31, "3.1"}, {
2759   AVCLevel32, "3.2"}, {
2760   AVCLevel4, "4"}, {
2761   AVCLevel41, "4.1"}, {
2762   AVCLevel42, "4.2"}, {
2763   AVCLevel5, "5"}, {
2764   AVCLevel51, "5.1"}
2765 };
2766 
2767 const gchar *
gst_amc_avc_level_to_string(gint level)2768 gst_amc_avc_level_to_string (gint level)
2769 {
2770   gint i;
2771 
2772   for (i = 0; i < G_N_ELEMENTS (avc_level_mapping_table); i++) {
2773     if (avc_level_mapping_table[i].id == level)
2774       return avc_level_mapping_table[i].str;
2775   }
2776 
2777   return NULL;
2778 }
2779 
2780 gint
gst_amc_avc_level_from_string(const gchar * level)2781 gst_amc_avc_level_from_string (const gchar * level)
2782 {
2783   gint i;
2784 
2785   g_return_val_if_fail (level != NULL, -1);
2786 
2787   for (i = 0; i < G_N_ELEMENTS (avc_level_mapping_table); i++) {
2788     if (strcmp (avc_level_mapping_table[i].str, level) == 0)
2789       return avc_level_mapping_table[i].id;
2790   }
2791 
2792   return -1;
2793 }
2794 
2795 static const struct
2796 {
2797   gint id;
2798   gint gst_id;
2799 } h263_profile_mapping_table[] = {
2800   {
2801   H263ProfileBaseline, 0}, {
2802   H263ProfileH320Coding, 1}, {
2803   H263ProfileBackwardCompatible, 2}, {
2804   H263ProfileISWV2, 3}, {
2805   H263ProfileISWV3, 4}, {
2806   H263ProfileHighCompression, 5}, {
2807   H263ProfileInternet, 6}, {
2808   H263ProfileInterlace, 7}, {
2809   H263ProfileHighLatency, 8}
2810 };
2811 
2812 gint
gst_amc_h263_profile_to_gst_id(gint profile)2813 gst_amc_h263_profile_to_gst_id (gint profile)
2814 {
2815   gint i;
2816 
2817   for (i = 0; i < G_N_ELEMENTS (h263_profile_mapping_table); i++) {
2818     if (h263_profile_mapping_table[i].id == profile)
2819       return h263_profile_mapping_table[i].gst_id;
2820   }
2821 
2822   return -1;
2823 }
2824 
2825 gint
gst_amc_h263_profile_from_gst_id(gint profile)2826 gst_amc_h263_profile_from_gst_id (gint profile)
2827 {
2828   gint i;
2829 
2830   for (i = 0; i < G_N_ELEMENTS (h263_profile_mapping_table); i++) {
2831     if (h263_profile_mapping_table[i].gst_id == profile)
2832       return h263_profile_mapping_table[i].id;
2833   }
2834 
2835   return -1;
2836 }
2837 
2838 static const struct
2839 {
2840   gint id;
2841   gint gst_id;
2842 } h263_level_mapping_table[] = {
2843   {
2844   H263Level10, 10}, {
2845   H263Level20, 20}, {
2846   H263Level30, 30}, {
2847   H263Level40, 40}, {
2848   H263Level50, 50}, {
2849   H263Level60, 60}, {
2850   H263Level70, 70}
2851 };
2852 
2853 gint
gst_amc_h263_level_to_gst_id(gint level)2854 gst_amc_h263_level_to_gst_id (gint level)
2855 {
2856   gint i;
2857 
2858   for (i = 0; i < G_N_ELEMENTS (h263_level_mapping_table); i++) {
2859     if (h263_level_mapping_table[i].id == level)
2860       return h263_level_mapping_table[i].gst_id;
2861   }
2862 
2863   return -1;
2864 }
2865 
2866 gint
gst_amc_h263_level_from_gst_id(gint level)2867 gst_amc_h263_level_from_gst_id (gint level)
2868 {
2869   gint i;
2870 
2871   for (i = 0; i < G_N_ELEMENTS (h263_level_mapping_table); i++) {
2872     if (h263_level_mapping_table[i].gst_id == level)
2873       return h263_level_mapping_table[i].id;
2874   }
2875 
2876   return -1;
2877 }
2878 
2879 static const struct
2880 {
2881   gint id;
2882   const gchar *str;
2883 } mpeg4_profile_mapping_table[] = {
2884   {
2885   MPEG4ProfileSimple, "simple"}, {
2886   MPEG4ProfileSimpleScalable, "simple-scalable"}, {
2887   MPEG4ProfileCore, "core"}, {
2888   MPEG4ProfileMain, "main"}, {
2889   MPEG4ProfileNbit, "n-bit"}, {
2890   MPEG4ProfileScalableTexture, "scalable"}, {
2891   MPEG4ProfileSimpleFace, "simple-face"}, {
2892   MPEG4ProfileSimpleFBA, "simple-fba"}, {
2893   MPEG4ProfileBasicAnimated, "basic-animated-texture"}, {
2894   MPEG4ProfileHybrid, "hybrid"}, {
2895   MPEG4ProfileAdvancedRealTime, "advanced-real-time"}, {
2896   MPEG4ProfileCoreScalable, "core-scalable"}, {
2897   MPEG4ProfileAdvancedCoding, "advanced-coding-efficiency"}, {
2898   MPEG4ProfileAdvancedCore, "advanced-core"}, {
2899   MPEG4ProfileAdvancedScalable, "advanced-scalable-texture"}, {
2900   MPEG4ProfileAdvancedSimple, "advanced-simple"}
2901 };
2902 
2903 const gchar *
gst_amc_mpeg4_profile_to_string(gint profile)2904 gst_amc_mpeg4_profile_to_string (gint profile)
2905 {
2906   gint i;
2907 
2908   for (i = 0; i < G_N_ELEMENTS (mpeg4_profile_mapping_table); i++) {
2909     if (mpeg4_profile_mapping_table[i].id == profile)
2910       return mpeg4_profile_mapping_table[i].str;
2911   }
2912 
2913   return NULL;
2914 }
2915 
2916 gint
gst_amc_mpeg4_profile_from_string(const gchar * profile)2917 gst_amc_mpeg4_profile_from_string (const gchar * profile)
2918 {
2919   gint i;
2920 
2921   g_return_val_if_fail (profile != NULL, -1);
2922 
2923   for (i = 0; i < G_N_ELEMENTS (mpeg4_profile_mapping_table); i++) {
2924     if (strcmp (mpeg4_profile_mapping_table[i].str, profile) == 0)
2925       return mpeg4_profile_mapping_table[i].id;
2926   }
2927 
2928   return -1;
2929 }
2930 
2931 static const struct
2932 {
2933   gint id;
2934   const gchar *str;
2935 } mpeg4_level_mapping_table[] = {
2936   {
2937   MPEG4Level0, "0"}, {
2938   MPEG4Level0b, "0b"}, {
2939   MPEG4Level1, "1"}, {
2940   MPEG4Level2, "2"}, {
2941   MPEG4Level3, "3"}, {
2942   MPEG4Level4, "4"}, {
2943   MPEG4Level4a, "4a"}, {
2944 MPEG4Level5, "5"},};
2945 
2946 const gchar *
gst_amc_mpeg4_level_to_string(gint level)2947 gst_amc_mpeg4_level_to_string (gint level)
2948 {
2949   gint i;
2950 
2951   for (i = 0; i < G_N_ELEMENTS (mpeg4_level_mapping_table); i++) {
2952     if (mpeg4_level_mapping_table[i].id == level)
2953       return mpeg4_level_mapping_table[i].str;
2954   }
2955 
2956   return NULL;
2957 }
2958 
2959 gint
gst_amc_mpeg4_level_from_string(const gchar * level)2960 gst_amc_mpeg4_level_from_string (const gchar * level)
2961 {
2962   gint i;
2963 
2964   g_return_val_if_fail (level != NULL, -1);
2965 
2966   for (i = 0; i < G_N_ELEMENTS (mpeg4_level_mapping_table); i++) {
2967     if (strcmp (mpeg4_level_mapping_table[i].str, level) == 0)
2968       return mpeg4_level_mapping_table[i].id;
2969   }
2970 
2971   return -1;
2972 }
2973 
2974 static const struct
2975 {
2976   gint id;
2977   const gchar *str;
2978 } aac_profile_mapping_table[] = {
2979   {
2980   AACObjectMain, "main"}, {
2981   AACObjectLC, "lc"}, {
2982   AACObjectSSR, "ssr"}, {
2983   AACObjectLTP, "ltp"}
2984 };
2985 
2986 const gchar *
gst_amc_aac_profile_to_string(gint profile)2987 gst_amc_aac_profile_to_string (gint profile)
2988 {
2989   gint i;
2990 
2991   for (i = 0; i < G_N_ELEMENTS (aac_profile_mapping_table); i++) {
2992     if (aac_profile_mapping_table[i].id == profile)
2993       return aac_profile_mapping_table[i].str;
2994   }
2995 
2996   return NULL;
2997 }
2998 
2999 gint
gst_amc_aac_profile_from_string(const gchar * profile)3000 gst_amc_aac_profile_from_string (const gchar * profile)
3001 {
3002   gint i;
3003 
3004   g_return_val_if_fail (profile != NULL, -1);
3005 
3006   for (i = 0; i < G_N_ELEMENTS (aac_profile_mapping_table); i++) {
3007     if (strcmp (aac_profile_mapping_table[i].str, profile) == 0)
3008       return aac_profile_mapping_table[i].id;
3009   }
3010 
3011   return -1;
3012 }
3013 
3014 static const struct
3015 {
3016   guint32 mask;
3017   GstAudioChannelPosition pos;
3018 } channel_mapping_table[] = {
3019   {
3020   CHANNEL_OUT_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT}, {
3021   CHANNEL_OUT_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
3022   CHANNEL_OUT_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, {
3023   CHANNEL_OUT_LOW_FREQUENCY, GST_AUDIO_CHANNEL_POSITION_LFE1}, {
3024   CHANNEL_OUT_BACK_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT}, {
3025   CHANNEL_OUT_BACK_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
3026   CHANNEL_OUT_FRONT_LEFT_OF_CENTER,
3027         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER}, {
3028   CHANNEL_OUT_FRONT_RIGHT_OF_CENTER,
3029         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, {
3030   CHANNEL_OUT_BACK_CENTER, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
3031   CHANNEL_OUT_SIDE_LEFT, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT}, {
3032   CHANNEL_OUT_SIDE_RIGHT, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, {
3033   CHANNEL_OUT_TOP_CENTER, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
3034   CHANNEL_OUT_TOP_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
3035   CHANNEL_OUT_TOP_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
3036   CHANNEL_OUT_TOP_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
3037   CHANNEL_OUT_TOP_BACK_LEFT, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
3038   CHANNEL_OUT_TOP_BACK_CENTER, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
3039   CHANNEL_OUT_TOP_BACK_RIGHT, GST_AUDIO_CHANNEL_POSITION_INVALID}
3040 };
3041 
3042 gboolean
gst_amc_audio_channel_mask_to_positions(guint32 channel_mask,gint channels,GstAudioChannelPosition * pos)3043 gst_amc_audio_channel_mask_to_positions (guint32 channel_mask, gint channels,
3044     GstAudioChannelPosition * pos)
3045 {
3046   gint i, j;
3047 
3048   if (channel_mask == 0) {
3049     if (channels == 1) {
3050       pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
3051       return TRUE;
3052     }
3053     if (channels == 2) {
3054       pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
3055       pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
3056       return TRUE;
3057     }
3058 
3059     /* Now let the guesswork begin, these are the
3060      * AAC default channel assignments for these numbers
3061      * of channels */
3062     if (channels == 3) {
3063       channel_mask =
3064           CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
3065           CHANNEL_OUT_FRONT_CENTER;
3066     } else if (channels == 4) {
3067       channel_mask =
3068           CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
3069           CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER;
3070     } else if (channels == 5) {
3071       channel_mask =
3072           CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
3073           CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_LEFT |
3074           CHANNEL_OUT_BACK_RIGHT;
3075     } else if (channels == 6) {
3076       channel_mask =
3077           CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
3078           CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_LEFT |
3079           CHANNEL_OUT_BACK_RIGHT | CHANNEL_OUT_LOW_FREQUENCY;
3080     } else if (channels == 8) {
3081       channel_mask =
3082           CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
3083           CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_LEFT |
3084           CHANNEL_OUT_BACK_RIGHT | CHANNEL_OUT_LOW_FREQUENCY |
3085           CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER;
3086     }
3087   }
3088 
3089   for (i = 0, j = 0; i < G_N_ELEMENTS (channel_mapping_table); i++) {
3090     if ((channel_mask & channel_mapping_table[i].mask)) {
3091       pos[j++] = channel_mapping_table[i].pos;
3092       if (channel_mapping_table[i].pos == GST_AUDIO_CHANNEL_POSITION_INVALID) {
3093         memset (pos, 0, sizeof (GstAudioChannelPosition) * channels);
3094         GST_ERROR ("Unable to map channel mask 0x%08x",
3095             channel_mapping_table[i].mask);
3096         return FALSE;
3097       }
3098       if (j == channels)
3099         break;
3100     }
3101   }
3102 
3103   if (j != channels) {
3104     memset (pos, 0, sizeof (GstAudioChannelPosition) * channels);
3105     GST_ERROR ("Unable to map all channel positions in mask 0x%08x",
3106         channel_mask);
3107     return FALSE;
3108   }
3109 
3110   return TRUE;
3111 }
3112 
3113 guint32
gst_amc_audio_channel_mask_from_positions(GstAudioChannelPosition * positions,gint channels)3114 gst_amc_audio_channel_mask_from_positions (GstAudioChannelPosition * positions,
3115     gint channels)
3116 {
3117   gint i, j;
3118   guint32 channel_mask = 0;
3119 
3120   if (channels == 1 && !positions)
3121     return CHANNEL_OUT_FRONT_CENTER;
3122   if (channels == 2 && !positions)
3123     return CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT;
3124 
3125   for (i = 0; i < channels; i++) {
3126     if (positions[i] == GST_AUDIO_CHANNEL_POSITION_INVALID)
3127       return 0;
3128 
3129     for (j = 0; j < G_N_ELEMENTS (channel_mapping_table); j++) {
3130       if (channel_mapping_table[j].pos == positions[i]) {
3131         channel_mask |= channel_mapping_table[j].mask;
3132         break;
3133       }
3134     }
3135 
3136     if (j == G_N_ELEMENTS (channel_mapping_table)) {
3137       GST_ERROR ("Unable to map channel position %d", positions[i]);
3138       return 0;
3139     }
3140   }
3141 
3142   return channel_mask;
3143 }
3144 
3145 static gchar *
create_type_name(const gchar * parent_name,const gchar * codec_name)3146 create_type_name (const gchar * parent_name, const gchar * codec_name)
3147 {
3148   gchar *typified_name;
3149   gint i, k;
3150   gint parent_name_len = strlen (parent_name);
3151   gint codec_name_len = strlen (codec_name);
3152   gboolean upper = TRUE;
3153 
3154   typified_name = g_new0 (gchar, parent_name_len + 1 + strlen (codec_name) + 1);
3155   memcpy (typified_name, parent_name, parent_name_len);
3156   typified_name[parent_name_len] = '-';
3157 
3158   for (i = 0, k = 0; i < codec_name_len; i++) {
3159     if (g_ascii_isalnum (codec_name[i])) {
3160       if (upper)
3161         typified_name[parent_name_len + 1 + k++] =
3162             g_ascii_toupper (codec_name[i]);
3163       else
3164         typified_name[parent_name_len + 1 + k++] =
3165             g_ascii_tolower (codec_name[i]);
3166 
3167       upper = FALSE;
3168     } else {
3169       /* Skip all non-alnum chars and start a new upper case word */
3170       upper = TRUE;
3171     }
3172   }
3173 
3174   return typified_name;
3175 }
3176 
3177 static gchar *
create_element_name(gboolean video,gboolean encoder,const gchar * codec_name)3178 create_element_name (gboolean video, gboolean encoder, const gchar * codec_name)
3179 {
3180 #define PREFIX_LEN 10
3181   static const gchar *prefixes[] = {
3182     "amcviddec-",
3183     "amcauddec-",
3184     "amcvidenc-",
3185     "amcaudenc-"
3186   };
3187   gchar *element_name;
3188   gint i, k;
3189   gint codec_name_len = strlen (codec_name);
3190   const gchar *prefix;
3191 
3192   if (video && !encoder)
3193     prefix = prefixes[0];
3194   else if (!video && !encoder)
3195     prefix = prefixes[1];
3196   else if (video && encoder)
3197     prefix = prefixes[2];
3198   else
3199     prefix = prefixes[3];
3200 
3201   element_name = g_new0 (gchar, PREFIX_LEN + strlen (codec_name) + 1);
3202   memcpy (element_name, prefix, PREFIX_LEN);
3203 
3204   for (i = 0, k = 0; i < codec_name_len; i++) {
3205     if (g_ascii_isalnum (codec_name[i])) {
3206       element_name[PREFIX_LEN + k++] = g_ascii_tolower (codec_name[i]);
3207     }
3208     /* Skip all non-alnum chars */
3209   }
3210 
3211   return element_name;
3212 }
3213 
3214 #undef PREFIX_LEN
3215 
3216 static gboolean
register_codecs(GstPlugin * plugin)3217 register_codecs (GstPlugin * plugin)
3218 {
3219   gboolean ret = TRUE;
3220   GList *l;
3221 
3222   GST_DEBUG ("Registering plugins");
3223 
3224   for (l = codec_infos.head; l; l = l->next) {
3225     GstAmcCodecInfo *codec_info = l->data;
3226     gboolean is_audio = FALSE;
3227     gboolean is_video = FALSE;
3228     gint i;
3229     gint n_types;
3230 
3231     GST_DEBUG ("Registering codec '%s'", codec_info->name);
3232     for (i = 0; i < codec_info->n_supported_types; i++) {
3233       GstAmcCodecType *codec_type = &codec_info->supported_types[i];
3234 
3235       if (g_str_has_prefix (codec_type->mime, "audio/"))
3236         is_audio = TRUE;
3237       else if (g_str_has_prefix (codec_type->mime, "video/"))
3238         is_video = TRUE;
3239     }
3240 
3241     n_types = 0;
3242     if (is_audio)
3243       n_types++;
3244     if (is_video)
3245       n_types++;
3246 
3247     for (i = 0; i < n_types; i++) {
3248       GTypeQuery type_query;
3249       GTypeInfo type_info = { 0, };
3250       GType type, subtype;
3251       gchar *type_name, *element_name;
3252       guint rank;
3253 
3254       if (is_video) {
3255         if (codec_info->is_encoder)
3256           type = gst_amc_video_enc_get_type ();
3257         else
3258           type = gst_amc_video_dec_get_type ();
3259       } else if (is_audio && !codec_info->is_encoder) {
3260         type = gst_amc_audio_dec_get_type ();
3261       } else {
3262         GST_DEBUG ("Skipping unsupported codec type");
3263         continue;
3264       }
3265 
3266       g_type_query (type, &type_query);
3267       memset (&type_info, 0, sizeof (type_info));
3268       type_info.class_size = type_query.class_size;
3269       type_info.instance_size = type_query.instance_size;
3270       type_name = create_type_name (type_query.type_name, codec_info->name);
3271 
3272       if (g_type_from_name (type_name) != G_TYPE_INVALID) {
3273         GST_ERROR ("Type '%s' already exists for codec '%s'", type_name,
3274             codec_info->name);
3275         g_free (type_name);
3276         continue;
3277       }
3278 
3279       subtype = g_type_register_static (type, type_name, &type_info, 0);
3280       g_free (type_name);
3281 
3282       g_type_set_qdata (subtype, gst_amc_codec_info_quark, codec_info);
3283 
3284       element_name =
3285           create_element_name (is_video, codec_info->is_encoder,
3286           codec_info->name);
3287 
3288       /* Give the Google software codec a secondary rank,
3289        * everything else is likely a hardware codec, except
3290        * OMX.SEC.*.sw.dec (as seen in Galaxy S4).
3291        *
3292        * Also on some devices there are codecs that don't start
3293        * with OMX., while there are also some that do. And on
3294        * some of these devices the ones that don't start with
3295        * OMX. just crash during initialization while the others
3296        * work. To make things even more complicated other devices
3297        * have codecs with the same name that work and no alternatives.
3298        * So just give a lower rank to these non-OMX codecs and hope
3299        * that there's an alternative with a higher rank.
3300        */
3301       if (g_str_has_prefix (codec_info->name, "OMX.google") ||
3302           g_str_has_suffix (codec_info->name, ".sw.dec")) {
3303         /* For video we prefer hardware codecs, for audio we prefer software
3304          * codecs. Hardware codecs don't make much sense for audio */
3305         rank = is_video ? GST_RANK_SECONDARY : GST_RANK_PRIMARY;
3306       } else if (g_str_has_prefix (codec_info->name, "OMX.Exynos.")
3307           && !is_video) {
3308         /* OMX.Exynos. audio codecs are existing on some devices like the
3309          * Galaxy S5 mini, and cause random crashes (of the device,
3310          * not the app!) and generally misbehave. That specific device
3311          * has other codecs that work with a different name, but let's
3312          * just give them marginal rank in case there are devices that
3313          * have no other codecs and these are actually the only working
3314          * ones
3315          */
3316         rank = GST_RANK_MARGINAL;
3317       } else if (g_str_has_prefix (codec_info->name, "OMX.")) {
3318         rank = is_video ? GST_RANK_PRIMARY : GST_RANK_SECONDARY;
3319       } else {
3320         rank = GST_RANK_MARGINAL;
3321       }
3322 
3323       ret |= gst_element_register (plugin, element_name, rank, subtype);
3324       g_free (element_name);
3325 
3326       is_video = FALSE;
3327     }
3328   }
3329 
3330   return ret;
3331 }
3332 
3333 static gboolean
amc_init(GstPlugin * plugin)3334 amc_init (GstPlugin * plugin)
3335 {
3336   const gchar *ignore;
3337 
3338   gst_plugin_add_dependency_simple (plugin, NULL, "/etc", "media_codecs.xml",
3339       GST_PLUGIN_DEPENDENCY_FLAG_NONE);
3340 
3341   gst_amc_codec_info_quark = g_quark_from_static_string ("gst-amc-codec-info");
3342 
3343   if (!get_java_classes ())
3344     return FALSE;
3345 
3346   /* Set this to TRUE to allow registering decoders that have
3347    * any unknown color formats, or encoders that only have
3348    * unknown color formats
3349    */
3350   ignore = g_getenv ("GST_AMC_IGNORE_UNKNOWN_COLOR_FORMATS");
3351   if (ignore && strcmp (ignore, "yes") == 0)
3352     ignore_unknown_color_formats = TRUE;
3353 
3354   if (!scan_codecs (plugin))
3355     return FALSE;
3356 
3357   if (!register_codecs (plugin))
3358     return FALSE;
3359 
3360   return TRUE;
3361 }
3362 
3363 static gboolean
ahc_init(GstPlugin * plugin)3364 ahc_init (GstPlugin * plugin)
3365 {
3366   if (!gst_android_graphics_imageformat_init ()) {
3367     GST_ERROR ("Failed to init android image format");
3368     return FALSE;
3369   }
3370 
3371   if (!gst_android_hardware_camera_init ()) {
3372     gst_android_graphics_imageformat_deinit ();
3373     return FALSE;
3374   }
3375 
3376   if (!gst_element_register (plugin, "ahcsrc", GST_RANK_NONE, GST_TYPE_AHC_SRC)) {
3377     GST_ERROR ("Failed to register android camera source");
3378     gst_android_hardware_camera_deinit ();
3379     gst_android_graphics_imageformat_deinit ();
3380     return FALSE;
3381   }
3382 
3383   return TRUE;
3384 }
3385 
3386 static gboolean
ahs_init(GstPlugin * plugin)3387 ahs_init (GstPlugin * plugin)
3388 {
3389   if (!gst_android_hardware_sensor_init ())
3390     return FALSE;
3391 
3392   if (!gst_element_register (plugin, "ahssrc", GST_RANK_NONE, GST_TYPE_AHS_SRC)) {
3393     GST_ERROR ("Failed to register android sensor source");
3394     gst_android_hardware_sensor_deinit ();
3395     return FALSE;
3396   }
3397 
3398   return TRUE;
3399 }
3400 
3401 static gboolean
plugin_init(GstPlugin * plugin)3402 plugin_init (GstPlugin * plugin)
3403 {
3404   gboolean init_ok = FALSE;
3405 
3406   GST_DEBUG_CATEGORY_INIT (gst_amc_debug, "amc", 0, "android-media-codec");
3407 
3408   if (!gst_amc_jni_initialize ())
3409     return FALSE;
3410 
3411   if (amc_init (plugin))
3412     init_ok = TRUE;
3413 
3414   if (ahc_init (plugin))
3415     init_ok = TRUE;
3416 
3417   if (ahs_init (plugin))
3418     init_ok = TRUE;
3419 
3420   return init_ok;
3421 }
3422 
3423 void
gst_amc_codec_info_to_caps(const GstAmcCodecInfo * codec_info,GstCaps ** sink_caps,GstCaps ** src_caps)3424 gst_amc_codec_info_to_caps (const GstAmcCodecInfo * codec_info,
3425     GstCaps ** sink_caps, GstCaps ** src_caps)
3426 {
3427   GstCaps *raw_ret = NULL, *encoded_ret = NULL;
3428   gint i;
3429 
3430   if (codec_info->is_encoder) {
3431     if (sink_caps)
3432       *sink_caps = raw_ret = gst_caps_new_empty ();
3433 
3434     if (src_caps)
3435       *src_caps = encoded_ret = gst_caps_new_empty ();
3436   } else {
3437     if (sink_caps)
3438       *sink_caps = encoded_ret = gst_caps_new_empty ();
3439 
3440     if (src_caps)
3441       *src_caps = raw_ret = gst_caps_new_empty ();
3442   }
3443 
3444   for (i = 0; i < codec_info->n_supported_types; i++) {
3445     const GstAmcCodecType *type = &codec_info->supported_types[i];
3446     GstStructure *tmp, *tmp2, *tmp3;
3447 
3448     if (g_str_has_prefix (type->mime, "audio/")) {
3449       if (raw_ret) {
3450         tmp = gst_structure_new ("audio/x-raw",
3451             "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3452             "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3453             "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
3454             "layout", G_TYPE_STRING, "interleaved", NULL);
3455 
3456         raw_ret = gst_caps_merge_structure (raw_ret, tmp);
3457       }
3458 
3459       if (encoded_ret) {
3460         if (strcmp (type->mime, "audio/mpeg") == 0) {
3461           tmp = gst_structure_new ("audio/mpeg",
3462               "mpegversion", G_TYPE_INT, 1,
3463               "layer", G_TYPE_INT, 3,
3464               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3465               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3466               "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
3467           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3468         } else if (strcmp (type->mime, "audio/3gpp") == 0) {
3469           tmp = gst_structure_new ("audio/AMR",
3470               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3471               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
3472           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3473         } else if (strcmp (type->mime, "audio/amr-wb") == 0) {
3474           tmp = gst_structure_new ("audio/AMR-WB",
3475               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3476               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
3477           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3478         } else if (strcmp (type->mime, "audio/mp4a-latm") == 0) {
3479           gint j;
3480           gboolean have_profile = FALSE;
3481           GValue va = { 0, };
3482           GValue v = { 0, };
3483 
3484           g_value_init (&va, GST_TYPE_LIST);
3485           g_value_init (&v, G_TYPE_STRING);
3486           g_value_set_string (&v, "raw");
3487           gst_value_list_append_value (&va, &v);
3488           g_value_set_string (&v, "adts");
3489           gst_value_list_append_value (&va, &v);
3490           g_value_unset (&v);
3491 
3492           tmp = gst_structure_new ("audio/mpeg",
3493               "mpegversion", G_TYPE_INT, 4,
3494               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3495               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3496               "framed", G_TYPE_BOOLEAN, TRUE, NULL);
3497           gst_structure_set_value (tmp, "stream-format", &va);
3498           g_value_unset (&va);
3499 
3500           for (j = 0; j < type->n_profile_levels; j++) {
3501             const gchar *profile;
3502 
3503             profile =
3504                 gst_amc_aac_profile_to_string (type->profile_levels[j].profile);
3505 
3506             if (!profile) {
3507               GST_ERROR ("Unable to map AAC profile 0x%08x",
3508                   type->profile_levels[j].profile);
3509               continue;
3510             }
3511 
3512             tmp2 = gst_structure_copy (tmp);
3513             gst_structure_set (tmp2, "profile", G_TYPE_STRING, profile, NULL);
3514             encoded_ret = gst_caps_merge_structure (encoded_ret, tmp2);
3515 
3516             have_profile = TRUE;
3517           }
3518 
3519           if (!have_profile) {
3520             encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3521           } else {
3522             gst_structure_free (tmp);
3523           }
3524         } else if (strcmp (type->mime, "audio/g711-alaw") == 0) {
3525           tmp = gst_structure_new ("audio/x-alaw",
3526               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3527               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
3528           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3529         } else if (strcmp (type->mime, "audio/g711-mlaw") == 0) {
3530           tmp = gst_structure_new ("audio/x-mulaw",
3531               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3532               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
3533           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3534         } else if (strcmp (type->mime, "audio/vorbis") == 0) {
3535           tmp = gst_structure_new ("audio/x-vorbis",
3536               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3537               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
3538           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3539         } else if (strcmp (type->mime, "audio/opus") == 0) {
3540           tmp = gst_structure_new ("audio/x-opus",
3541               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3542               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
3543           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3544         } else if (strcmp (type->mime, "audio/flac") == 0) {
3545           tmp = gst_structure_new ("audio/x-flac",
3546               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3547               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3548               "framed", G_TYPE_BOOLEAN, TRUE, NULL);
3549           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3550         } else if (strcmp (type->mime, "audio/mpeg-L2") == 0) {
3551           tmp = gst_structure_new ("audio/mpeg",
3552               "mpegversion", G_TYPE_INT, 1,
3553               "layer", G_TYPE_INT, 2,
3554               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3555               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3556               "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
3557           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3558         } else {
3559           GST_WARNING ("Unsupported mimetype '%s'", type->mime);
3560         }
3561       }
3562     } else if (g_str_has_prefix (type->mime, "video/")) {
3563       if (raw_ret) {
3564         gint j;
3565 
3566         for (j = 0; j < type->n_color_formats; j++) {
3567           GstVideoFormat format;
3568 
3569           /* Skip here without a warning, this is special and handled
3570            * in the decoder when doing rendering to a surface */
3571           if (type->color_formats[j] == COLOR_FormatAndroidOpaque)
3572             continue;
3573 
3574           format =
3575               gst_amc_color_format_to_video_format (codec_info,
3576               type->mime, type->color_formats[j]);
3577           if (format == GST_VIDEO_FORMAT_UNKNOWN) {
3578             GST_WARNING ("Unknown color format 0x%08x for codec %s",
3579                 type->color_formats[j], type->mime);
3580             continue;
3581           }
3582 
3583           tmp = gst_structure_new ("video/x-raw",
3584               "format", G_TYPE_STRING, gst_video_format_to_string (format),
3585               "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3586               "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
3587               "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
3588 
3589           raw_ret = gst_caps_merge_structure (raw_ret, tmp);
3590         }
3591       }
3592 
3593       if (encoded_ret) {
3594         if (strcmp (type->mime, "video/mp4v-es") == 0) {
3595           gint j;
3596           gboolean have_profile_level = FALSE;
3597 
3598           tmp = gst_structure_new ("video/mpeg",
3599               "width", GST_TYPE_INT_RANGE, 16, 4096,
3600               "height", GST_TYPE_INT_RANGE, 16, 4096,
3601               "framerate", GST_TYPE_FRACTION_RANGE,
3602               0, 1, G_MAXINT, 1,
3603               "mpegversion", G_TYPE_INT, 4,
3604               "systemstream", G_TYPE_BOOLEAN, FALSE,
3605               "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
3606 
3607           if (type->n_profile_levels) {
3608             for (j = type->n_profile_levels - 1; j >= 0; j--) {
3609               const gchar *profile;
3610 
3611               profile =
3612                   gst_amc_mpeg4_profile_to_string (type->profile_levels[j].
3613                   profile);
3614               if (!profile) {
3615                 GST_ERROR ("Unable to map MPEG4 profile 0x%08x",
3616                     type->profile_levels[j].profile);
3617                 continue;
3618               }
3619 
3620               tmp2 = gst_structure_copy (tmp);
3621               gst_structure_set (tmp2, "profile", G_TYPE_STRING, profile, NULL);
3622 
3623               /* Don't put the level restrictions on the sinkpad caps for decoders,
3624                * see 2b94641a4 */
3625               if (codec_info->is_encoder) {
3626                 const gchar *level;
3627                 gint k;
3628                 GValue va = { 0, };
3629                 GValue v = { 0, };
3630 
3631                 g_value_init (&va, GST_TYPE_LIST);
3632                 g_value_init (&v, G_TYPE_STRING);
3633 
3634                 for (k = 1; k <= type->profile_levels[j].level && k != 0;
3635                     k <<= 1) {
3636                   level = gst_amc_mpeg4_level_to_string (k);
3637                   if (!level)
3638                     continue;
3639 
3640                   g_value_set_string (&v, level);
3641                   gst_value_list_append_value (&va, &v);
3642                   g_value_reset (&v);
3643                 }
3644 
3645                 gst_structure_set_value (tmp2, "level", &va);
3646                 g_value_unset (&va);
3647                 g_value_unset (&v);
3648               }
3649 
3650               encoded_ret = gst_caps_merge_structure (encoded_ret, tmp2);
3651               have_profile_level = TRUE;
3652             }
3653           }
3654 
3655           if (!have_profile_level) {
3656             encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3657           } else {
3658             gst_structure_free (tmp);
3659           }
3660 
3661           tmp = gst_structure_new ("video/x-divx",
3662               "width", GST_TYPE_INT_RANGE, 16, 4096,
3663               "height", GST_TYPE_INT_RANGE, 16, 4096,
3664               "framerate", GST_TYPE_FRACTION_RANGE,
3665               0, 1, G_MAXINT, 1,
3666               "divxversion", GST_TYPE_INT_RANGE, 3, 5,
3667               "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
3668           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3669         } else if (strcmp (type->mime, "video/3gpp") == 0) {
3670           gint j;
3671           gboolean have_profile_level = FALSE;
3672 
3673           tmp = gst_structure_new ("video/x-h263",
3674               "width", GST_TYPE_INT_RANGE, 16, 4096,
3675               "height", GST_TYPE_INT_RANGE, 16, 4096,
3676               "framerate", GST_TYPE_FRACTION_RANGE,
3677               0, 1, G_MAXINT, 1,
3678               "parsed", G_TYPE_BOOLEAN, TRUE,
3679               "variant", G_TYPE_STRING, "itu", NULL);
3680 
3681           if (type->n_profile_levels) {
3682             for (j = type->n_profile_levels - 1; j >= 0; j--) {
3683               gint profile;
3684 
3685               profile =
3686                   gst_amc_h263_profile_to_gst_id (type->profile_levels[j].
3687                   profile);
3688 
3689               if (profile == -1) {
3690                 GST_ERROR ("Unable to map h263 profile 0x%08x",
3691                     type->profile_levels[j].profile);
3692                 continue;
3693               }
3694 
3695               tmp2 = gst_structure_copy (tmp);
3696               gst_structure_set (tmp2, "profile", G_TYPE_UINT, profile, NULL);
3697 
3698               if (codec_info->is_encoder) {
3699                 gint k;
3700                 gint level;
3701                 GValue va = { 0, };
3702                 GValue v = { 0, };
3703 
3704                 g_value_init (&va, GST_TYPE_LIST);
3705                 g_value_init (&v, G_TYPE_UINT);
3706 
3707                 for (k = 1; k <= type->profile_levels[j].level && k != 0;
3708                     k <<= 1) {
3709                   level = gst_amc_h263_level_to_gst_id (k);
3710                   if (level == -1)
3711                     continue;
3712 
3713                   g_value_set_uint (&v, level);
3714                   gst_value_list_append_value (&va, &v);
3715                   g_value_reset (&v);
3716                 }
3717 
3718                 gst_structure_set_value (tmp2, "level", &va);
3719                 g_value_unset (&va);
3720                 g_value_unset (&v);
3721               }
3722 
3723               encoded_ret = gst_caps_merge_structure (encoded_ret, tmp2);
3724               have_profile_level = TRUE;
3725             }
3726           }
3727 
3728           if (!have_profile_level) {
3729             encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3730           } else {
3731             gst_structure_free (tmp);
3732           }
3733         } else if (strcmp (type->mime, "video/avc") == 0) {
3734           gint j;
3735           gboolean have_profile_level = FALSE;
3736 
3737           tmp = gst_structure_new ("video/x-h264",
3738               "width", GST_TYPE_INT_RANGE, 16, 4096,
3739               "height", GST_TYPE_INT_RANGE, 16, 4096,
3740               "framerate", GST_TYPE_FRACTION_RANGE,
3741               0, 1, G_MAXINT, 1,
3742               "parsed", G_TYPE_BOOLEAN, TRUE,
3743               "stream-format", G_TYPE_STRING, "byte-stream",
3744               "alignment", G_TYPE_STRING, "au", NULL);
3745 
3746           if (type->n_profile_levels) {
3747             for (j = type->n_profile_levels - 1; j >= 0; j--) {
3748               const gchar *profile, *alternative = NULL;
3749 
3750               profile =
3751                   gst_amc_avc_profile_to_string (type->profile_levels[j].
3752                   profile, &alternative);
3753 
3754               if (!profile) {
3755                 GST_ERROR ("Unable to map H264 profile 0x%08x",
3756                     type->profile_levels[j].profile);
3757                 continue;
3758               }
3759 
3760               tmp2 = gst_structure_copy (tmp);
3761               gst_structure_set (tmp2, "profile", G_TYPE_STRING, profile, NULL);
3762 
3763               if (alternative) {
3764                 tmp3 = gst_structure_copy (tmp);
3765                 gst_structure_set (tmp3, "profile", G_TYPE_STRING, alternative,
3766                     NULL);
3767               } else
3768                 tmp3 = NULL;
3769 
3770               if (codec_info->is_encoder) {
3771                 const gchar *level;
3772                 gint k;
3773                 GValue va = { 0, };
3774                 GValue v = { 0, };
3775 
3776                 g_value_init (&va, GST_TYPE_LIST);
3777                 g_value_init (&v, G_TYPE_STRING);
3778                 for (k = 1; k <= type->profile_levels[j].level && k != 0;
3779                     k <<= 1) {
3780                   level = gst_amc_avc_level_to_string (k);
3781                   if (!level)
3782                     continue;
3783 
3784                   g_value_set_string (&v, level);
3785                   gst_value_list_append_value (&va, &v);
3786                   g_value_reset (&v);
3787                 }
3788 
3789                 gst_structure_set_value (tmp2, "level", &va);
3790                 if (tmp3)
3791                   gst_structure_set_value (tmp3, "level", &va);
3792 
3793                 g_value_unset (&va);
3794                 g_value_unset (&v);
3795               }
3796 
3797               encoded_ret = gst_caps_merge_structure (encoded_ret, tmp2);
3798               if (tmp3)
3799                 encoded_ret = gst_caps_merge_structure (encoded_ret, tmp3);
3800               have_profile_level = TRUE;
3801             }
3802           }
3803 
3804           if (!have_profile_level) {
3805             encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3806           } else {
3807             gst_structure_free (tmp);
3808           }
3809         } else if (strcmp (type->mime, "video/hevc") == 0) {
3810           gint j;
3811           gboolean have_profile_level = FALSE;
3812 
3813           tmp = gst_structure_new ("video/x-h265",
3814               "width", GST_TYPE_INT_RANGE, 16, 4096,
3815               "height", GST_TYPE_INT_RANGE, 16, 4096,
3816               "framerate", GST_TYPE_FRACTION_RANGE,
3817               0, 1, G_MAXINT, 1,
3818               "parsed", G_TYPE_BOOLEAN, TRUE,
3819               "stream-format", G_TYPE_STRING, "byte-stream",
3820               "alignment", G_TYPE_STRING, "au", NULL);
3821 
3822           if (type->n_profile_levels) {
3823             for (j = type->n_profile_levels - 1; j >= 0; j--) {
3824               const gchar *profile;
3825 
3826               profile =
3827                   gst_amc_hevc_profile_to_string (type->profile_levels[j].
3828                   profile);
3829 
3830               if (!profile) {
3831                 GST_ERROR ("Unable to map H265 profile 0x%08x",
3832                     type->profile_levels[j].profile);
3833                 continue;
3834               }
3835 
3836               tmp2 = gst_structure_copy (tmp);
3837               gst_structure_set (tmp2, "profile", G_TYPE_STRING, profile, NULL);
3838 
3839               /* FIXME: Implement tier/level support here */
3840 #if 0
3841               if (codec_info->is_encoder) {
3842                 const gchar *level, *tier;
3843                 gint k;
3844                 GValue va = { 0, };
3845                 GValue v = { 0, };
3846 
3847                 g_value_init (&va, GST_TYPE_LIST);
3848                 g_value_init (&v, G_TYPE_STRING);
3849                 for (k = 1; k <= type->profile_levels[j].level && k != 0;
3850                     k <<= 1) {
3851                   level = gst_amc_hevc_tier_level_to_string (k, &tier);
3852                   if (!level)
3853                     continue;
3854 
3855                   g_value_set_string (&v, level);
3856                   gst_value_list_append_value (&va, &v);
3857                   g_value_reset (&v);
3858                 }
3859 
3860                 gst_structure_set_value (tmp2, "level", &va);
3861 
3862                 g_value_unset (&va);
3863                 g_value_unset (&v);
3864               }
3865 #endif
3866 
3867               encoded_ret = gst_caps_merge_structure (encoded_ret, tmp2);
3868               have_profile_level = TRUE;
3869             }
3870           }
3871 
3872           if (!have_profile_level) {
3873             encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3874           } else {
3875             gst_structure_free (tmp);
3876           }
3877         } else if (strcmp (type->mime, "video/x-vnd.on2.vp8") == 0) {
3878           tmp = gst_structure_new ("video/x-vp8",
3879               "width", GST_TYPE_INT_RANGE, 16, 4096,
3880               "height", GST_TYPE_INT_RANGE, 16, 4096,
3881               "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
3882 
3883           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3884         } else if (strcmp (type->mime, "video/x-vnd.on2.vp9") == 0) {
3885           tmp = gst_structure_new ("video/x-vp9",
3886               "width", GST_TYPE_INT_RANGE, 16, 4096,
3887               "height", GST_TYPE_INT_RANGE, 16, 4096,
3888               "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
3889 
3890           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3891         } else if (strcmp (type->mime, "video/mpeg2") == 0) {
3892           tmp = gst_structure_new ("video/mpeg",
3893               "width", GST_TYPE_INT_RANGE, 16, 4096,
3894               "height", GST_TYPE_INT_RANGE, 16, 4096,
3895               "framerate", GST_TYPE_FRACTION_RANGE,
3896               0, 1, G_MAXINT, 1,
3897               "mpegversion", GST_TYPE_INT_RANGE, 1, 2,
3898               "systemstream", G_TYPE_BOOLEAN, FALSE,
3899               "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
3900 
3901           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
3902         } else {
3903           GST_WARNING ("Unsupported mimetype '%s'", type->mime);
3904         }
3905       }
3906     }
3907   }
3908 
3909   GST_DEBUG ("Returning caps for '%s':", codec_info->name);
3910   GST_DEBUG ("  raw caps: %" GST_PTR_FORMAT, raw_ret);
3911   GST_DEBUG ("  encoded caps: %" GST_PTR_FORMAT, encoded_ret);
3912 }
3913 
3914 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
3915     GST_VERSION_MINOR,
3916     androidmedia,
3917     "Android Media plugin",
3918     plugin_init,
3919     PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
3920