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