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