Some more WIP

Scanning all codecs now and have data structures for holding codec
information and codec contexts. Also function declarations for
working with them.
This commit is contained in:
Sebastian Dröge 2012-08-15 18:23:34 +02:00
parent 8f232ea90b
commit f99214a657
2 changed files with 611 additions and 5 deletions

View file

@ -37,7 +37,7 @@ static jint (*get_created_java_vms) (JavaVM ** vmBuf, jsize bufLen,
static jint (*create_java_vm) (JavaVM ** p_vm, JNIEnv ** p_env, void *vm_args);
static JavaVM *java_vm;
JNIEnv *
static JNIEnv *
gst_amc_attach_current_thread (void)
{
JNIEnv *env;
@ -47,7 +47,7 @@ gst_amc_attach_current_thread (void)
args.name = NULL;
args.group = NULL;
if ((*java_vm)->AttachCurrentThread (java_vm, (void **) &env, &args) < 0) {
if ((*java_vm)->AttachCurrentThread (java_vm, &env, &args) < 0) {
GST_ERROR ("Failed to attach current thread");
return NULL;
}
@ -55,7 +55,7 @@ gst_amc_attach_current_thread (void)
return env;
}
void
static void
gst_amc_detach_current_thread (void)
{
(*java_vm)->DetachCurrentThread (java_vm);
@ -131,6 +131,526 @@ create_failed:
}
}
GstAmcCodec *
gst_amc_codec_new (const gchar * name)
{
return NULL;
}
void
gst_amc_codec_free (GstAmcCodec * codec)
{
}
void
gst_amc_codec_configure (GstAmcCodec * codec, gint flags)
{
}
GstAmcFormat *
gst_amc_codec_get_output_format (GstAmcCodec * codec)
{
return NULL;
}
void
gst_amc_codec_start (GstAmcCodec * codec)
{
}
void
gst_amc_codec_stop (GstAmcCodec * codec)
{
}
void
gst_amc_codec_flush (GstAmcCodec * codec)
{
}
GstAmcBuffer *
gst_amc_codec_get_output_buffers (GstAmcCodec * codec, gsize * n_buffers)
{
return NULL;
}
GstAmcBuffer *
gst_amc_codec_get_input_buffers (GstAmcCodec * codec, gsize * n_buffers)
{
return NULL;
}
gint
gst_amc_codec_dequeue_input_buffer (GstAmcCodec * codec, gint64 timeoutUs)
{
return -1;
}
gint
gst_amc_codec_dequeue_output_buffer (GstAmcCodec * codec,
GstAmcBufferInfo * info, gint64 timeoutUs)
{
return -1;
}
void
gst_amc_codec_queue_input_buffer (GstAmcCodec * codec, gint index,
const GstAmcBufferInfo * info)
{
}
void
gst_amc_codec_release_output_buffer (GstAmcCodec * codec, gint index)
{
}
GstAmcFormat *
gst_amc_format_new_audio (const gchar * mime, gint sample_rate, gint channels)
{
return NULL;
}
GstAmcFormat *
gst_amc_format_new_video (const gchar * mime, gint width, gint height)
{
return NULL;
}
void
gst_amc_format_free (GstAmcFormat * format)
{
}
gboolean
gst_amc_format_contains_key (GstAmcFormat * format, const gchar * key)
{
return FALSE;
}
gboolean
gst_amc_format_get_float (GstAmcFormat * format, const gchar * key,
gfloat * value)
{
return FALSE;
}
void
gst_amc_format_set_float (GstAmcFormat * format, const gchar * key,
gfloat * value)
{
}
gboolean
gst_amc_format_get_int (GstAmcFormat * format, const gchar * key, gint * value)
{
return FALSE;
}
void
gst_amc_format_set_int (GstAmcFormat * format, const gchar * key, gint * value)
{
}
gboolean
gst_amc_format_get_string (GstAmcFormat * format, const gchar * key,
gchar ** value)
{
return FALSE;
}
void
gst_amc_format_set_string (GstAmcFormat * format, const gchar * key,
const gchar * value)
{
}
static GList *codec_infos = NULL;
static gboolean
register_codecs (void)
{
gboolean ret = TRUE;
JNIEnv *env;
jclass codec_list_class = NULL;
jmethodID get_codec_count_id, get_codec_info_at_id;
jint codec_count, i;
env = gst_amc_attach_current_thread ();
codec_list_class = (*env)->FindClass (env, "android/media/MediaCodecList");
if (!codec_list_class) {
ret = FALSE;
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get codec list class");
goto done;
}
get_codec_count_id =
(*env)->GetStaticMethodID (env, codec_list_class, "getCodecCount", "()I");
get_codec_info_at_id =
(*env)->GetStaticMethodID (env, codec_list_class, "getCodecInfoAt",
"(I)Landroid/media/MediaCodecInfo;");
if (!get_codec_count_id || !get_codec_info_at_id) {
ret = FALSE;
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get codec list method IDs");
goto done;
}
codec_count =
(*env)->CallStaticIntMethod (env, codec_list_class, get_codec_count_id);
if ((*env)->ExceptionCheck (env)) {
ret = FALSE;
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get number of available codecs");
goto done;
}
GST_LOG ("Found %d available codecs", codec_count);
for (i = 0; i < codec_count; i++) {
GstAmcCodecInfo *gst_codec_info;
jobject codec_info = NULL;
jclass codec_info_class = NULL;
jmethodID get_capabilities_for_type_id, get_name_id;
jmethodID get_supported_types_id, is_encoder_id;
jobject name = NULL;
const gchar *name_str = NULL;
jboolean is_encoder;
jarray supported_types = NULL;
jsize n_supported_types;
jsize j;
gboolean valid_type = FALSE;
gst_codec_info = g_new0 (GstAmcCodecInfo, 1);
codec_info =
(*env)->CallStaticObjectMethod (env, codec_list_class,
get_codec_info_at_id, i);
if ((*env)->ExceptionCheck (env) || !codec_info) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get codec info %d", i);
goto next_codec;
}
codec_info_class = (*env)->GetObjectClass (env, codec_info);
if (!codec_list_class) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get codec info class");
goto next_codec;
}
get_capabilities_for_type_id =
(*env)->GetMethodID (env, codec_info_class, "getCapabilitiesForType",
"(Ljava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;");
get_name_id =
(*env)->GetMethodID (env, codec_info_class, "getName",
"()Ljava/lang/String;");
get_supported_types_id =
(*env)->GetMethodID (env, codec_info_class, "getSupportedTypes",
"()[Ljava/lang/String;");
is_encoder_id =
(*env)->GetMethodID (env, codec_info_class, "isEncoder", "()Z");
if (!get_capabilities_for_type_id || !get_name_id
|| !get_supported_types_id || !is_encoder_id) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get codec info method IDs");
goto next_codec;
}
name = (*env)->CallObjectMethod (env, codec_info, get_name_id);
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get codec name");
goto next_codec;
}
name_str = (*env)->GetStringUTFChars (env, name, NULL);
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to convert codec name to UTF8");
goto next_codec;
}
GST_INFO ("Checking codec '%s'", name_str);
/* Compatibility codec names */
if (strcmp (name_str, "AACEncoder") == 0 ||
strcmp (name_str, "OMX.google.raw.decoder") == 0) {
GST_INFO ("Skipping compatibility codec '%s'", name_str);
goto next_codec;
}
gst_codec_info->name = g_strdup (name_str);
is_encoder = (*env)->CallBooleanMethod (env, codec_info, is_encoder_id);
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to detect if codec is an encoder");
goto next_codec;
}
gst_codec_info->is_encoder = is_encoder;
supported_types =
(*env)->CallObjectMethod (env, codec_info, get_supported_types_id);
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get supported types");
goto next_codec;
}
n_supported_types = (*env)->GetArrayLength (env, supported_types);
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get supported types array length");
goto next_codec;
}
GST_INFO ("Codec '%s' has %d supported types", name_str, n_supported_types);
gst_codec_info->supported_types = g_new0 (GstAmcCodecType, 1);
gst_codec_info->n_supported_types = n_supported_types;
for (j = 0; j < n_supported_types; j++) {
GstAmcCodecType *gst_codec_type;
jobject supported_type = NULL;
const gchar *supported_type_str = NULL;
jobject capabilities = NULL;
jclass capabilities_class = NULL;
jfieldID color_formats_id, profile_levels_id;
jobject color_formats = NULL;
jobject profile_levels = NULL;
jint *color_formats_elems = NULL;
jsize n_elems, k;
gst_codec_type = &gst_codec_info->supported_types[j];
supported_type = (*env)->GetObjectArrayElement (env, supported_types, j);
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get %d-th supported type", j);
goto next_supported_type;
}
supported_type_str =
(*env)->GetStringUTFChars (env, supported_type, NULL);
if ((*env)->ExceptionCheck (env) || !supported_type_str) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to convert supported type to UTF8");
goto next_supported_type;
}
GST_INFO ("Supported type '%s'", supported_type_str);
gst_codec_type->mime = g_strdup (supported_type_str);
valid_type = TRUE;
capabilities =
(*env)->CallObjectMethod (env, codec_info,
get_capabilities_for_type_id, supported_type);
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get capabilities for supported type");
goto next_supported_type;
}
capabilities_class = (*env)->GetObjectClass (env, capabilities);
if (!capabilities_class) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get capabilities class");
goto next_supported_type;
}
color_formats_id =
(*env)->GetFieldID (env, capabilities_class, "colorFormats", "[I");
profile_levels_id =
(*env)->GetFieldID (env, capabilities_class, "profileLevels",
"[Landroid/media/MediaCodecInfo$CodecProfileLevel;");
if (!color_formats_id || !profile_levels_id) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get capabilities field IDs");
goto next_supported_type;
}
color_formats =
(*env)->GetObjectField (env, capabilities, color_formats_id);
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get color formats");
goto next_supported_type;
}
n_elems = (*env)->GetArrayLength (env, color_formats);
gst_codec_type->n_color_formats = n_elems;
gst_codec_type->color_formats = g_new0 (gint, n_elems);
color_formats_elems =
(*env)->GetIntArrayElements (env, color_formats, NULL);
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get color format elements");
goto next_supported_type;
}
for (k = 0; k < n_elems; k++) {
GST_INFO ("Color format %d: %d", k, color_formats_elems[k]);
gst_codec_type->color_formats[k] = color_formats_elems[k];
}
profile_levels =
(*env)->GetObjectField (env, capabilities, profile_levels_id);
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get profile/levels");
goto next_supported_type;
}
n_elems = (*env)->GetArrayLength (env, profile_levels);
gst_codec_type->n_profile_levels = n_elems;
gst_codec_type->profile_levels =
g_malloc0 (sizeof (gst_codec_type->profile_levels) * n_elems);
for (k = 0; k < n_elems; k++) {
jobject profile_level = NULL;
jclass profile_level_class = NULL;
jfieldID level_id, profile_id;
jint level, profile;
profile_level = (*env)->GetObjectArrayElement (env, profile_levels, k);
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get %d-th profile/level", k);
goto next_profile_level;
}
profile_level_class = (*env)->GetObjectClass (env, profile_level);
if (!profile_level_class) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get profile/level class");
goto next_profile_level;
}
level_id = (*env)->GetFieldID (env, profile_level_class, "level", "I");
profile_id =
(*env)->GetFieldID (env, profile_level_class, "profile", "I");
if (!level_id || !profile_id) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get profile/level field IDs");
goto next_profile_level;
}
level = (*env)->GetIntField (env, profile_level, level_id);
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get level");
goto next_profile_level;
}
GST_INFO ("Level %d: 0x%08x", k, level);
gst_codec_type->profile_levels[k].level = level;
profile = (*env)->GetIntField (env, profile_level, profile_id);
if ((*env)->ExceptionCheck (env)) {
(*env)->ExceptionClear (env);
GST_ERROR ("Failed to get profile");
goto next_profile_level;
}
GST_INFO ("Profile %d: 0x%08x", k, profile);
gst_codec_type->profile_levels[k].profile = profile;
next_profile_level:
if (profile_level)
(*env)->DeleteLocalRef (env, profile_level);
profile_level = NULL;
if (profile_level_class)
(*env)->DeleteLocalRef (env, profile_level_class);
profile_level_class = NULL;
}
next_supported_type:
if (color_formats_elems)
(*env)->ReleaseIntArrayElements (env, color_formats,
color_formats_elems, JNI_ABORT);
color_formats_elems = NULL;
if (color_formats)
(*env)->DeleteLocalRef (env, color_formats);
color_formats = NULL;
if (profile_levels)
(*env)->DeleteLocalRef (env, profile_levels);
color_formats = NULL;
if (capabilities)
(*env)->DeleteLocalRef (env, capabilities);
capabilities = NULL;
if (capabilities_class)
(*env)->DeleteLocalRef (env, capabilities_class);
capabilities_class = NULL;
if (supported_type_str)
(*env)->ReleaseStringUTFChars (env, supported_type, supported_type_str);
supported_type_str = NULL;
if (supported_type)
(*env)->DeleteLocalRef (env, supported_type);
supported_type = NULL;
}
/* We need at least a valid supported type */
if (valid_type) {
GST_LOG ("Successfully scanned codec '%s'", name_str);
codec_infos = g_list_append (codec_infos, gst_codec_info);
gst_codec_info = NULL;
}
/* Clean up of all local references we got */
next_codec:
if (name_str)
(*env)->ReleaseStringUTFChars (env, name, name_str);
name_str = NULL;
if (name)
(*env)->DeleteLocalRef (env, name);
name = NULL;
if (supported_types)
(*env)->DeleteLocalRef (env, supported_types);
supported_types = NULL;
if (codec_info)
(*env)->DeleteLocalRef (env, codec_info);
codec_info = NULL;
if (codec_info_class)
(*env)->DeleteLocalRef (env, codec_info_class);
codec_info_class = NULL;
if (gst_codec_info) {
gint j;
for (j = 0; j < gst_codec_info->n_supported_types; j++) {
GstAmcCodecType *gst_codec_type = &gst_codec_info->supported_types[j];
g_free (gst_codec_type->mime);
g_free (gst_codec_type->color_formats);
g_free (gst_codec_type->profile_levels);
}
g_free (gst_codec_info->supported_types);
g_free (gst_codec_info->name);
g_free (gst_codec_info);
}
gst_codec_info = NULL;
valid_type = FALSE;
}
ret = codec_infos != NULL;
done:
if (codec_list_class)
(*env)->DeleteLocalRef (env, codec_list_class);
gst_amc_detach_current_thread ();
return ret;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
@ -139,6 +659,9 @@ plugin_init (GstPlugin * plugin)
if (!initialize_java_vm ())
return FALSE;
if (!register_codecs ())
return FALSE;
return TRUE;
}

View file

@ -26,8 +26,91 @@
G_BEGIN_DECLS
JNIEnv * gst_amc_attach_current_thread (void);
void gst_amc_detach_current_thread (void);
typedef struct _GstAmcCodecInfo GstAmcCodecInfo;
typedef struct _GstAmcCodecType GstAmcCodecType;
typedef struct _GstAmcCodec GstAmcCodec;
typedef struct _GstAmcCodecBufferInfo GstAmcBufferInfo;
typedef struct _GstAmcFormat GstAmcFormat;
typedef struct _GstAmcBuffer GstAmcBuffer;
struct _GstAmcCodecType {
gchar *mime;
gint *color_formats;
gint n_color_formats;
struct {
gint profile;
gint level;
} *profile_levels;
gint n_profile_levels;
};
struct _GstAmcCodecInfo {
gchar *name;
gboolean is_encoder;
GstAmcCodecType *supported_types;
gint n_supported_types;
};
struct _GstAmcBuffer {
guint8 *data;
gsize len;
};
struct _GstAmcFormat {
/* < private > */
jobject format; /* global reference */
jclass format_class; /* global reference */
};
struct _GstAmcCodec {
/* < private > */
jobject codec; /* global reference */
jclass codec_class; /* global reference */
};
struct _GstAmcBufferInfo {
gint flags;
gint offset;
gint64 presentationTimeUs;
gint size;
};
GstAmcCodec * gst_amc_codec_new (const gchar *name);
void gst_amc_codec_free (GstAmcCodec * codec);
void gst_amc_codec_configure (GstAmcCodec * codec, gint flags);
GstAmcFormat * gst_amc_codec_get_output_format (GstAmcCodec * codec);
void gst_amc_codec_start (GstAmcCodec * codec);
void gst_amc_codec_stop (GstAmcCodec * codec);
void gst_amc_codec_flush (GstAmcCodec * codec);
GstAmcBuffer * gst_amc_codec_get_output_buffers (GstAmcCodec * codec, gsize * n_buffers);
GstAmcBuffer * gst_amc_codec_get_input_buffers (GstAmcCodec * codec, gsize * n_buffers);
gint gst_amc_codec_dequeue_input_buffer (GstAmcCodec * codec, gint64 timeoutUs);
gint gst_amc_codec_dequeue_output_buffer (GstAmcCodec * codec, GstAmcBufferInfo *info, gint64 timeoutUs);
void gst_amc_codec_queue_input_buffer (GstAmcCodec * codec, gint index, const GstAmcBufferInfo *info);
void gst_amc_codec_release_output_buffer (GstAmcCodec * codec, gint index);
GstAmcFormat * gst_amc_format_new_audio (const gchar *mime, gint sample_rate, gint channels);
GstAmcFormat * gst_amc_format_new_video (const gchar *mime, gint width, gint height);
void gst_amc_format_free (GstAmcFormat * format);
gboolean gst_amc_format_contains_key (GstAmcFormat *format, const gchar *key);
gboolean gst_amc_format_get_float (GstAmcFormat *format, const gchar *key, gfloat *value);
void gst_amc_format_set_float (GstAmcFormat *format, const gchar *key, gfloat *value);
gboolean gst_amc_format_get_int (GstAmcFormat *format, const gchar *key, gint *value);
void gst_amc_format_set_int (GstAmcFormat *format, const gchar *key, gint *value);
gboolean gst_amc_format_get_string (GstAmcFormat *format, const gchar *key, gchar **value);
void gst_amc_format_set_string (GstAmcFormat *format, const gchar *key, const gchar *value);
G_END_DECLS