• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef HAVE_JNI_H
33 #include "gstahcsrc.h"
34 #include "gstahssrc.h"
35 #include "gstjniutils.h"
36 #endif
37 
38 #include "gstamc.h"
39 #include "gstamc-constants.h"
40 
41 #include "gstamcvideodec.h"
42 #include "gstamcvideoenc.h"
43 #include "gstamcaudiodec.h"
44 
45 #include <gst/gst.h>
46 #include <gst/video/video.h>
47 #include <gst/audio/audio.h>
48 #include <string.h>
49 
50 GST_DEBUG_CATEGORY (gst_amc_debug);
51 #define GST_CAT_DEFAULT gst_amc_debug
52 
53 GQuark gst_amc_codec_info_quark = 0;
54 
55 static GQueue codec_infos = G_QUEUE_INIT;
56 #ifdef GST_AMC_IGNORE_UNKNOWN_COLOR_FORMATS
57 static gboolean ignore_unknown_color_formats = TRUE;
58 #else
59 static gboolean ignore_unknown_color_formats = FALSE;
60 #endif
61 
62 static gboolean accepted_color_formats (GstAmcCodecType * type,
63     gboolean is_encoder);
64 
65 static gboolean
scan_codecs(GstPlugin * plugin)66 scan_codecs (GstPlugin * plugin)
67 {
68   gboolean ret = TRUE;
69   gint codec_count, i;
70   const GstStructure *cache_data;
71   GError *error = NULL;
72 
73   GST_DEBUG ("Scanning codecs");
74 
75   if ((cache_data = gst_plugin_get_cache_data (plugin))) {
76     const GValue *arr = gst_structure_get_value (cache_data, "codecs");
77     guint i, n;
78 
79     GST_DEBUG ("Getting codecs from cache");
80     n = gst_value_array_get_size (arr);
81     for (i = 0; i < n; i++) {
82       const GValue *cv = gst_value_array_get_value (arr, i);
83       const GstStructure *cs = gst_value_get_structure (cv);
84       const gchar *name;
85       gboolean is_encoder;
86       const GValue *starr;
87       guint j, n2;
88       GstAmcCodecInfo *gst_codec_info;
89 
90       gst_codec_info = g_new0 (GstAmcCodecInfo, 1);
91 
92       name = gst_structure_get_string (cs, "name");
93       gst_structure_get_boolean (cs, "is-encoder", &is_encoder);
94       gst_codec_info->name = g_strdup (name);
95       gst_codec_info->is_encoder = is_encoder;
96 
97       starr = gst_structure_get_value (cs, "supported-types");
98       n2 = gst_value_array_get_size (starr);
99 
100       gst_codec_info->n_supported_types = n2;
101       gst_codec_info->supported_types = g_new0 (GstAmcCodecType, n2);
102 
103       for (j = 0; j < n2; j++) {
104         const GValue *stv = gst_value_array_get_value (starr, j);
105         const GstStructure *sts = gst_value_get_structure (stv);
106         const gchar *mime;
107         const GValue *cfarr;
108         const GValue *plarr;
109         guint k, n3;
110         GstAmcCodecType *gst_codec_type = &gst_codec_info->supported_types[j];
111 
112         mime = gst_structure_get_string (sts, "mime");
113         gst_codec_type->mime = g_strdup (mime);
114 
115         cfarr = gst_structure_get_value (sts, "color-formats");
116         n3 = gst_value_array_get_size (cfarr);
117 
118         gst_codec_type->n_color_formats = n3;
119         gst_codec_type->color_formats = g_new0 (gint, n3);
120 
121         for (k = 0; k < n3; k++) {
122           const GValue *cfv = gst_value_array_get_value (cfarr, k);
123           gint cf = g_value_get_int (cfv);
124 
125           gst_codec_type->color_formats[k] = cf;
126         }
127 
128         plarr = gst_structure_get_value (sts, "profile-levels");
129         n3 = gst_value_array_get_size (plarr);
130 
131         gst_codec_type->n_profile_levels = n3;
132         gst_codec_type->profile_levels =
133             g_malloc0 (sizeof (gst_codec_type->profile_levels[0]) * n3);
134 
135         for (k = 0; k < n3; k++) {
136           const GValue *plv = gst_value_array_get_value (plarr, k);
137           const GValue *p, *l;
138 
139           p = gst_value_array_get_value (plv, 0);
140           l = gst_value_array_get_value (plv, 1);
141           gst_codec_type->profile_levels[k].profile = g_value_get_int (p);
142           gst_codec_type->profile_levels[k].level = g_value_get_int (l);
143         }
144       }
145 
146       g_queue_push_tail (&codec_infos, gst_codec_info);
147     }
148 
149     return TRUE;
150   }
151 
152   if (!gst_amc_codeclist_get_count (&codec_count, &error)) {
153     GST_ERROR ("Failed to get number of available codecs");
154     ret = FALSE;
155     goto done;
156   }
157 
158   GST_INFO ("Found %d available codecs", codec_count);
159 
160   for (i = 0; i < codec_count; i++) {
161     GstAmcCodecInfo *gst_codec_info;
162     GstAmcCodecInfoHandle *codec_info = NULL;
163     gchar *name_str = NULL;
164     gboolean is_encoder;
165     gchar **supported_types = NULL;
166     gsize n_supported_types;
167     gsize j;
168     gboolean valid_codec = TRUE;
169 
170     gst_codec_info = g_new0 (GstAmcCodecInfo, 1);
171 
172     codec_info = gst_amc_codeclist_get_codec_info_at (i, &error);
173     if (!codec_info) {
174       GST_ERROR ("Failed to get codec info %d", i);
175       valid_codec = FALSE;
176       goto next_codec;
177     }
178 
179     name_str = gst_amc_codec_info_handle_get_name (codec_info, &error);
180     if (!name_str) {
181       GST_ERROR ("Failed to get codec name");
182       valid_codec = FALSE;
183       goto next_codec;
184     }
185 
186     GST_INFO ("Checking codec '%s'", name_str);
187 
188     /* Compatibility codec names */
189     if (strcmp (name_str, "AACEncoder") == 0 ||
190         strcmp (name_str, "OMX.google.raw.decoder") == 0) {
191       GST_INFO ("Skipping compatibility codec '%s'", name_str);
192       valid_codec = FALSE;
193       goto next_codec;
194     }
195 
196     if (g_str_has_suffix (name_str, ".secure")) {
197       GST_INFO ("Skipping DRM codec '%s'", name_str);
198       valid_codec = FALSE;
199       goto next_codec;
200     }
201 #ifdef HAVE_JNI_H
202     /* FIXME: Non-Google codecs usually just don't work and hang forever
203      * or crash when not used from a process that started the Java
204      * VM via the non-public AndroidRuntime class. Can we somehow
205      * initialize all this?
206      */
207     if (gst_amc_jni_is_vm_started () &&
208         !g_str_has_prefix (name_str, "OMX.google.")) {
209       GST_INFO ("Skipping non-Google codec '%s' in standalone mode", name_str);
210       valid_codec = FALSE;
211       goto next_codec;
212     }
213 #endif
214 
215     if (g_str_has_prefix (name_str, "OMX.ARICENT.")) {
216       GST_INFO ("Skipping possible broken codec '%s'", name_str);
217       valid_codec = FALSE;
218       goto next_codec;
219     }
220 
221     /* FIXME:
222      *   - Vorbis: Generates clicks for multi-channel streams
223      *   - *Law: Generates output with too low frequencies
224      */
225     if (strcmp (name_str, "OMX.google.vorbis.decoder") == 0 ||
226         strcmp (name_str, "OMX.google.g711.alaw.decoder") == 0 ||
227         strcmp (name_str, "OMX.google.g711.mlaw.decoder") == 0) {
228       GST_INFO ("Skipping known broken codec '%s'", name_str);
229       valid_codec = FALSE;
230       goto next_codec;
231     }
232     gst_codec_info->name = g_strdup (name_str);
233 
234     if (!gst_amc_codec_info_handle_is_encoder (codec_info, &is_encoder, &error)) {
235       GST_ERROR ("Failed to detect if codec is an encoder");
236       valid_codec = FALSE;
237       goto next_codec;
238     }
239     gst_codec_info->is_encoder = is_encoder;
240     gst_codec_info->gl_output_only = FALSE;
241 
242     supported_types =
243         gst_amc_codec_info_handle_get_supported_types (codec_info,
244         &n_supported_types, &error);
245     if (!supported_types) {
246       GST_ERROR ("Failed to get supported types");
247       valid_codec = FALSE;
248       goto next_codec;
249     }
250 
251     GST_INFO ("Codec '%s' has %" G_GSIZE_FORMAT " supported types", name_str,
252         n_supported_types);
253 
254     gst_codec_info->supported_types =
255         g_new0 (GstAmcCodecType, n_supported_types);
256     gst_codec_info->n_supported_types = n_supported_types;
257 
258     if (n_supported_types == 0) {
259       valid_codec = FALSE;
260       GST_ERROR ("Codec has no supported types");
261       goto next_codec;
262     }
263 
264     for (j = 0; j < n_supported_types; j++) {
265       GstAmcCodecType *gst_codec_type;
266       const gchar *supported_type_str;
267       GstAmcCodecCapabilitiesHandle *capabilities = NULL;
268       gint k;
269 
270       gst_codec_type = &gst_codec_info->supported_types[j];
271       supported_type_str = supported_types[j];
272 
273       GST_INFO ("Supported type '%s'", supported_type_str);
274       gst_codec_type->mime = g_strdup (supported_type_str);
275 
276       capabilities =
277           gst_amc_codec_info_handle_get_capabilities_for_type (codec_info,
278           supported_type_str, &error);
279       if (!capabilities) {
280         GST_ERROR ("Failed to get capabilities for supported type");
281         valid_codec = FALSE;
282         goto next_supported_type;
283       }
284 
285       if (g_str_has_prefix (gst_codec_type->mime, "video/")) {
286         gst_codec_type->color_formats =
287             gst_amc_codec_capabilities_handle_get_color_formats (capabilities,
288             &gst_codec_type->n_color_formats, &error);
289         if (!gst_codec_type->color_formats) {
290           GST_ERROR ("Failed to get color format elements");
291           valid_codec = FALSE;
292           goto next_supported_type;
293         }
294 
295         for (k = 0; k < gst_codec_type->n_color_formats; k++) {
296           GST_INFO ("Color format %d: 0x%x", k,
297               gst_codec_type->color_formats[k]);
298         }
299 
300         if (!gst_codec_type->n_color_formats) {
301           GST_ERROR ("No supported color formats for video codec");
302           valid_codec = FALSE;
303           goto next_supported_type;
304         }
305 
306         if (!accepted_color_formats (gst_codec_type, is_encoder)) {
307           if (!ignore_unknown_color_formats) {
308             gst_codec_info->gl_output_only = TRUE;
309             GST_WARNING
310                 ("%s %s has unknown color formats, only direct rendering will be supported",
311                 gst_codec_type->mime, is_encoder ? "encoder" : "decoder");
312           }
313         }
314       }
315 
316       gst_codec_type->profile_levels =
317           gst_amc_codec_capabilities_handle_get_profile_levels (capabilities,
318           &gst_codec_type->n_profile_levels, &error);
319       if (error) {
320         GST_ERROR ("Failed to get profile/levels: %s", error->message);
321         valid_codec = FALSE;
322         goto next_supported_type;
323       }
324 
325       for (k = 0; k < gst_codec_type->n_profile_levels; k++) {
326         GST_INFO ("Level %d: 0x%08x", k,
327             gst_codec_type->profile_levels[k].level);
328         GST_INFO ("Profile %d: 0x%08x", k,
329             gst_codec_type->profile_levels[k].profile);
330       }
331 
332     next_supported_type:
333       if (capabilities)
334         gst_amc_codec_capabilities_handle_free (capabilities);
335       capabilities = NULL;
336       g_clear_error (&error);
337       if (!valid_codec)
338         break;
339     }
340 
341     /* We need at least a valid supported type */
342     if (valid_codec) {
343       GList *l;
344 
345       for (l = codec_infos.head; l; l = l->next) {
346         GstAmcCodecInfo *tmp = l->data;
347 
348         if (strcmp (tmp->name, gst_codec_info->name) == 0
349             && ! !tmp->is_encoder == ! !gst_codec_info->is_encoder) {
350           gint m = tmp->n_supported_types, n;
351 
352           GST_LOG ("Successfully scanned codec '%s', appending to existing",
353               name_str);
354 
355           tmp->gl_output_only |= gst_codec_info->gl_output_only;
356           tmp->n_supported_types += gst_codec_info->n_supported_types;
357           tmp->supported_types =
358               g_realloc (tmp->supported_types,
359               tmp->n_supported_types * sizeof (GstAmcCodecType));
360 
361           for (n = 0; n < gst_codec_info->n_supported_types; n++, m++) {
362             tmp->supported_types[m] = gst_codec_info->supported_types[n];
363           }
364           g_free (gst_codec_info->supported_types);
365           g_free (gst_codec_info->name);
366           g_free (gst_codec_info);
367           gst_codec_info = NULL;
368 
369           break;
370         }
371       }
372 
373       /* Found no existing codec with this name */
374       if (l == NULL) {
375         GST_LOG ("Successfully scanned codec '%s'", name_str);
376         g_queue_push_tail (&codec_infos, gst_codec_info);
377         gst_codec_info = NULL;
378       }
379     }
380 
381     /* Clean up of all local references we got */
382   next_codec:
383     if (name_str)
384       g_free (name_str);
385     name_str = NULL;
386     if (supported_types)
387       g_strfreev (supported_types);
388     supported_types = NULL;
389     if (codec_info)
390       gst_amc_codec_info_handle_free (codec_info);
391     codec_info = NULL;
392     if (gst_codec_info) {
393       gint j;
394 
395       for (j = 0; j < gst_codec_info->n_supported_types; j++) {
396         GstAmcCodecType *gst_codec_type = &gst_codec_info->supported_types[j];
397 
398         g_free (gst_codec_type->mime);
399         g_free (gst_codec_type->color_formats);
400         g_free (gst_codec_type->profile_levels);
401       }
402       g_free (gst_codec_info->supported_types);
403       g_free (gst_codec_info->name);
404       g_free (gst_codec_info);
405     }
406     gst_codec_info = NULL;
407     valid_codec = TRUE;
408     g_clear_error (&error);
409   }
410 
411   ret = codec_infos.length != 0;
412 
413   /* If successful we store a cache of the codec information in
414    * the registry. Otherwise we would always load all codecs during
415    * plugin initialization which can take quite some time (because
416    * of hardware) and also loads lots of shared libraries (which
417    * number is limited by 64 in Android).
418    */
419   if (ret) {
420     GstStructure *new_cache_data = gst_structure_new_empty ("gst-amc-cache");
421     GList *l;
422     GValue arr = { 0, };
423 
424     g_value_init (&arr, GST_TYPE_ARRAY);
425 
426     for (l = codec_infos.head; l; l = l->next) {
427       GstAmcCodecInfo *gst_codec_info = l->data;
428       GValue cv = { 0, };
429       GstStructure *cs = gst_structure_new_empty ("gst-amc-codec");
430       GValue starr = { 0, };
431       gint i;
432 
433       gst_structure_set (cs, "name", G_TYPE_STRING, gst_codec_info->name,
434           "is-encoder", G_TYPE_BOOLEAN, gst_codec_info->is_encoder, NULL);
435 
436       g_value_init (&starr, GST_TYPE_ARRAY);
437 
438       for (i = 0; i < gst_codec_info->n_supported_types; i++) {
439         GstAmcCodecType *gst_codec_type = &gst_codec_info->supported_types[i];
440         GstStructure *sts = gst_structure_new_empty ("gst-amc-supported-type");
441         GValue stv = { 0, };
442         GValue tmparr = { 0, };
443         gint j;
444 
445         gst_structure_set (sts, "mime", G_TYPE_STRING, gst_codec_type->mime,
446             NULL);
447 
448         g_value_init (&tmparr, GST_TYPE_ARRAY);
449         for (j = 0; j < gst_codec_type->n_color_formats; j++) {
450           GValue tmp = { 0, };
451 
452           g_value_init (&tmp, G_TYPE_INT);
453           g_value_set_int (&tmp, gst_codec_type->color_formats[j]);
454           gst_value_array_append_value (&tmparr, &tmp);
455           g_value_unset (&tmp);
456         }
457         gst_structure_set_value (sts, "color-formats", &tmparr);
458         g_value_unset (&tmparr);
459 
460         g_value_init (&tmparr, GST_TYPE_ARRAY);
461         for (j = 0; j < gst_codec_type->n_profile_levels; j++) {
462           GValue tmparr2 = { 0, };
463           GValue tmp = { 0, };
464 
465           g_value_init (&tmparr2, GST_TYPE_ARRAY);
466           g_value_init (&tmp, G_TYPE_INT);
467           g_value_set_int (&tmp, gst_codec_type->profile_levels[j].profile);
468           gst_value_array_append_value (&tmparr2, &tmp);
469           g_value_set_int (&tmp, gst_codec_type->profile_levels[j].level);
470           gst_value_array_append_value (&tmparr2, &tmp);
471           gst_value_array_append_value (&tmparr, &tmparr2);
472           g_value_unset (&tmp);
473           g_value_unset (&tmparr2);
474         }
475         gst_structure_set_value (sts, "profile-levels", &tmparr);
476 
477         g_value_init (&stv, GST_TYPE_STRUCTURE);
478         gst_value_set_structure (&stv, sts);
479         gst_value_array_append_value (&starr, &stv);
480         g_value_unset (&tmparr);
481         gst_structure_free (sts);
482       }
483 
484       gst_structure_set_value (cs, "supported-types", &starr);
485       g_value_unset (&starr);
486 
487       g_value_init (&cv, GST_TYPE_STRUCTURE);
488       gst_value_set_structure (&cv, cs);
489       gst_value_array_append_value (&arr, &cv);
490       g_value_unset (&cv);
491       gst_structure_free (cs);
492     }
493 
494     gst_structure_set_value (new_cache_data, "codecs", &arr);
495     g_value_unset (&arr);
496 
497     gst_plugin_set_cache_data (plugin, new_cache_data);
498   }
499 
500 done:
501   g_clear_error (&error);
502 
503   return ret;
504 }
505 
506 static const struct
507 {
508   gint color_format;
509   GstVideoFormat video_format;
510 } color_format_mapping_table[] = {
511   {
512   COLOR_FormatYUV420Planar, GST_VIDEO_FORMAT_I420}, {
513   COLOR_FormatYUV420Flexible, GST_VIDEO_FORMAT_I420}, {
514   COLOR_FormatYUV420SemiPlanar, GST_VIDEO_FORMAT_NV12}, {
515   COLOR_TI_FormatYUV420PackedSemiPlanar, GST_VIDEO_FORMAT_NV12}, {
516   COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced, GST_VIDEO_FORMAT_NV12}, {
517   COLOR_INTEL_FormatYUV420PackedSemiPlanar, GST_VIDEO_FORMAT_NV12}, {
518   COLOR_INTEL_FormatYUV420PackedSemiPlanar_Tiled, GST_VIDEO_FORMAT_NV12}, {
519   COLOR_QCOM_FormatYUV420SemiPlanar, GST_VIDEO_FORMAT_NV12}, {
520   COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka, GST_VIDEO_FORMAT_NV12}, {
521   COLOR_QCOM_FormatYVU420SemiPlanar32m, GST_VIDEO_FORMAT_NV12}, {
522   COLOR_QCOM_FormatYVU420SemiPlanar32mMultiView, GST_VIDEO_FORMAT_NV12}, {
523   COLOR_OMX_SEC_FormatNV12Tiled, GST_VIDEO_FORMAT_NV12}, {
524   COLOR_FormatYCbYCr, GST_VIDEO_FORMAT_YUY2}, {
525   COLOR_FormatYV12, GST_VIDEO_FORMAT_YV12}
526 };
527 
528 static gboolean
accepted_color_formats(GstAmcCodecType * type,gboolean is_encoder)529 accepted_color_formats (GstAmcCodecType * type, gboolean is_encoder)
530 {
531   gint i, j;
532   gint accepted = 0, all = type->n_color_formats;
533 
534   for (i = 0; i < type->n_color_formats; i++) {
535     gboolean found = FALSE;
536     /* We ignore this one */
537     if (type->color_formats[i] == COLOR_FormatAndroidOpaque) {
538       all--;
539       continue;
540     }
541 
542     for (j = 0; j < G_N_ELEMENTS (color_format_mapping_table); j++) {
543       if (color_format_mapping_table[j].color_format == type->color_formats[i]) {
544         found = TRUE;
545         accepted++;
546         break;
547       }
548     }
549 
550     if (!found) {
551       GST_ERROR ("Unknown color format 0x%x, ignoring", type->color_formats[i]);
552     }
553   }
554 
555   if (is_encoder)
556     return accepted > 0;
557   else
558     return accepted == all && all > 0;
559 }
560 
561 GstVideoFormat
gst_amc_color_format_to_video_format(const GstAmcCodecInfo * codec_info,const gchar * mime,gint color_format)562 gst_amc_color_format_to_video_format (const GstAmcCodecInfo * codec_info,
563     const gchar * mime, gint color_format)
564 {
565   gint i;
566 
567   if (color_format == COLOR_FormatYCbYCr) {
568     if (strcmp (codec_info->name, "OMX.k3.video.decoder.avc") == 0) {
569       GST_INFO
570           ("OMX.k3.video.decoder.avc: COLOR_FormatYCbYCr is actually GST_VIDEO_FORMAT_NV12.");
571       return GST_VIDEO_FORMAT_NV12;
572     }
573 
574     /* FIXME COLOR_FormatYCbYCr doesn't work properly for OMX.k3.video.encoder.avc temporarily. */
575     if (strcmp (codec_info->name, "OMX.k3.video.encoder.avc") == 0) {
576       GST_INFO
577           ("OMX.k3.video.encoder.avc: COLOR_FormatYCbYCr is not supported yet.");
578       return GST_VIDEO_FORMAT_UNKNOWN;
579     }
580 
581     /* FIXME COLOR_FormatYCbYCr is not supported in gst_amc_color_format_info_set yet, mask it. */
582     return GST_VIDEO_FORMAT_UNKNOWN;
583   }
584 
585   if (color_format == COLOR_FormatYUV420SemiPlanar) {
586     if (strcmp (codec_info->name, "OMX.k3.video.encoder.avc") == 0) {
587       GST_INFO
588           ("OMX.k3.video.encoder.avc: COLOR_FormatYUV420SemiPlanar is actually GST_VIDEO_FORMAT_NV21.");
589       return GST_VIDEO_FORMAT_NV21;
590     }
591   }
592 
593   for (i = 0; i < G_N_ELEMENTS (color_format_mapping_table); i++) {
594     if (color_format_mapping_table[i].color_format == color_format)
595       return color_format_mapping_table[i].video_format;
596   }
597 
598   return GST_VIDEO_FORMAT_UNKNOWN;
599 }
600 
601 gint
gst_amc_video_format_to_color_format(const GstAmcCodecInfo * codec_info,const gchar * mime,GstVideoFormat video_format)602 gst_amc_video_format_to_color_format (const GstAmcCodecInfo * codec_info,
603     const gchar * mime, GstVideoFormat video_format)
604 {
605   const GstAmcCodecType *codec_type = NULL;
606   gint i, j;
607 
608   for (i = 0; i < codec_info->n_supported_types; i++) {
609     if (strcmp (codec_info->supported_types[i].mime, mime) == 0) {
610       codec_type = &codec_info->supported_types[i];
611       break;
612     }
613   }
614 
615   if (!codec_type)
616     return -1;
617 
618   if (video_format == GST_VIDEO_FORMAT_NV12) {
619     if (strcmp (codec_info->name, "OMX.k3.video.decoder.avc") == 0) {
620       GST_INFO
621           ("OMX.k3.video.decoder.avc: GST_VIDEO_FORMAT_NV12 is reported as COLOR_FormatYCbYCr.");
622 
623       return COLOR_FormatYCbYCr;
624     }
625   }
626 
627   if (video_format == GST_VIDEO_FORMAT_NV21) {
628     if (strcmp (codec_info->name, "OMX.k3.video.encoder.avc") == 0) {
629       GST_INFO
630           ("OMX.k3.video.encoder.avc: GST_VIDEO_FORMAT_NV21 is reported as COLOR_FormatYUV420SemiPlanar.");
631 
632       return COLOR_FormatYUV420SemiPlanar;
633     }
634   }
635 
636   for (i = 0; i < G_N_ELEMENTS (color_format_mapping_table); i++) {
637     if (color_format_mapping_table[i].video_format == video_format) {
638       gint color_format = color_format_mapping_table[i].color_format;
639 
640       for (j = 0; j < codec_type->n_color_formats; j++)
641         if (color_format == codec_type->color_formats[j])
642           return color_format;
643     }
644   }
645 
646   return -1;
647 }
648 
649 /*
650  * The format is called QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka.
651  * Which is actually NV12 (interleaved U&V).
652  */
653 #define TILE_WIDTH 64
654 #define TILE_HEIGHT 32
655 #define TILE_SIZE (TILE_WIDTH * TILE_HEIGHT)
656 #define TILE_GROUP_SIZE (4 * TILE_SIZE)
657 
658 /* get frame tile coordinate. XXX: nothing to be understood here, don't try. */
659 static size_t
tile_pos(size_t x,size_t y,size_t w,size_t h)660 tile_pos (size_t x, size_t y, size_t w, size_t h)
661 {
662   size_t flim = x + (y & ~1) * w;
663 
664   if (y & 1) {
665     flim += (x & ~3) + 2;
666   } else if ((h & 1) == 0 || y != (h - 1)) {
667     flim += (x + 2) & ~3;
668   }
669 
670   return flim;
671 }
672 
673 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)674 gst_amc_color_format_info_set (GstAmcColorFormatInfo * color_format_info,
675     const GstAmcCodecInfo * codec_info, const gchar * mime, gint color_format,
676     gint width, gint height, gint stride, gint slice_height, gint crop_left,
677     gint crop_right, gint crop_top, gint crop_bottom)
678 {
679   gint frame_size = 0;
680 
681   if (color_format == COLOR_FormatYCbYCr) {
682     if (strcmp (codec_info->name, "OMX.k3.video.decoder.avc") == 0)
683       color_format = COLOR_FormatYUV420SemiPlanar;
684   }
685 
686   /* Samsung Galaxy S3 seems to report wrong strides.
687    * I.e. BigBuckBunny 854x480 H264 reports a stride of 864 when it is
688    * actually 854, so we use width instead of stride here.
689    * This is obviously bound to break in the future. */
690   if (g_str_has_prefix (codec_info->name, "OMX.SEC.")) {
691     stride = width;
692   }
693 
694   if (strcmp (codec_info->name, "OMX.k3.video.decoder.avc") == 0) {
695     stride = width;
696     slice_height = height;
697   }
698 
699   if (slice_height == 0) {
700     /* NVidia Tegra 3 on Nexus 7 does not set this */
701     if (g_str_has_prefix (codec_info->name, "OMX.Nvidia."))
702       slice_height = GST_ROUND_UP_16 (height);
703   }
704 
705   if (width == 0 || height == 0) {
706     GST_ERROR ("Width or height is 0");
707     return FALSE;
708   }
709 
710   switch (color_format) {
711     case COLOR_FormatYUV420Planar:
712     case COLOR_FormatYUV420Flexible:{
713     case COLOR_FormatYV12:
714       if (stride == 0 || slice_height == 0) {
715         GST_ERROR ("Stride or slice height is 0");
716         return FALSE;
717       }
718 
719       frame_size =
720           stride * slice_height + 2 * ((stride + 1) / 2) * ((slice_height +
721               1) / 2);
722       break;
723     }
724     case COLOR_INTEL_FormatYUV420PackedSemiPlanar:
725     case COLOR_INTEL_FormatYUV420PackedSemiPlanar_Tiled:
726       if (stride == 0) {
727         GST_ERROR ("Stride is 0");
728         return FALSE;
729       }
730       if (slice_height <= 0)
731         slice_height = height;
732 
733       frame_size =
734           stride * (slice_height - crop_top / 2) +
735           (GST_ROUND_UP_2 (stride) * ((slice_height + 1) / 2));
736       break;
737 
738     case COLOR_TI_FormatYUV420PackedSemiPlanar:
739     case COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced:{
740       if (stride == 0 || slice_height == 0) {
741         GST_ERROR ("Stride or slice height is 0");
742         return FALSE;
743       }
744 
745       frame_size =
746           stride * (slice_height - crop_top / 2) +
747           (GST_ROUND_UP_2 (stride) * ((slice_height + 1) / 2));
748       break;
749     }
750     case COLOR_QCOM_FormatYUV420SemiPlanar:
751     case COLOR_QCOM_FormatYVU420SemiPlanar32m:
752     case COLOR_QCOM_FormatYVU420SemiPlanar32mMultiView:
753     case COLOR_FormatYUV420SemiPlanar:{
754       if (stride == 0 || slice_height == 0) {
755         GST_ERROR ("Stride or slice height is 0");
756         return FALSE;
757       }
758 
759       frame_size = stride * slice_height + stride * ((slice_height + 1) / 2);
760       break;
761     }
762     case COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka:{
763       const size_t tile_w = (width - 1) / TILE_WIDTH + 1;
764       const size_t tile_w_align = (tile_w + 1) & ~1;
765       const size_t tile_h_luma = (height - 1) / TILE_HEIGHT + 1;
766       frame_size =
767           tile_pos (tile_w, tile_h_luma, tile_w_align, tile_h_luma) * TILE_SIZE;
768       break;
769     }
770     default:
771       GST_ERROR ("Unsupported color format %d", color_format);
772       return FALSE;
773       break;
774   }
775 
776   color_format_info->color_format = color_format;
777   color_format_info->width = width;
778   color_format_info->height = height;
779   color_format_info->stride = stride;
780   color_format_info->slice_height = slice_height;
781   color_format_info->crop_left = crop_left;
782   color_format_info->crop_right = crop_right;
783   color_format_info->crop_top = crop_top;
784   color_format_info->crop_bottom = crop_bottom;
785   color_format_info->frame_size = frame_size;
786 
787   return TRUE;
788 }
789 
790 /* The weird handling of cropping, alignment and everything is taken from
791  * platform/frameworks/media/libstagefright/colorconversion/ColorConversion.cpp
792  */
793 gboolean
gst_amc_color_format_copy(GstAmcColorFormatInfo * cinfo,GstAmcBuffer * cbuffer,const GstAmcBufferInfo * cbuffer_info,GstVideoInfo * vinfo,GstBuffer * vbuffer,GstAmcColorFormatCopyDirection direction)794 gst_amc_color_format_copy (GstAmcColorFormatInfo * cinfo,
795     GstAmcBuffer * cbuffer, const GstAmcBufferInfo * cbuffer_info,
796     GstVideoInfo * vinfo, GstBuffer * vbuffer,
797     GstAmcColorFormatCopyDirection direction)
798 {
799   gboolean ret = FALSE;
800   guint8 *cptr = NULL, *vptr = NULL;
801   guint8 **src, **dest;
802 
803   if (direction == COLOR_FORMAT_COPY_OUT) {
804     src = &cptr;
805     dest = &vptr;
806   } else {
807     src = &vptr;
808     dest = &cptr;
809   }
810 
811   /* Same video format */
812   if (cbuffer_info->size == gst_buffer_get_size (vbuffer)) {
813     GstMapInfo minfo;
814 
815     GST_DEBUG ("Buffer sizes equal, doing fast copy");
816     gst_buffer_map (vbuffer, &minfo, GST_MAP_WRITE);
817 
818     cptr = cbuffer->data + cbuffer_info->offset;
819     vptr = minfo.data;
820     orc_memcpy (*dest, *src, cbuffer_info->size);
821 
822     gst_buffer_unmap (vbuffer, &minfo);
823     ret = TRUE;
824     goto done;
825   }
826 
827   GST_DEBUG ("Sizes not equal (%d vs %" G_GSIZE_FORMAT
828       "), doing slow line-by-line copying", cbuffer_info->size,
829       gst_buffer_get_size (vbuffer));
830 
831   /* Different video format, try to convert */
832   switch (cinfo->color_format) {
833     case COLOR_FormatYUV420Planar:{
834       GstVideoFrame vframe;
835       gint i, j, height;
836       gint stride, slice_height;
837       gint c_stride, v_stride;
838       gint row_length;
839 
840       stride = cinfo->stride;
841       slice_height = cinfo->slice_height;
842       g_assert (stride > 0 && slice_height > 0);
843 
844       gst_video_frame_map (&vframe, vinfo, vbuffer, GST_MAP_WRITE);
845 
846       for (i = 0; i < 3; i++) {
847         if (i == 0) {
848           c_stride = stride;
849           v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i);
850         } else {
851           c_stride = (stride + 1) / 2;
852           v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i);
853         }
854 
855         cptr = cbuffer->data + cbuffer_info->offset;
856 
857         if (i == 0) {
858           cptr += cinfo->crop_top * stride;
859           cptr += cinfo->crop_left;
860           row_length = cinfo->width;
861         } else if (i > 0) {
862           /* skip the Y plane */
863           cptr += slice_height * stride;
864 
865           /* crop_top/crop_left divided by two
866            * because one byte of the U/V planes
867            * corresponds to two pixels horizontally/vertically */
868           cptr += cinfo->crop_top / 2 * c_stride;
869           cptr += cinfo->crop_left / 2;
870           row_length = (cinfo->width + 1) / 2;
871         }
872         if (i == 2) {
873           /* skip the U plane */
874           cptr += ((slice_height + 1) / 2) * ((stride + 1) / 2);
875         }
876 
877         vptr = GST_VIDEO_FRAME_COMP_DATA (&vframe, i);
878         height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i);
879 
880         for (j = 0; j < height; j++) {
881           orc_memcpy (*dest, *src, row_length);
882           cptr += c_stride;
883           vptr += v_stride;
884         }
885       }
886       gst_video_frame_unmap (&vframe);
887       ret = TRUE;
888       break;
889     }
890     case COLOR_TI_FormatYUV420PackedSemiPlanar:
891     case COLOR_TI_FormatYUV420PackedSemiPlanarInterlaced:{
892       gint i, j, height;
893       gint c_stride, v_stride;
894       gint row_length;
895       GstVideoFrame vframe;
896 
897       /* This should always be set */
898       g_assert (cinfo->stride > 0 && cinfo->slice_height > 0);
899 
900       /* FIXME: This does not work for odd widths or heights
901        * but might as well be a bug in the codec */
902       gst_video_frame_map (&vframe, vinfo, vbuffer, GST_MAP_WRITE);
903       for (i = 0; i < 2; i++) {
904         if (i == 0) {
905           c_stride = cinfo->stride;
906           v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i);
907         } else {
908           c_stride = GST_ROUND_UP_2 (cinfo->stride);
909           v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i);
910         }
911 
912         cptr = cbuffer->data + cbuffer_info->offset;
913         if (i == 0) {
914           row_length = cinfo->width;
915         } else if (i == 1) {
916           cptr += (cinfo->slice_height - cinfo->crop_top / 2) * cinfo->stride;
917           row_length = GST_ROUND_UP_2 (cinfo->width);
918         }
919 
920         vptr = GST_VIDEO_FRAME_COMP_DATA (&vframe, i);
921         height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i);
922 
923         for (j = 0; j < height; j++) {
924           orc_memcpy (*dest, *src, row_length);
925           cptr += c_stride;
926           vptr += v_stride;
927         }
928       }
929       gst_video_frame_unmap (&vframe);
930       ret = TRUE;
931       break;
932     }
933     case COLOR_QCOM_FormatYUV420SemiPlanar:
934     case COLOR_QCOM_FormatYVU420SemiPlanar32m:
935     case COLOR_QCOM_FormatYVU420SemiPlanar32mMultiView:
936     case COLOR_FormatYUV420SemiPlanar:{
937       gint i, j, height;
938       gint c_stride, v_stride;
939       gint row_length;
940       GstVideoFrame vframe;
941 
942       /* This should always be set */
943       g_assert (cinfo->stride > 0 && cinfo->slice_height > 0);
944 
945       gst_video_frame_map (&vframe, vinfo, vbuffer, GST_MAP_WRITE);
946 
947       for (i = 0; i < 2; i++) {
948         c_stride = cinfo->stride;
949         v_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i);
950 
951         cptr = cbuffer->data + cbuffer_info->offset;
952         if (i == 0) {
953           cptr += cinfo->crop_top * cinfo->stride;
954           cptr += cinfo->crop_left;
955           row_length = cinfo->width;
956         } else if (i == 1) {
957           cptr += cinfo->slice_height * cinfo->stride;
958           cptr += cinfo->crop_top * cinfo->stride;
959           cptr += cinfo->crop_left;
960           row_length = cinfo->width;
961         }
962 
963         vptr = GST_VIDEO_FRAME_COMP_DATA (&vframe, i);
964         height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i);
965 
966         for (j = 0; j < height; j++) {
967           orc_memcpy (*dest, *src, row_length);
968           cptr += c_stride;
969           vptr += v_stride;
970         }
971       }
972       gst_video_frame_unmap (&vframe);
973       ret = TRUE;
974       break;
975     }
976       /* FIXME: This should be in libgstvideo as MT12 or similar, see v4l2 */
977     case COLOR_QCOM_FormatYUV420PackedSemiPlanar64x32Tile2m8ka:{
978       GstVideoFrame vframe;
979       gint width = cinfo->width;
980       gint height = cinfo->height;
981       gint v_luma_stride, v_chroma_stride;
982       guint8 *cdata = cbuffer->data + cbuffer_info->offset;
983       guint8 *v_luma, *v_chroma;
984       gint y;
985       const size_t tile_w = (width - 1) / TILE_WIDTH + 1;
986       const size_t tile_w_align = (tile_w + 1) & ~1;
987       const size_t tile_h_luma = (height - 1) / TILE_HEIGHT + 1;
988       const size_t tile_h_chroma = (height / 2 - 1) / TILE_HEIGHT + 1;
989       size_t luma_size = tile_w_align * tile_h_luma * TILE_SIZE;
990 
991       gst_video_frame_map (&vframe, vinfo, vbuffer, GST_MAP_WRITE);
992       v_luma = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0);
993       v_chroma = GST_VIDEO_FRAME_PLANE_DATA (&vframe, 1);
994       v_luma_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 0);
995       v_chroma_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, 1);
996 
997       if ((luma_size % TILE_GROUP_SIZE) != 0)
998         luma_size = (((luma_size - 1) / TILE_GROUP_SIZE) + 1) * TILE_GROUP_SIZE;
999 
1000       for (y = 0; y < tile_h_luma; y++) {
1001         size_t row_width = width;
1002         gint x;
1003 
1004         for (x = 0; x < tile_w; x++) {
1005           size_t tile_width = row_width;
1006           size_t tile_height = height;
1007           gint luma_idx;
1008           gint chroma_idx;
1009           /* luma source pointer for this tile */
1010           uint8_t *c_luma =
1011               cdata + tile_pos (x, y, tile_w_align, tile_h_luma) * TILE_SIZE;
1012 
1013           /* chroma source pointer for this tile */
1014           uint8_t *c_chroma =
1015               cdata + luma_size + tile_pos (x, y / 2, tile_w_align,
1016               tile_h_chroma) * TILE_SIZE;
1017           if (y & 1)
1018             c_chroma += TILE_SIZE / 2;
1019 
1020           /* account for right columns */
1021           if (tile_width > TILE_WIDTH)
1022             tile_width = TILE_WIDTH;
1023 
1024           /* account for bottom rows */
1025           if (tile_height > TILE_HEIGHT)
1026             tile_height = TILE_HEIGHT;
1027 
1028           /* vptr luma memory index for this tile */
1029           luma_idx = y * TILE_HEIGHT * v_luma_stride + x * TILE_WIDTH;
1030 
1031           /* vptr chroma memory index for this tile */
1032           /* XXX: remove divisions */
1033           chroma_idx = y * TILE_HEIGHT / 2 * v_chroma_stride + x * TILE_WIDTH;
1034 
1035           tile_height /= 2;     // we copy 2 luma lines at once
1036           while (tile_height--) {
1037             vptr = v_luma + luma_idx;
1038             cptr = c_luma;
1039             memcpy (*dest, *src, tile_width);
1040             c_luma += TILE_WIDTH;
1041             luma_idx += v_luma_stride;
1042 
1043             vptr = v_luma + luma_idx;
1044             cptr = c_luma;
1045             memcpy (*dest, *src, tile_width);
1046             c_luma += TILE_WIDTH;
1047             luma_idx += v_luma_stride;
1048 
1049             vptr = v_chroma + chroma_idx;
1050             cptr = c_chroma;
1051             memcpy (*dest, *src, tile_width);
1052             c_chroma += TILE_WIDTH;
1053             chroma_idx += v_chroma_stride;
1054           }
1055           row_width -= TILE_WIDTH;
1056         }
1057         height -= TILE_HEIGHT;
1058       }
1059       gst_video_frame_unmap (&vframe);
1060       ret = TRUE;
1061       break;
1062 
1063     }
1064     default:
1065       GST_ERROR ("Unsupported color format %d", cinfo->color_format);
1066       goto done;
1067       break;
1068   }
1069 
1070 done:
1071   return ret;
1072 }
1073 
1074 static const struct
1075 {
1076   gint id;
1077   const gchar *str;
1078 } hevc_profile_mapping_table[] = {
1079   {
1080   HEVCProfileMain, "main"}, {
1081   HEVCProfileMain10, "main-10"}
1082 };
1083 
1084 const gchar *
gst_amc_hevc_profile_to_string(gint profile)1085 gst_amc_hevc_profile_to_string (gint profile)
1086 {
1087   gint i;
1088 
1089   for (i = 0; i < G_N_ELEMENTS (hevc_profile_mapping_table); i++) {
1090     if (hevc_profile_mapping_table[i].id == profile) {
1091       return hevc_profile_mapping_table[i].str;
1092     }
1093   }
1094 
1095   return NULL;
1096 }
1097 
1098 gint
gst_amc_hevc_profile_from_string(const gchar * profile)1099 gst_amc_hevc_profile_from_string (const gchar * profile)
1100 {
1101   gint i;
1102 
1103   g_return_val_if_fail (profile != NULL, -1);
1104 
1105   for (i = 0; i < G_N_ELEMENTS (hevc_profile_mapping_table); i++) {
1106     if (strcmp (hevc_profile_mapping_table[i].str, profile) == 0)
1107       return hevc_profile_mapping_table[i].id;
1108   }
1109 
1110   return -1;
1111 }
1112 
1113 static const struct
1114 {
1115   gint id;
1116   const gchar *tier_str;
1117   const gchar *level_str;
1118 } hevc_tier_level_mapping_table[] = {
1119   {
1120   HEVCMainTierLevel1, "main", "1"}, {
1121   HEVCMainTierLevel2, "main", "2"}, {
1122   HEVCMainTierLevel21, "main", "2.1"}, {
1123   HEVCMainTierLevel3, "main", "3"}, {
1124   HEVCMainTierLevel31, "main", "3.1"}, {
1125   HEVCMainTierLevel4, "main", "4"}, {
1126   HEVCMainTierLevel41, "main", "4.1"}, {
1127   HEVCMainTierLevel5, "main", "5"}, {
1128   HEVCMainTierLevel51, "main", "5.1"}, {
1129   HEVCMainTierLevel52, "main", "5.2"}, {
1130   HEVCMainTierLevel6, "main", "6"}, {
1131   HEVCMainTierLevel61, "main", "6.1"}, {
1132   HEVCMainTierLevel62, "main", "6.2"}, {
1133   HEVCHighTierLevel1, "high", "1"}, {
1134   HEVCHighTierLevel2, "high", "2"}, {
1135   HEVCHighTierLevel21, "high", "2.1"}, {
1136   HEVCHighTierLevel3, "high", "3"}, {
1137   HEVCHighTierLevel31, "high", "3.1"}, {
1138   HEVCHighTierLevel4, "high", "4"}, {
1139   HEVCHighTierLevel41, "high", "4.1"}, {
1140   HEVCHighTierLevel5, "high", "5"}, {
1141   HEVCHighTierLevel51, "high", "5.1"}, {
1142   HEVCHighTierLevel52, "high", "5.2"}, {
1143   HEVCHighTierLevel6, "high", "6"}, {
1144   HEVCHighTierLevel61, "high", "6.1"}, {
1145   HEVCHighTierLevel62, "high", "6.2"}
1146 };
1147 
1148 const gchar *
gst_amc_hevc_tier_level_to_string(gint tier_level,const gchar ** tier)1149 gst_amc_hevc_tier_level_to_string (gint tier_level, const gchar ** tier)
1150 {
1151   gint i;
1152 
1153   for (i = 0; i < G_N_ELEMENTS (hevc_tier_level_mapping_table); i++) {
1154     if (hevc_tier_level_mapping_table[i].id == tier_level)
1155       *tier = hevc_tier_level_mapping_table[i].tier_str;
1156     return hevc_tier_level_mapping_table[i].level_str;
1157   }
1158 
1159   return NULL;
1160 }
1161 
1162 gint
gst_amc_hevc_tier_level_from_string(const gchar * tier,const gchar * level)1163 gst_amc_hevc_tier_level_from_string (const gchar * tier, const gchar * level)
1164 {
1165   gint i;
1166 
1167   g_return_val_if_fail (level != NULL, -1);
1168 
1169   for (i = 0; i < G_N_ELEMENTS (hevc_tier_level_mapping_table); i++) {
1170     if (strcmp (hevc_tier_level_mapping_table[i].tier_str, tier) == 0 &&
1171         strcmp (hevc_tier_level_mapping_table[i].level_str, level) == 0)
1172       return hevc_tier_level_mapping_table[i].id;
1173   }
1174 
1175   return -1;
1176 }
1177 
1178 static const struct
1179 {
1180   gint id;
1181   const gchar *str;
1182   const gchar *alt_str;
1183 } avc_profile_mapping_table[] = {
1184   {
1185   AVCProfileBaseline, "baseline", "constrained-baseline"}, {
1186   AVCProfileMain, "main", NULL}, {
1187   AVCProfileExtended, "extended", NULL}, {
1188   AVCProfileHigh, "high"}, {
1189   AVCProfileHigh10, "high-10", "high-10-intra"}, {
1190   AVCProfileHigh422, "high-4:2:2", "high-4:2:2-intra"}, {
1191   AVCProfileHigh444, "high-4:4:4", "high-4:4:4-intra"}
1192 };
1193 
1194 const gchar *
gst_amc_avc_profile_to_string(gint profile,const gchar ** alternative)1195 gst_amc_avc_profile_to_string (gint profile, const gchar ** alternative)
1196 {
1197   gint i;
1198 
1199   for (i = 0; i < G_N_ELEMENTS (avc_profile_mapping_table); i++) {
1200     if (avc_profile_mapping_table[i].id == profile) {
1201       if (alternative != NULL)
1202         *alternative = avc_profile_mapping_table[i].alt_str;
1203       return avc_profile_mapping_table[i].str;
1204     }
1205   }
1206 
1207   return NULL;
1208 }
1209 
1210 gint
gst_amc_avc_profile_from_string(const gchar * profile)1211 gst_amc_avc_profile_from_string (const gchar * profile)
1212 {
1213   gint i;
1214 
1215   g_return_val_if_fail (profile != NULL, -1);
1216 
1217   for (i = 0; i < G_N_ELEMENTS (avc_profile_mapping_table); i++) {
1218     if (strcmp (avc_profile_mapping_table[i].str, profile) == 0 ||
1219         (avc_profile_mapping_table[i].alt_str &&
1220             strcmp (avc_profile_mapping_table[i].alt_str, profile) == 0))
1221       return avc_profile_mapping_table[i].id;
1222   }
1223 
1224   return -1;
1225 }
1226 
1227 static const struct
1228 {
1229   gint id;
1230   const gchar *str;
1231 } avc_level_mapping_table[] = {
1232   {
1233   AVCLevel1, "1"}, {
1234   AVCLevel1b, "1b"}, {
1235   AVCLevel11, "1.1"}, {
1236   AVCLevel12, "1.2"}, {
1237   AVCLevel13, "1.3"}, {
1238   AVCLevel2, "2"}, {
1239   AVCLevel21, "2.1"}, {
1240   AVCLevel22, "2.2"}, {
1241   AVCLevel3, "3"}, {
1242   AVCLevel31, "3.1"}, {
1243   AVCLevel32, "3.2"}, {
1244   AVCLevel4, "4"}, {
1245   AVCLevel41, "4.1"}, {
1246   AVCLevel42, "4.2"}, {
1247   AVCLevel5, "5"}, {
1248   AVCLevel51, "5.1"}
1249 };
1250 
1251 const gchar *
gst_amc_avc_level_to_string(gint level)1252 gst_amc_avc_level_to_string (gint level)
1253 {
1254   gint i;
1255 
1256   for (i = 0; i < G_N_ELEMENTS (avc_level_mapping_table); i++) {
1257     if (avc_level_mapping_table[i].id == level)
1258       return avc_level_mapping_table[i].str;
1259   }
1260 
1261   return NULL;
1262 }
1263 
1264 gint
gst_amc_avc_level_from_string(const gchar * level)1265 gst_amc_avc_level_from_string (const gchar * level)
1266 {
1267   gint i;
1268 
1269   g_return_val_if_fail (level != NULL, -1);
1270 
1271   for (i = 0; i < G_N_ELEMENTS (avc_level_mapping_table); i++) {
1272     if (strcmp (avc_level_mapping_table[i].str, level) == 0)
1273       return avc_level_mapping_table[i].id;
1274   }
1275 
1276   return -1;
1277 }
1278 
1279 static const struct
1280 {
1281   gint id;
1282   gint gst_id;
1283 } h263_profile_mapping_table[] = {
1284   {
1285   H263ProfileBaseline, 0}, {
1286   H263ProfileH320Coding, 1}, {
1287   H263ProfileBackwardCompatible, 2}, {
1288   H263ProfileISWV2, 3}, {
1289   H263ProfileISWV3, 4}, {
1290   H263ProfileHighCompression, 5}, {
1291   H263ProfileInternet, 6}, {
1292   H263ProfileInterlace, 7}, {
1293   H263ProfileHighLatency, 8}
1294 };
1295 
1296 gint
gst_amc_h263_profile_to_gst_id(gint profile)1297 gst_amc_h263_profile_to_gst_id (gint profile)
1298 {
1299   gint i;
1300 
1301   for (i = 0; i < G_N_ELEMENTS (h263_profile_mapping_table); i++) {
1302     if (h263_profile_mapping_table[i].id == profile)
1303       return h263_profile_mapping_table[i].gst_id;
1304   }
1305 
1306   return -1;
1307 }
1308 
1309 gint
gst_amc_h263_profile_from_gst_id(gint profile)1310 gst_amc_h263_profile_from_gst_id (gint profile)
1311 {
1312   gint i;
1313 
1314   for (i = 0; i < G_N_ELEMENTS (h263_profile_mapping_table); i++) {
1315     if (h263_profile_mapping_table[i].gst_id == profile)
1316       return h263_profile_mapping_table[i].id;
1317   }
1318 
1319   return -1;
1320 }
1321 
1322 static const struct
1323 {
1324   gint id;
1325   gint gst_id;
1326 } h263_level_mapping_table[] = {
1327   {
1328   H263Level10, 10}, {
1329   H263Level20, 20}, {
1330   H263Level30, 30}, {
1331   H263Level40, 40}, {
1332   H263Level50, 50}, {
1333   H263Level60, 60}, {
1334   H263Level70, 70}
1335 };
1336 
1337 gint
gst_amc_h263_level_to_gst_id(gint level)1338 gst_amc_h263_level_to_gst_id (gint level)
1339 {
1340   gint i;
1341 
1342   for (i = 0; i < G_N_ELEMENTS (h263_level_mapping_table); i++) {
1343     if (h263_level_mapping_table[i].id == level)
1344       return h263_level_mapping_table[i].gst_id;
1345   }
1346 
1347   return -1;
1348 }
1349 
1350 gint
gst_amc_h263_level_from_gst_id(gint level)1351 gst_amc_h263_level_from_gst_id (gint level)
1352 {
1353   gint i;
1354 
1355   for (i = 0; i < G_N_ELEMENTS (h263_level_mapping_table); i++) {
1356     if (h263_level_mapping_table[i].gst_id == level)
1357       return h263_level_mapping_table[i].id;
1358   }
1359 
1360   return -1;
1361 }
1362 
1363 static const struct
1364 {
1365   gint id;
1366   const gchar *str;
1367 } mpeg4_profile_mapping_table[] = {
1368   {
1369   MPEG4ProfileSimple, "simple"}, {
1370   MPEG4ProfileSimpleScalable, "simple-scalable"}, {
1371   MPEG4ProfileCore, "core"}, {
1372   MPEG4ProfileMain, "main"}, {
1373   MPEG4ProfileNbit, "n-bit"}, {
1374   MPEG4ProfileScalableTexture, "scalable"}, {
1375   MPEG4ProfileSimpleFace, "simple-face"}, {
1376   MPEG4ProfileSimpleFBA, "simple-fba"}, {
1377   MPEG4ProfileBasicAnimated, "basic-animated-texture"}, {
1378   MPEG4ProfileHybrid, "hybrid"}, {
1379   MPEG4ProfileAdvancedRealTime, "advanced-real-time"}, {
1380   MPEG4ProfileCoreScalable, "core-scalable"}, {
1381   MPEG4ProfileAdvancedCoding, "advanced-coding-efficiency"}, {
1382   MPEG4ProfileAdvancedCore, "advanced-core"}, {
1383   MPEG4ProfileAdvancedScalable, "advanced-scalable-texture"}, {
1384   MPEG4ProfileAdvancedSimple, "advanced-simple"}
1385 };
1386 
1387 const gchar *
gst_amc_mpeg4_profile_to_string(gint profile)1388 gst_amc_mpeg4_profile_to_string (gint profile)
1389 {
1390   gint i;
1391 
1392   for (i = 0; i < G_N_ELEMENTS (mpeg4_profile_mapping_table); i++) {
1393     if (mpeg4_profile_mapping_table[i].id == profile)
1394       return mpeg4_profile_mapping_table[i].str;
1395   }
1396 
1397   return NULL;
1398 }
1399 
1400 gint
gst_amc_mpeg4_profile_from_string(const gchar * profile)1401 gst_amc_mpeg4_profile_from_string (const gchar * profile)
1402 {
1403   gint i;
1404 
1405   g_return_val_if_fail (profile != NULL, -1);
1406 
1407   for (i = 0; i < G_N_ELEMENTS (mpeg4_profile_mapping_table); i++) {
1408     if (strcmp (mpeg4_profile_mapping_table[i].str, profile) == 0)
1409       return mpeg4_profile_mapping_table[i].id;
1410   }
1411 
1412   return -1;
1413 }
1414 
1415 static const struct
1416 {
1417   gint id;
1418   const gchar *str;
1419 } mpeg4_level_mapping_table[] = {
1420   {
1421   MPEG4Level0, "0"}, {
1422   MPEG4Level0b, "0b"}, {
1423   MPEG4Level1, "1"}, {
1424   MPEG4Level2, "2"}, {
1425   MPEG4Level3, "3"}, {
1426   MPEG4Level4, "4"}, {
1427   MPEG4Level4a, "4a"}, {
1428 MPEG4Level5, "5"},};
1429 
1430 const gchar *
gst_amc_mpeg4_level_to_string(gint level)1431 gst_amc_mpeg4_level_to_string (gint level)
1432 {
1433   gint i;
1434 
1435   for (i = 0; i < G_N_ELEMENTS (mpeg4_level_mapping_table); i++) {
1436     if (mpeg4_level_mapping_table[i].id == level)
1437       return mpeg4_level_mapping_table[i].str;
1438   }
1439 
1440   return NULL;
1441 }
1442 
1443 gint
gst_amc_mpeg4_level_from_string(const gchar * level)1444 gst_amc_mpeg4_level_from_string (const gchar * level)
1445 {
1446   gint i;
1447 
1448   g_return_val_if_fail (level != NULL, -1);
1449 
1450   for (i = 0; i < G_N_ELEMENTS (mpeg4_level_mapping_table); i++) {
1451     if (strcmp (mpeg4_level_mapping_table[i].str, level) == 0)
1452       return mpeg4_level_mapping_table[i].id;
1453   }
1454 
1455   return -1;
1456 }
1457 
1458 static const struct
1459 {
1460   gint id;
1461   const gchar *str;
1462 } aac_profile_mapping_table[] = {
1463   {
1464   AACObjectMain, "main"}, {
1465   AACObjectLC, "lc"}, {
1466   AACObjectSSR, "ssr"}, {
1467   AACObjectLTP, "ltp"}
1468 };
1469 
1470 const gchar *
gst_amc_aac_profile_to_string(gint profile)1471 gst_amc_aac_profile_to_string (gint profile)
1472 {
1473   gint i;
1474 
1475   for (i = 0; i < G_N_ELEMENTS (aac_profile_mapping_table); i++) {
1476     if (aac_profile_mapping_table[i].id == profile)
1477       return aac_profile_mapping_table[i].str;
1478   }
1479 
1480   return NULL;
1481 }
1482 
1483 gint
gst_amc_aac_profile_from_string(const gchar * profile)1484 gst_amc_aac_profile_from_string (const gchar * profile)
1485 {
1486   gint i;
1487 
1488   g_return_val_if_fail (profile != NULL, -1);
1489 
1490   for (i = 0; i < G_N_ELEMENTS (aac_profile_mapping_table); i++) {
1491     if (strcmp (aac_profile_mapping_table[i].str, profile) == 0)
1492       return aac_profile_mapping_table[i].id;
1493   }
1494 
1495   return -1;
1496 }
1497 
1498 static const struct
1499 {
1500   guint32 mask;
1501   GstAudioChannelPosition pos;
1502 } channel_mapping_table[] = {
1503   {
1504   CHANNEL_OUT_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT}, {
1505   CHANNEL_OUT_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
1506   CHANNEL_OUT_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, {
1507   CHANNEL_OUT_LOW_FREQUENCY, GST_AUDIO_CHANNEL_POSITION_LFE1}, {
1508   CHANNEL_OUT_BACK_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT}, {
1509   CHANNEL_OUT_BACK_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
1510   CHANNEL_OUT_FRONT_LEFT_OF_CENTER,
1511         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER}, {
1512   CHANNEL_OUT_FRONT_RIGHT_OF_CENTER,
1513         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, {
1514   CHANNEL_OUT_BACK_CENTER, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
1515   CHANNEL_OUT_SIDE_LEFT, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT}, {
1516   CHANNEL_OUT_SIDE_RIGHT, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, {
1517   CHANNEL_OUT_TOP_CENTER, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
1518   CHANNEL_OUT_TOP_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
1519   CHANNEL_OUT_TOP_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
1520   CHANNEL_OUT_TOP_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
1521   CHANNEL_OUT_TOP_BACK_LEFT, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
1522   CHANNEL_OUT_TOP_BACK_CENTER, GST_AUDIO_CHANNEL_POSITION_INVALID}, {
1523   CHANNEL_OUT_TOP_BACK_RIGHT, GST_AUDIO_CHANNEL_POSITION_INVALID}
1524 };
1525 
1526 gboolean
gst_amc_audio_channel_mask_to_positions(guint32 channel_mask,gint channels,GstAudioChannelPosition * pos)1527 gst_amc_audio_channel_mask_to_positions (guint32 channel_mask, gint channels,
1528     GstAudioChannelPosition * pos)
1529 {
1530   gint i, j;
1531 
1532   if (channel_mask == 0) {
1533     if (channels == 1) {
1534       pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
1535       return TRUE;
1536     }
1537     if (channels == 2) {
1538       pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
1539       pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
1540       return TRUE;
1541     }
1542 
1543     /* Now let the guesswork begin, these are the
1544      * AAC default channel assignments for these numbers
1545      * of channels */
1546     if (channels == 3) {
1547       channel_mask =
1548           CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
1549           CHANNEL_OUT_FRONT_CENTER;
1550     } else if (channels == 4) {
1551       channel_mask =
1552           CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
1553           CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER;
1554     } else if (channels == 5) {
1555       channel_mask =
1556           CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
1557           CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_LEFT |
1558           CHANNEL_OUT_BACK_RIGHT;
1559     } else if (channels == 6) {
1560       channel_mask =
1561           CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
1562           CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_LEFT |
1563           CHANNEL_OUT_BACK_RIGHT | CHANNEL_OUT_LOW_FREQUENCY;
1564     } else if (channels == 8) {
1565       channel_mask =
1566           CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
1567           CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_LEFT |
1568           CHANNEL_OUT_BACK_RIGHT | CHANNEL_OUT_LOW_FREQUENCY |
1569           CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER;
1570     }
1571   }
1572 
1573   for (i = 0, j = 0; i < G_N_ELEMENTS (channel_mapping_table); i++) {
1574     if ((channel_mask & channel_mapping_table[i].mask)) {
1575       pos[j++] = channel_mapping_table[i].pos;
1576       if (channel_mapping_table[i].pos == GST_AUDIO_CHANNEL_POSITION_INVALID) {
1577         memset (pos, 0, sizeof (GstAudioChannelPosition) * channels);
1578         GST_ERROR ("Unable to map channel mask 0x%08x",
1579             channel_mapping_table[i].mask);
1580         return FALSE;
1581       }
1582       if (j == channels)
1583         break;
1584     }
1585   }
1586 
1587   if (j != channels) {
1588     memset (pos, 0, sizeof (GstAudioChannelPosition) * channels);
1589     GST_ERROR ("Unable to map all channel positions in mask 0x%08x",
1590         channel_mask);
1591     return FALSE;
1592   }
1593 
1594   return TRUE;
1595 }
1596 
1597 guint32
gst_amc_audio_channel_mask_from_positions(GstAudioChannelPosition * positions,gint channels)1598 gst_amc_audio_channel_mask_from_positions (GstAudioChannelPosition * positions,
1599     gint channels)
1600 {
1601   gint i, j;
1602   guint32 channel_mask = 0;
1603 
1604   if (channels == 1 && !positions)
1605     return CHANNEL_OUT_FRONT_CENTER;
1606   if (channels == 2 && !positions)
1607     return CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT;
1608 
1609   for (i = 0; i < channels; i++) {
1610     if (positions[i] == GST_AUDIO_CHANNEL_POSITION_INVALID)
1611       return 0;
1612 
1613     for (j = 0; j < G_N_ELEMENTS (channel_mapping_table); j++) {
1614       if (channel_mapping_table[j].pos == positions[i]) {
1615         channel_mask |= channel_mapping_table[j].mask;
1616         break;
1617       }
1618     }
1619 
1620     if (j == G_N_ELEMENTS (channel_mapping_table)) {
1621       GST_ERROR ("Unable to map channel position %d", positions[i]);
1622       return 0;
1623     }
1624   }
1625 
1626   return channel_mask;
1627 }
1628 
1629 static gchar *
create_type_name(const gchar * parent_name,const gchar * codec_name)1630 create_type_name (const gchar * parent_name, const gchar * codec_name)
1631 {
1632   gchar *typified_name;
1633   gint i, k;
1634   gint parent_name_len = strlen (parent_name);
1635   gint codec_name_len = strlen (codec_name);
1636   gboolean upper = TRUE;
1637 
1638   typified_name = g_new0 (gchar, parent_name_len + 1 + strlen (codec_name) + 1);
1639   memcpy (typified_name, parent_name, parent_name_len);
1640   typified_name[parent_name_len] = '-';
1641 
1642   for (i = 0, k = 0; i < codec_name_len; i++) {
1643     if (g_ascii_isalnum (codec_name[i])) {
1644       if (upper)
1645         typified_name[parent_name_len + 1 + k++] =
1646             g_ascii_toupper (codec_name[i]);
1647       else
1648         typified_name[parent_name_len + 1 + k++] =
1649             g_ascii_tolower (codec_name[i]);
1650 
1651       upper = FALSE;
1652     } else {
1653       /* Skip all non-alnum chars and start a new upper case word */
1654       upper = TRUE;
1655     }
1656   }
1657 
1658   return typified_name;
1659 }
1660 
1661 static gchar *
create_element_name(gboolean video,gboolean encoder,const gchar * codec_name)1662 create_element_name (gboolean video, gboolean encoder, const gchar * codec_name)
1663 {
1664 #define PREFIX_LEN 10
1665   static const gchar *prefixes[] = {
1666     "amcviddec-",
1667     "amcauddec-",
1668     "amcvidenc-",
1669     "amcaudenc-"
1670   };
1671   gchar *element_name;
1672   gint i, k;
1673   gint codec_name_len = strlen (codec_name);
1674   const gchar *prefix;
1675 
1676   if (video && !encoder)
1677     prefix = prefixes[0];
1678   else if (!video && !encoder)
1679     prefix = prefixes[1];
1680   else if (video && encoder)
1681     prefix = prefixes[2];
1682   else
1683     prefix = prefixes[3];
1684 
1685   element_name = g_new0 (gchar, PREFIX_LEN + strlen (codec_name) + 1);
1686   memcpy (element_name, prefix, PREFIX_LEN);
1687 
1688   for (i = 0, k = 0; i < codec_name_len; i++) {
1689     if (g_ascii_isalnum (codec_name[i])) {
1690       element_name[PREFIX_LEN + k++] = g_ascii_tolower (codec_name[i]);
1691     }
1692     /* Skip all non-alnum chars */
1693   }
1694 
1695   return element_name;
1696 }
1697 
1698 #undef PREFIX_LEN
1699 
1700 static gboolean
register_codecs(GstPlugin * plugin)1701 register_codecs (GstPlugin * plugin)
1702 {
1703   gboolean ret = TRUE;
1704   GList *l;
1705 
1706   GST_DEBUG ("Registering plugins");
1707 
1708   for (l = codec_infos.head; l; l = l->next) {
1709     GstAmcCodecInfo *codec_info = l->data;
1710     gboolean is_audio = FALSE;
1711     gboolean is_video = FALSE;
1712     gint i;
1713     gint n_types;
1714 
1715     GST_DEBUG ("Registering codec '%s'", codec_info->name);
1716     for (i = 0; i < codec_info->n_supported_types; i++) {
1717       GstAmcCodecType *codec_type = &codec_info->supported_types[i];
1718 
1719       if (g_str_has_prefix (codec_type->mime, "audio/"))
1720         is_audio = TRUE;
1721       else if (g_str_has_prefix (codec_type->mime, "video/"))
1722         is_video = TRUE;
1723     }
1724 
1725     n_types = 0;
1726     if (is_audio)
1727       n_types++;
1728     if (is_video)
1729       n_types++;
1730 
1731     for (i = 0; i < n_types; i++) {
1732       GTypeQuery type_query;
1733       GTypeInfo type_info = { 0, };
1734       GType type, subtype;
1735       gchar *type_name, *element_name;
1736       guint rank;
1737 
1738       if (is_video) {
1739         if (codec_info->is_encoder)
1740           type = gst_amc_video_enc_get_type ();
1741         else
1742           type = gst_amc_video_dec_get_type ();
1743       } else if (is_audio && !codec_info->is_encoder) {
1744         type = gst_amc_audio_dec_get_type ();
1745       } else {
1746         GST_DEBUG ("Skipping unsupported codec type");
1747         continue;
1748       }
1749 
1750       g_type_query (type, &type_query);
1751       memset (&type_info, 0, sizeof (type_info));
1752       type_info.class_size = type_query.class_size;
1753       type_info.instance_size = type_query.instance_size;
1754       type_name = create_type_name (type_query.type_name, codec_info->name);
1755 
1756       if (g_type_from_name (type_name) != G_TYPE_INVALID) {
1757         GST_ERROR ("Type '%s' already exists for codec '%s'", type_name,
1758             codec_info->name);
1759         g_free (type_name);
1760         continue;
1761       }
1762 
1763       subtype = g_type_register_static (type, type_name, &type_info, 0);
1764       g_free (type_name);
1765 
1766       g_type_set_qdata (subtype, gst_amc_codec_info_quark, codec_info);
1767 
1768       element_name =
1769           create_element_name (is_video, codec_info->is_encoder,
1770           codec_info->name);
1771 
1772       /* Give the Google software codec a secondary rank,
1773        * everything else is likely a hardware codec, except
1774        * OMX.SEC.*.sw.dec (as seen in Galaxy S4).
1775        *
1776        * Also on some devices there are codecs that don't start
1777        * with OMX., while there are also some that do. And on
1778        * some of these devices the ones that don't start with
1779        * OMX. just crash during initialization while the others
1780        * work. To make things even more complicated other devices
1781        * have codecs with the same name that work and no alternatives.
1782        * So just give a lower rank to these non-OMX codecs and hope
1783        * that there's an alternative with a higher rank.
1784        */
1785       if (g_str_has_prefix (codec_info->name, "OMX.google") ||
1786           g_str_has_suffix (codec_info->name, ".sw.dec")) {
1787         /* For video we prefer hardware codecs, for audio we prefer software
1788          * codecs. Hardware codecs don't make much sense for audio */
1789         rank = is_video ? GST_RANK_SECONDARY : GST_RANK_PRIMARY;
1790       } else if (g_str_has_prefix (codec_info->name, "OMX.Exynos.")
1791           && !is_video) {
1792         /* OMX.Exynos. audio codecs are existing on some devices like the
1793          * Galaxy S5 mini, and cause random crashes (of the device,
1794          * not the app!) and generally misbehave. That specific device
1795          * has other codecs that work with a different name, but let's
1796          * just give them marginal rank in case there are devices that
1797          * have no other codecs and these are actually the only working
1798          * ones
1799          */
1800         rank = GST_RANK_MARGINAL;
1801       } else if (g_str_has_prefix (codec_info->name, "OMX.")) {
1802         rank = is_video ? GST_RANK_PRIMARY : GST_RANK_SECONDARY;
1803       } else {
1804         rank = GST_RANK_MARGINAL;
1805       }
1806 
1807       ret |= gst_element_register (plugin, element_name, rank, subtype);
1808       g_free (element_name);
1809 
1810       is_video = FALSE;
1811     }
1812   }
1813 
1814   return ret;
1815 }
1816 
1817 static gboolean
amc_init(GstPlugin * plugin)1818 amc_init (GstPlugin * plugin)
1819 {
1820   const gchar *ignore;
1821 
1822   gst_plugin_add_dependency_simple (plugin, NULL, "/etc:/system/vendor/etc",
1823       "media_codecs.xml", GST_PLUGIN_DEPENDENCY_FLAG_NONE);
1824 
1825   gst_amc_codec_info_quark = g_quark_from_static_string ("gst-amc-codec-info");
1826 
1827   if (!gst_amc_codeclist_static_init ())
1828     return FALSE;
1829 
1830   if (!gst_amc_codec_static_init ())
1831     return FALSE;
1832 
1833   if (!gst_amc_format_static_init ())
1834     return FALSE;
1835 
1836   if (!gst_amc_surface_texture_static_init ())
1837     return FALSE;
1838 
1839   /* Set this to TRUE to allow registering decoders that have
1840    * any unknown color formats, or encoders that only have
1841    * unknown color formats
1842    */
1843   ignore = g_getenv ("GST_AMC_IGNORE_UNKNOWN_COLOR_FORMATS");
1844   if (ignore && strcmp (ignore, "yes") == 0)
1845     ignore_unknown_color_formats = TRUE;
1846 
1847   if (!scan_codecs (plugin))
1848     return FALSE;
1849 
1850   if (!register_codecs (plugin))
1851     return FALSE;
1852 
1853   return TRUE;
1854 }
1855 
1856 #ifdef HAVE_JNI_H
1857 static gboolean
ahc_init(GstPlugin * plugin)1858 ahc_init (GstPlugin * plugin)
1859 {
1860   if (!gst_android_graphics_imageformat_init ()) {
1861     GST_ERROR ("Failed to init android image format");
1862     return FALSE;
1863   }
1864 
1865   if (!gst_android_hardware_camera_init ()) {
1866     gst_android_graphics_imageformat_deinit ();
1867     return FALSE;
1868   }
1869 
1870   if (!gst_element_register (plugin, "ahcsrc", GST_RANK_NONE, GST_TYPE_AHC_SRC)) {
1871     GST_ERROR ("Failed to register android camera source");
1872     gst_android_hardware_camera_deinit ();
1873     gst_android_graphics_imageformat_deinit ();
1874     return FALSE;
1875   }
1876 
1877   return TRUE;
1878 }
1879 
1880 static gboolean
ahs_init(GstPlugin * plugin)1881 ahs_init (GstPlugin * plugin)
1882 {
1883   if (!gst_android_hardware_sensor_init ())
1884     return FALSE;
1885 
1886   if (!gst_element_register (plugin, "ahssrc", GST_RANK_NONE, GST_TYPE_AHS_SRC)) {
1887     GST_ERROR ("Failed to register android sensor source");
1888     gst_android_hardware_sensor_deinit ();
1889     return FALSE;
1890   }
1891 
1892   return TRUE;
1893 }
1894 #endif
1895 
1896 static gboolean
plugin_init(GstPlugin * plugin)1897 plugin_init (GstPlugin * plugin)
1898 {
1899   gboolean init_ok = FALSE;
1900 
1901   GST_DEBUG_CATEGORY_INIT (gst_amc_debug, "amc", 0, "android-media-codec");
1902 
1903 #ifdef HAVE_JNI_H
1904   if (!gst_amc_jni_initialize ())
1905     return FALSE;
1906 #endif
1907 
1908   if (amc_init (plugin))
1909     init_ok = TRUE;
1910 
1911 #ifdef HAVE_JNI_H
1912   if (ahc_init (plugin))
1913     init_ok = TRUE;
1914 
1915   if (ahs_init (plugin))
1916     init_ok = TRUE;
1917 #endif
1918 
1919   return init_ok;
1920 }
1921 
1922 void
gst_amc_codec_info_to_caps(const GstAmcCodecInfo * codec_info,GstCaps ** sink_caps,GstCaps ** src_caps)1923 gst_amc_codec_info_to_caps (const GstAmcCodecInfo * codec_info,
1924     GstCaps ** sink_caps, GstCaps ** src_caps)
1925 {
1926   GstCaps *raw_ret = NULL, *encoded_ret = NULL;
1927   gint i;
1928 
1929   if (codec_info->is_encoder) {
1930     if (sink_caps)
1931       *sink_caps = raw_ret = gst_caps_new_empty ();
1932 
1933     if (src_caps)
1934       *src_caps = encoded_ret = gst_caps_new_empty ();
1935   } else {
1936     if (sink_caps)
1937       *sink_caps = encoded_ret = gst_caps_new_empty ();
1938 
1939     if (src_caps)
1940       *src_caps = raw_ret = gst_caps_new_empty ();
1941   }
1942 
1943   for (i = 0; i < codec_info->n_supported_types; i++) {
1944     const GstAmcCodecType *type = &codec_info->supported_types[i];
1945     GstStructure *tmp, *tmp2, *tmp3;
1946 
1947     if (g_str_has_prefix (type->mime, "audio/")) {
1948       if (raw_ret) {
1949         tmp = gst_structure_new ("audio/x-raw",
1950             "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1951             "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1952             "format", G_TYPE_STRING, GST_AUDIO_NE (S16),
1953             "layout", G_TYPE_STRING, "interleaved", NULL);
1954 
1955         raw_ret = gst_caps_merge_structure (raw_ret, tmp);
1956       }
1957 
1958       if (encoded_ret) {
1959         if (strcmp (type->mime, "audio/mpeg") == 0) {
1960           tmp = gst_structure_new ("audio/mpeg",
1961               "mpegversion", G_TYPE_INT, 1,
1962               "layer", G_TYPE_INT, 3,
1963               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1964               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1965               "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
1966           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
1967         } else if (strcmp (type->mime, "audio/3gpp") == 0) {
1968           tmp = gst_structure_new ("audio/AMR",
1969               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1970               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
1971           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
1972         } else if (strcmp (type->mime, "audio/amr-wb") == 0) {
1973           tmp = gst_structure_new ("audio/AMR-WB",
1974               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1975               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
1976           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
1977         } else if (strcmp (type->mime, "audio/mp4a-latm") == 0) {
1978           gint j;
1979           gboolean have_profile = FALSE;
1980           GValue va = { 0, };
1981           GValue v = { 0, };
1982 
1983           g_value_init (&va, GST_TYPE_LIST);
1984           g_value_init (&v, G_TYPE_STRING);
1985           g_value_set_string (&v, "raw");
1986           gst_value_list_append_value (&va, &v);
1987           g_value_set_string (&v, "adts");
1988           gst_value_list_append_value (&va, &v);
1989           g_value_unset (&v);
1990 
1991           tmp = gst_structure_new ("audio/mpeg",
1992               "mpegversion", G_TYPE_INT, 4,
1993               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1994               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
1995               "framed", G_TYPE_BOOLEAN, TRUE, NULL);
1996           gst_structure_set_value (tmp, "stream-format", &va);
1997           g_value_unset (&va);
1998 
1999           for (j = 0; j < type->n_profile_levels; j++) {
2000             const gchar *profile;
2001 
2002             profile =
2003                 gst_amc_aac_profile_to_string (type->profile_levels[j].profile);
2004 
2005             if (!profile) {
2006               GST_ERROR ("Unable to map AAC profile 0x%08x",
2007                   type->profile_levels[j].profile);
2008               continue;
2009             }
2010 
2011             tmp2 = gst_structure_copy (tmp);
2012             gst_structure_set (tmp2, "profile", G_TYPE_STRING, profile, NULL);
2013             encoded_ret = gst_caps_merge_structure (encoded_ret, tmp2);
2014 
2015             have_profile = TRUE;
2016           }
2017 
2018           if (!have_profile) {
2019             encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2020           } else {
2021             gst_structure_free (tmp);
2022           }
2023         } else if (strcmp (type->mime, "audio/g711-alaw") == 0) {
2024           tmp = gst_structure_new ("audio/x-alaw",
2025               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
2026               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
2027           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2028         } else if (strcmp (type->mime, "audio/g711-mlaw") == 0) {
2029           tmp = gst_structure_new ("audio/x-mulaw",
2030               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
2031               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
2032           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2033         } else if (strcmp (type->mime, "audio/vorbis") == 0) {
2034           tmp = gst_structure_new ("audio/x-vorbis",
2035               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
2036               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
2037           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2038         } else if (strcmp (type->mime, "audio/opus") == 0) {
2039           tmp = gst_structure_new ("audio/x-opus",
2040               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
2041               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
2042           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2043         } else if (strcmp (type->mime, "audio/flac") == 0) {
2044           tmp = gst_structure_new ("audio/x-flac",
2045               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
2046               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
2047               "framed", G_TYPE_BOOLEAN, TRUE, NULL);
2048           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2049         } else if (strcmp (type->mime, "audio/mpeg-L2") == 0) {
2050           tmp = gst_structure_new ("audio/mpeg",
2051               "mpegversion", G_TYPE_INT, 1,
2052               "layer", G_TYPE_INT, 2,
2053               "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
2054               "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
2055               "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
2056           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2057         } else {
2058           GST_WARNING ("Unsupported mimetype '%s'", type->mime);
2059         }
2060       }
2061     } else if (g_str_has_prefix (type->mime, "video/")) {
2062       if (raw_ret) {
2063         gint j;
2064 
2065         for (j = 0; j < type->n_color_formats; j++) {
2066           GstVideoFormat format;
2067 
2068           /* Skip here without a warning, this is special and handled
2069            * in the decoder when doing rendering to a surface */
2070           if (type->color_formats[j] == COLOR_FormatAndroidOpaque)
2071             continue;
2072 
2073           format =
2074               gst_amc_color_format_to_video_format (codec_info,
2075               type->mime, type->color_formats[j]);
2076           if (format == GST_VIDEO_FORMAT_UNKNOWN) {
2077             GST_WARNING ("Unknown color format 0x%08x for codec %s",
2078                 type->color_formats[j], type->mime);
2079             continue;
2080           }
2081 
2082           tmp = gst_structure_new ("video/x-raw",
2083               "format", G_TYPE_STRING, gst_video_format_to_string (format),
2084               "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
2085               "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
2086               "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
2087 
2088           raw_ret = gst_caps_merge_structure (raw_ret, tmp);
2089         }
2090       }
2091 
2092       if (encoded_ret) {
2093         if (strcmp (type->mime, "video/mp4v-es") == 0) {
2094           gint j;
2095           gboolean have_profile_level = FALSE;
2096 
2097           tmp = gst_structure_new ("video/mpeg",
2098               "width", GST_TYPE_INT_RANGE, 16, 4096,
2099               "height", GST_TYPE_INT_RANGE, 16, 4096,
2100               "framerate", GST_TYPE_FRACTION_RANGE,
2101               0, 1, G_MAXINT, 1,
2102               "mpegversion", G_TYPE_INT, 4,
2103               "systemstream", G_TYPE_BOOLEAN, FALSE,
2104               "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
2105 
2106           if (type->n_profile_levels) {
2107             for (j = type->n_profile_levels - 1; j >= 0; j--) {
2108               const gchar *profile;
2109 
2110               profile =
2111                   gst_amc_mpeg4_profile_to_string (type->profile_levels[j].
2112                   profile);
2113               if (!profile) {
2114                 GST_ERROR ("Unable to map MPEG4 profile 0x%08x",
2115                     type->profile_levels[j].profile);
2116                 continue;
2117               }
2118 
2119               tmp2 = gst_structure_copy (tmp);
2120               gst_structure_set (tmp2, "profile", G_TYPE_STRING, profile, NULL);
2121 
2122               /* Don't put the level restrictions on the sinkpad caps for decoders,
2123                * see 2b94641a4 */
2124               if (codec_info->is_encoder) {
2125                 const gchar *level;
2126                 gint k;
2127                 GValue va = { 0, };
2128                 GValue v = { 0, };
2129 
2130                 g_value_init (&va, GST_TYPE_LIST);
2131                 g_value_init (&v, G_TYPE_STRING);
2132 
2133                 for (k = 1; k <= type->profile_levels[j].level && k != 0;
2134                     k <<= 1) {
2135                   level = gst_amc_mpeg4_level_to_string (k);
2136                   if (!level)
2137                     continue;
2138 
2139                   g_value_set_string (&v, level);
2140                   gst_value_list_append_value (&va, &v);
2141                   g_value_reset (&v);
2142                 }
2143 
2144                 gst_structure_set_value (tmp2, "level", &va);
2145                 g_value_unset (&va);
2146                 g_value_unset (&v);
2147               }
2148 
2149               encoded_ret = gst_caps_merge_structure (encoded_ret, tmp2);
2150               have_profile_level = TRUE;
2151             }
2152           }
2153 
2154           if (!have_profile_level) {
2155             encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2156           } else {
2157             gst_structure_free (tmp);
2158           }
2159 
2160           tmp = gst_structure_new ("video/x-divx",
2161               "width", GST_TYPE_INT_RANGE, 16, 4096,
2162               "height", GST_TYPE_INT_RANGE, 16, 4096,
2163               "framerate", GST_TYPE_FRACTION_RANGE,
2164               0, 1, G_MAXINT, 1,
2165               "divxversion", GST_TYPE_INT_RANGE, 3, 5,
2166               "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
2167           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2168         } else if (strcmp (type->mime, "video/3gpp") == 0) {
2169           gint j;
2170           gboolean have_profile_level = FALSE;
2171 
2172           tmp = gst_structure_new ("video/x-h263",
2173               "width", GST_TYPE_INT_RANGE, 16, 4096,
2174               "height", GST_TYPE_INT_RANGE, 16, 4096,
2175               "framerate", GST_TYPE_FRACTION_RANGE,
2176               0, 1, G_MAXINT, 1,
2177               "parsed", G_TYPE_BOOLEAN, TRUE,
2178               "variant", G_TYPE_STRING, "itu", NULL);
2179 
2180           if (type->n_profile_levels) {
2181             for (j = type->n_profile_levels - 1; j >= 0; j--) {
2182               gint profile;
2183 
2184               profile =
2185                   gst_amc_h263_profile_to_gst_id (type->profile_levels[j].
2186                   profile);
2187 
2188               if (profile == -1) {
2189                 GST_ERROR ("Unable to map h263 profile 0x%08x",
2190                     type->profile_levels[j].profile);
2191                 continue;
2192               }
2193 
2194               tmp2 = gst_structure_copy (tmp);
2195               gst_structure_set (tmp2, "profile", G_TYPE_UINT, profile, NULL);
2196 
2197               if (codec_info->is_encoder) {
2198                 gint k;
2199                 gint level;
2200                 GValue va = { 0, };
2201                 GValue v = { 0, };
2202 
2203                 g_value_init (&va, GST_TYPE_LIST);
2204                 g_value_init (&v, G_TYPE_UINT);
2205 
2206                 for (k = 1; k <= type->profile_levels[j].level && k != 0;
2207                     k <<= 1) {
2208                   level = gst_amc_h263_level_to_gst_id (k);
2209                   if (level == -1)
2210                     continue;
2211 
2212                   g_value_set_uint (&v, level);
2213                   gst_value_list_append_value (&va, &v);
2214                   g_value_reset (&v);
2215                 }
2216 
2217                 gst_structure_set_value (tmp2, "level", &va);
2218                 g_value_unset (&va);
2219                 g_value_unset (&v);
2220               }
2221 
2222               encoded_ret = gst_caps_merge_structure (encoded_ret, tmp2);
2223               have_profile_level = TRUE;
2224             }
2225           }
2226 
2227           if (!have_profile_level) {
2228             encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2229           } else {
2230             gst_structure_free (tmp);
2231           }
2232         } else if (strcmp (type->mime, "video/avc") == 0) {
2233           gint j;
2234           gboolean have_profile_level = FALSE;
2235 
2236           tmp = gst_structure_new ("video/x-h264",
2237               "width", GST_TYPE_INT_RANGE, 16, 4096,
2238               "height", GST_TYPE_INT_RANGE, 16, 4096,
2239               "framerate", GST_TYPE_FRACTION_RANGE,
2240               0, 1, G_MAXINT, 1,
2241               "parsed", G_TYPE_BOOLEAN, TRUE,
2242               "stream-format", G_TYPE_STRING, "byte-stream",
2243               "alignment", G_TYPE_STRING, "au", NULL);
2244 
2245           if (type->n_profile_levels) {
2246             for (j = type->n_profile_levels - 1; j >= 0; j--) {
2247               const gchar *profile, *alternative = NULL;
2248 
2249               profile =
2250                   gst_amc_avc_profile_to_string (type->profile_levels[j].
2251                   profile, &alternative);
2252 
2253               if (!profile) {
2254                 GST_ERROR ("Unable to map H264 profile 0x%08x",
2255                     type->profile_levels[j].profile);
2256                 continue;
2257               }
2258 
2259               tmp2 = gst_structure_copy (tmp);
2260               gst_structure_set (tmp2, "profile", G_TYPE_STRING, profile, NULL);
2261 
2262               if (alternative) {
2263                 tmp3 = gst_structure_copy (tmp);
2264                 gst_structure_set (tmp3, "profile", G_TYPE_STRING, alternative,
2265                     NULL);
2266               } else
2267                 tmp3 = NULL;
2268 
2269               if (codec_info->is_encoder) {
2270                 const gchar *level;
2271                 gint k;
2272                 GValue va = { 0, };
2273                 GValue v = { 0, };
2274 
2275                 g_value_init (&va, GST_TYPE_LIST);
2276                 g_value_init (&v, G_TYPE_STRING);
2277                 for (k = 1; k <= type->profile_levels[j].level && k != 0;
2278                     k <<= 1) {
2279                   level = gst_amc_avc_level_to_string (k);
2280                   if (!level)
2281                     continue;
2282 
2283                   g_value_set_string (&v, level);
2284                   gst_value_list_append_value (&va, &v);
2285                   g_value_reset (&v);
2286                 }
2287 
2288                 gst_structure_set_value (tmp2, "level", &va);
2289                 if (tmp3)
2290                   gst_structure_set_value (tmp3, "level", &va);
2291 
2292                 g_value_unset (&va);
2293                 g_value_unset (&v);
2294               }
2295 
2296               encoded_ret = gst_caps_merge_structure (encoded_ret, tmp2);
2297               if (tmp3)
2298                 encoded_ret = gst_caps_merge_structure (encoded_ret, tmp3);
2299               have_profile_level = TRUE;
2300             }
2301           }
2302 
2303           if (!have_profile_level) {
2304             encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2305           } else {
2306             gst_structure_free (tmp);
2307           }
2308         } else if (strcmp (type->mime, "video/hevc") == 0) {
2309           gint j;
2310           gboolean have_profile_level = FALSE;
2311 
2312           tmp = gst_structure_new ("video/x-h265",
2313               "width", GST_TYPE_INT_RANGE, 16, 4096,
2314               "height", GST_TYPE_INT_RANGE, 16, 4096,
2315               "framerate", GST_TYPE_FRACTION_RANGE,
2316               0, 1, G_MAXINT, 1,
2317               "parsed", G_TYPE_BOOLEAN, TRUE,
2318               "stream-format", G_TYPE_STRING, "byte-stream",
2319               "alignment", G_TYPE_STRING, "au", NULL);
2320 
2321           if (type->n_profile_levels) {
2322             for (j = type->n_profile_levels - 1; j >= 0; j--) {
2323               const gchar *profile;
2324 
2325               profile =
2326                   gst_amc_hevc_profile_to_string (type->profile_levels[j].
2327                   profile);
2328 
2329               if (!profile) {
2330                 GST_ERROR ("Unable to map H265 profile 0x%08x",
2331                     type->profile_levels[j].profile);
2332                 continue;
2333               }
2334 
2335               tmp2 = gst_structure_copy (tmp);
2336               gst_structure_set (tmp2, "profile", G_TYPE_STRING, profile, NULL);
2337 
2338               if (codec_info->is_encoder) {
2339                 const gchar *level, *tier;
2340                 gint k;
2341                 GValue v = { 0, };
2342 
2343                 g_value_init (&v, G_TYPE_STRING);
2344                 for (k = 1; k <= type->profile_levels[j].level && k != 0;
2345                     k <<= 1) {
2346                   level = gst_amc_hevc_tier_level_to_string (k, &tier);
2347                   if (!level || !tier)
2348                     continue;
2349 
2350                   tmp3 = gst_structure_copy (tmp2);
2351 
2352                   g_value_set_string (&v, tier);
2353                   gst_structure_set_value (tmp3, "tier", &v);
2354                   g_value_reset (&v);
2355 
2356                   g_value_set_string (&v, level);
2357                   gst_structure_set_value (tmp3, "level", &v);
2358                   g_value_reset (&v);
2359 
2360                   encoded_ret = gst_caps_merge_structure (encoded_ret, tmp3);
2361 
2362                   have_profile_level = TRUE;
2363                 }
2364               }
2365 
2366               if (have_profile_level) {
2367                 gst_structure_free (tmp2);
2368               } else {
2369                 encoded_ret = gst_caps_merge_structure (encoded_ret, tmp2);
2370               }
2371 
2372               have_profile_level = TRUE;
2373             }
2374           }
2375 
2376           if (!have_profile_level) {
2377             encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2378           } else {
2379             gst_structure_free (tmp);
2380           }
2381         } else if (strcmp (type->mime, "video/x-vnd.on2.vp8") == 0) {
2382           tmp = gst_structure_new ("video/x-vp8",
2383               "width", GST_TYPE_INT_RANGE, 16, 4096,
2384               "height", GST_TYPE_INT_RANGE, 16, 4096,
2385               "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
2386 
2387           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2388         } else if (strcmp (type->mime, "video/x-vnd.on2.vp9") == 0) {
2389           tmp = gst_structure_new ("video/x-vp9",
2390               "width", GST_TYPE_INT_RANGE, 16, 4096,
2391               "height", GST_TYPE_INT_RANGE, 16, 4096,
2392               "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
2393 
2394           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2395         } else if (strcmp (type->mime, "video/mpeg2") == 0) {
2396           tmp = gst_structure_new ("video/mpeg",
2397               "width", GST_TYPE_INT_RANGE, 16, 4096,
2398               "height", GST_TYPE_INT_RANGE, 16, 4096,
2399               "framerate", GST_TYPE_FRACTION_RANGE,
2400               0, 1, G_MAXINT, 1,
2401               "mpegversion", GST_TYPE_INT_RANGE, 1, 2,
2402               "systemstream", G_TYPE_BOOLEAN, FALSE,
2403               "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
2404 
2405           encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
2406         } else {
2407           GST_WARNING ("Unsupported mimetype '%s'", type->mime);
2408         }
2409       }
2410     }
2411   }
2412 
2413   GST_DEBUG ("Returning caps for '%s':", codec_info->name);
2414   GST_DEBUG ("  raw caps: %" GST_PTR_FORMAT, raw_ret);
2415   GST_DEBUG ("  encoded caps: %" GST_PTR_FORMAT, encoded_ret);
2416 }
2417 
2418 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2419     GST_VERSION_MINOR,
2420     PLUGIN_NAME,
2421     PLUGIN_DESCRIPTION,
2422     plugin_init,
2423     PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
2424