diff options
author | Sebastian Dröge <sebastian.droege@collabora.co.uk> | 2012-10-18 16:41:07 +0200 |
---|---|---|
committer | Sebastian Dröge <sebastian.droege@collabora.co.uk> | 2012-10-25 14:05:48 +0200 |
commit | 079c68e4de878390304da28330c149508448fa6e (patch) | |
tree | a455dac4255b3590c194328db68b58d98e469da4 /sys/androidmedia | |
parent | 36680b1190b3ddbe733e526e870ce9e904b129c4 (diff) | |
download | gstreamer-plugins-bad-079c68e4de878390304da28330c149508448fa6e.tar.gz |
androidmedia: Port to 1.0
Diffstat (limited to 'sys/androidmedia')
-rw-r--r-- | sys/androidmedia/Makefile.am | 2 | ||||
-rw-r--r-- | sys/androidmedia/gstamc.c | 68 | ||||
-rw-r--r-- | sys/androidmedia/gstamc.h | 8 | ||||
-rw-r--r-- | sys/androidmedia/gstamcaudiodec.c | 230 | ||||
-rw-r--r-- | sys/androidmedia/gstamcaudiodec.h | 10 | ||||
-rw-r--r-- | sys/androidmedia/gstamcvideodec.c | 307 | ||||
-rw-r--r-- | sys/androidmedia/gstamcvideodec.h | 3 |
7 files changed, 345 insertions, 283 deletions
diff --git a/sys/androidmedia/Makefile.am b/sys/androidmedia/Makefile.am index 283488f95..fba8777ce 100644 --- a/sys/androidmedia/Makefile.am +++ b/sys/androidmedia/Makefile.am @@ -25,7 +25,7 @@ libgstandroidmedia_la_LIBADD = \ $(GST_LIBS) \ $(ORC_LIBS) libgstandroidmedia_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -libgstandroidmedia_la_LIBTOOLFLAGS = --tag=disable-static +libgstandroidmedia_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) Android.mk: Makefile.am $(BUILT_SOURCES) androgenizer \ diff --git a/sys/androidmedia/gstamc.c b/sys/androidmedia/gstamc.c index 205b8502f..a1153b5a6 100644 --- a/sys/androidmedia/gstamc.c +++ b/sys/androidmedia/gstamc.c @@ -28,6 +28,7 @@ #include "gstamcvideodec.h" #include "gstamcaudiodec.h" +#include <gmodule.h> #include <gst/gst.h> #include <gst/video/video.h> #include <gst/audio/audio.h> @@ -1169,20 +1170,20 @@ done: gboolean gst_amc_format_get_buffer (GstAmcFormat * format, const gchar * key, - GstBuffer ** value) + guint8 ** data, gsize * size) { JNIEnv *env; gboolean ret = FALSE; jstring key_str = NULL; jobject v = NULL; - guint8 *data; - gsize size; g_return_val_if_fail (format != NULL, FALSE); g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (size != NULL, FALSE); - *value = 0; + *data = NULL; + *size = 0; env = gst_amc_get_jni_env (); key_str = (*env)->NewStringUTF (env, key); @@ -1197,15 +1198,14 @@ gst_amc_format_get_buffer (GstAmcFormat * format, const gchar * key, goto done; } - data = (*env)->GetDirectBufferAddress (env, v); + *data = (*env)->GetDirectBufferAddress (env, v); if (!data) { (*env)->ExceptionClear (env); GST_ERROR ("Failed to get buffer address"); goto done; } - size = (*env)->GetDirectBufferCapacity (env, v); - *value = gst_buffer_new_and_alloc (size); - memcpy (GST_BUFFER_DATA (*value), data, size); + *size = (*env)->GetDirectBufferCapacity (env, v); + *data = g_memdup (*data, *size); ret = TRUE; @@ -1220,7 +1220,7 @@ done: void gst_amc_format_set_buffer (GstAmcFormat * format, const gchar * key, - GstBuffer * value) + guint8 * data, gsize size) { JNIEnv *env; jstring key_str = NULL; @@ -1228,7 +1228,7 @@ gst_amc_format_set_buffer (GstAmcFormat * format, const gchar * key, g_return_if_fail (format != NULL); g_return_if_fail (key != NULL); - g_return_if_fail (value != NULL); + g_return_if_fail (data != NULL); env = gst_amc_get_jni_env (); @@ -1236,9 +1236,8 @@ gst_amc_format_set_buffer (GstAmcFormat * format, const gchar * key, if (!key_str) goto done; - /* FIXME: The buffer must remain valid until the codec is stopped */ - v = (*env)->NewDirectByteBuffer (env, GST_BUFFER_DATA (value), - GST_BUFFER_SIZE (value)); + /* FIXME: The memory must remain valid until the codec is stopped */ + v = (*env)->NewDirectByteBuffer (env, data, size); if (!v) goto done; @@ -2016,7 +2015,7 @@ scan_codecs (GstPlugin * plugin) * number is limited by 64 in Android). */ if (ret) { - GstStructure *new_cache_data = gst_structure_empty_new ("gst-amc-cache"); + GstStructure *new_cache_data = gst_structure_new_empty ("gst-amc-cache"); GList *l; GValue arr = { 0, }; @@ -2025,7 +2024,7 @@ scan_codecs (GstPlugin * plugin) for (l = codec_infos; l; l = l->next) { GstAmcCodecInfo *gst_codec_info = l->data; GValue cv = { 0, }; - GstStructure *cs = gst_structure_empty_new ("gst-amc-codec"); + GstStructure *cs = gst_structure_new_empty ("gst-amc-codec"); GValue starr = { 0, }; gint i; @@ -2036,7 +2035,7 @@ scan_codecs (GstPlugin * plugin) for (i = 0; i < gst_codec_info->n_supported_types; i++) { GstAmcCodecType *gst_codec_type = &gst_codec_info->supported_types[i]; - GstStructure *sts = gst_structure_empty_new ("gst-amc-supported-type"); + GstStructure *sts = gst_structure_new_empty ("gst-amc-supported-type"); GValue stv = { 0, }; GValue tmparr = { 0, }; gint j; @@ -2497,7 +2496,7 @@ static const struct CHANNEL_OUT_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT}, { CHANNEL_OUT_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, { CHANNEL_OUT_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, { - CHANNEL_OUT_LOW_FREQUENCY, GST_AUDIO_CHANNEL_POSITION_LFE}, { + CHANNEL_OUT_LOW_FREQUENCY, GST_AUDIO_CHANNEL_POSITION_LFE1}, { CHANNEL_OUT_BACK_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT}, { CHANNEL_OUT_BACK_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, { CHANNEL_OUT_FRONT_LEFT_OF_CENTER, @@ -2516,21 +2515,21 @@ static const struct CHANNEL_OUT_TOP_BACK_RIGHT, GST_AUDIO_CHANNEL_POSITION_INVALID} }; -GstAudioChannelPosition * -gst_amc_audio_channel_mask_to_positions (guint32 channel_mask, gint channels) +gboolean +gst_amc_audio_channel_mask_to_positions (guint32 channel_mask, gint channels, + GstAudioChannelPosition * pos) { - GstAudioChannelPosition *pos = g_new0 (GstAudioChannelPosition, channels); gint i, j; if (channel_mask == 0) { if (channels == 1) { - pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_MONO; - return pos; + pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO; + return TRUE; } if (channels == 2) { pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT; pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT; - return pos; + return TRUE; } /* Now let the guesswork begin, these are the @@ -2567,10 +2566,10 @@ gst_amc_audio_channel_mask_to_positions (guint32 channel_mask, gint channels) if ((channel_mask & channel_mapping_table[i].mask)) { pos[j++] = channel_mapping_table[i].pos; if (channel_mapping_table[i].pos == GST_AUDIO_CHANNEL_POSITION_INVALID) { - g_free (pos); + memset (pos, 0, sizeof (GstAudioChannelPosition) * channels); GST_ERROR ("Unable to map channel mask 0x%08x", channel_mapping_table[i].mask); - return NULL; + return FALSE; } if (j == channels) break; @@ -2578,13 +2577,13 @@ gst_amc_audio_channel_mask_to_positions (guint32 channel_mask, gint channels) } if (j != channels) { - g_free (pos); + memset (pos, 0, sizeof (GstAudioChannelPosition) * channels); GST_ERROR ("Unable to map all channel positions in mask 0x%08x", channel_mask); - return NULL; + return FALSE; } - return pos; + return TRUE; } guint32 @@ -2813,18 +2812,9 @@ plugin_init (GstPlugin * plugin) return TRUE; } -#ifdef GST_PLUGIN_DEFINE2 -GST_PLUGIN_DEFINE2 (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - androidmedia, - "Android Media plugin", - plugin_init, - PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) -#else GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, - "androidmedia", + androidmedia, "Android Media plugin", plugin_init, PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) -#endif diff --git a/sys/androidmedia/gstamc.h b/sys/androidmedia/gstamc.h index 9568b4939..b48a3ee7c 100644 --- a/sys/androidmedia/gstamc.h +++ b/sys/androidmedia/gstamc.h @@ -23,7 +23,7 @@ #include <gst/gst.h> #include <gst/video/video.h> -#include <gst/audio/multichannel.h> +#include <gst/audio/audio.h> #include <jni.h> G_BEGIN_DECLS @@ -116,8 +116,8 @@ gboolean gst_amc_format_get_int (GstAmcFormat *format, const gchar *key, gint *v 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); -gboolean gst_amc_format_get_buffer (GstAmcFormat *format, const gchar *key, GstBuffer **value); -void gst_amc_format_set_buffer (GstAmcFormat *format, const gchar *key, GstBuffer *value); +gboolean gst_amc_format_get_buffer (GstAmcFormat *format, const gchar *key, guint8 **data, gsize *size); +void gst_amc_format_set_buffer (GstAmcFormat *format, const gchar *key, guint8 *data, gsize size); GstVideoFormat gst_amc_color_format_to_video_format (gint color_format); gint gst_amc_video_format_to_color_format (GstVideoFormat video_format); @@ -137,7 +137,7 @@ gint gst_amc_mpeg4_level_from_string (const gchar *level); const gchar * gst_amc_aac_profile_to_string (gint profile); gint gst_amc_aac_profile_from_string (const gchar *profile); -GstAudioChannelPosition* gst_amc_audio_channel_mask_to_positions (guint32 channel_mask, gint channels); +gboolean gst_amc_audio_channel_mask_to_positions (guint32 channel_mask, gint channels, GstAudioChannelPosition *pos); guint32 gst_amc_audio_channel_mask_from_positions (GstAudioChannelPosition *positions, gint channels); G_END_DECLS diff --git a/sys/androidmedia/gstamcaudiodec.c b/sys/androidmedia/gstamcaudiodec.c index 31a8bf5f2..886556ae2 100644 --- a/sys/androidmedia/gstamcaudiodec.c +++ b/sys/androidmedia/gstamcaudiodec.c @@ -28,7 +28,7 @@ #endif #include <gst/gst.h> -#include <gst/audio/multichannel.h> +#include <gst/audio/audio.h> #include <string.h> #ifdef HAVE_ORC @@ -69,11 +69,12 @@ enum /* class initialization */ -#define DEBUG_INIT(bla) \ +#define DEBUG_INIT \ GST_DEBUG_CATEGORY_INIT (gst_amc_audio_dec_debug_category, "amcaudiodec", 0, \ "Android MediaCodec audio decoder"); +#define parent_class gst_amc_audio_dec_parent_class -GST_BOILERPLATE_FULL (GstAmcAudioDec, gst_amc_audio_dec, GstAudioDecoder, +G_DEFINE_TYPE_WITH_CODE (GstAmcAudioDec, gst_amc_audio_dec, GST_TYPE_AUDIO_DECODER, DEBUG_INIT); static GstCaps * @@ -95,21 +96,21 @@ create_sink_caps (const GstAmcCodecInfo * codec_info) "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else if (strcmp (type->mime, "audio/3gpp") == 0) { GstStructure *tmp; tmp = gst_structure_new ("audio/AMR", "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else if (strcmp (type->mime, "audio/amr-wb") == 0) { GstStructure *tmp; tmp = gst_structure_new ("audio/AMR-WB", "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else if (strcmp (type->mime, "audio/mp4a-latm") == 0) { gint j; GstStructure *tmp, *tmp2; @@ -147,13 +148,13 @@ create_sink_caps (const GstAmcCodecInfo * codec_info) tmp2 = gst_structure_copy (tmp); gst_structure_set (tmp2, "profile", G_TYPE_STRING, profile, NULL); - gst_caps_merge_structure (ret, tmp2); + ret = gst_caps_merge_structure (ret, tmp2); have_profile = TRUE; } if (!have_profile) { - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else { gst_structure_free (tmp); } @@ -163,21 +164,21 @@ create_sink_caps (const GstAmcCodecInfo * codec_info) tmp = gst_structure_new ("audio/x-alaw", "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else if (strcmp (type->mime, "audio/g711-mlaw") == 0) { GstStructure *tmp; tmp = gst_structure_new ("audio/x-mulaw", "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else if (strcmp (type->mime, "audio/vorbis") == 0) { GstStructure *tmp; tmp = gst_structure_new ("audio/x-vorbis", "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else if (strcmp (type->mime, "audio/flac") == 0) { GstStructure *tmp; @@ -185,7 +186,7 @@ create_sink_caps (const GstAmcCodecInfo * codec_info) "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, "framed", G_TYPE_BOOLEAN, TRUE, NULL); - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else if (strcmp (type->mime, "audio/mpeg-L2") == 0) { GstStructure *tmp; @@ -195,7 +196,7 @@ create_sink_caps (const GstAmcCodecInfo * codec_info) "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else { GST_WARNING ("Unsupported mimetype '%s'", type->mime); } @@ -264,22 +265,38 @@ create_src_caps (const GstAmcCodecInfo * codec_info) } static void -gst_amc_audio_dec_base_init (gpointer g_class) +gst_amc_audio_dec_class_init (GstAmcAudioDecClass * klass) { - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - GstAmcAudioDecClass *audiodec_class = GST_AMC_AUDIO_DEC_CLASS (g_class); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstAudioDecoderClass *audiodec_class = GST_AUDIO_DECODER_CLASS (klass); + GstAmcAudioDecClass *amcaudiodec_class = GST_AMC_AUDIO_DEC_CLASS (klass); const GstAmcCodecInfo *codec_info; GstPadTemplate *templ; GstCaps *caps; gchar *longname; + gobject_class->finalize = gst_amc_audio_dec_finalize; + + element_class->change_state = + GST_DEBUG_FUNCPTR (gst_amc_audio_dec_change_state); + + audiodec_class->start = GST_DEBUG_FUNCPTR (gst_amc_audio_dec_start); + audiodec_class->stop = GST_DEBUG_FUNCPTR (gst_amc_audio_dec_stop); + audiodec_class->open = GST_DEBUG_FUNCPTR (gst_amc_audio_dec_open); + audiodec_class->close = GST_DEBUG_FUNCPTR (gst_amc_audio_dec_close); + audiodec_class->flush = GST_DEBUG_FUNCPTR (gst_amc_audio_dec_flush); + audiodec_class->set_format = GST_DEBUG_FUNCPTR (gst_amc_audio_dec_set_format); + audiodec_class->handle_frame = + GST_DEBUG_FUNCPTR (gst_amc_audio_dec_handle_frame); + codec_info = - g_type_get_qdata (G_TYPE_FROM_CLASS (g_class), gst_amc_codec_info_quark); + g_type_get_qdata (G_TYPE_FROM_CLASS (klass), gst_amc_codec_info_quark); /* This happens for the base class and abstract subclasses */ if (!codec_info) return; - audiodec_class->codec_info = codec_info; + amcaudiodec_class->codec_info = codec_info; /* Add pad templates */ caps = create_sink_caps (codec_info); @@ -293,7 +310,7 @@ gst_amc_audio_dec_base_init (gpointer g_class) gst_object_unref (templ); longname = g_strdup_printf ("Android MediaCodec %s", codec_info->name); - gst_element_class_set_details_simple (element_class, + gst_element_class_set_metadata (element_class, codec_info->name, "Codec/Decoder/Audio", longname, "Sebastian Dröge <sebastian.droege@collabora.co.uk>"); @@ -301,31 +318,7 @@ gst_amc_audio_dec_base_init (gpointer g_class) } static void -gst_amc_audio_dec_class_init (GstAmcAudioDecClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstAudioDecoderClass *audiodec_class = GST_AUDIO_DECODER_CLASS (klass); - - gobject_class->finalize = gst_amc_audio_dec_finalize; - - element_class->change_state = - GST_DEBUG_FUNCPTR (gst_amc_audio_dec_change_state); - - audiodec_class->start = GST_DEBUG_FUNCPTR (gst_amc_audio_dec_start); - audiodec_class->stop = GST_DEBUG_FUNCPTR (gst_amc_audio_dec_stop); -#if 0 - audiodec_class->open = GST_DEBUG_FUNCPTR (gst_amc_audio_dec_open); - audiodec_class->close = GST_DEBUG_FUNCPTR (gst_amc_audio_dec_close); -#endif - audiodec_class->flush = GST_DEBUG_FUNCPTR (gst_amc_audio_dec_flush); - audiodec_class->set_format = GST_DEBUG_FUNCPTR (gst_amc_audio_dec_set_format); - audiodec_class->handle_frame = - GST_DEBUG_FUNCPTR (gst_amc_audio_dec_handle_frame); -} - -static void -gst_amc_audio_dec_init (GstAmcAudioDec * self, GstAmcAudioDecClass * klass) +gst_amc_audio_dec_init (GstAmcAudioDec * self) { gst_audio_decoder_set_needs_format (GST_AUDIO_DECODER (self), TRUE); gst_audio_decoder_set_drainable (GST_AUDIO_DECODER (self), TRUE); @@ -400,8 +393,6 @@ gst_amc_audio_dec_change_state (GstElement * element, GstStateChange transition) self->downstream_flow_ret = GST_FLOW_OK; self->draining = FALSE; self->started = FALSE; - if (!gst_amc_audio_dec_open (GST_AUDIO_DECODER (self))) - return GST_STATE_CHANGE_FAILURE; break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; @@ -429,9 +420,7 @@ gst_amc_audio_dec_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: - if (!gst_amc_audio_dec_close (GST_AUDIO_DECODER (self))) - return GST_STATE_CHANGE_FAILURE; - self->downstream_flow_ret = GST_FLOW_WRONG_STATE; + self->downstream_flow_ret = GST_FLOW_FLUSHING; self->started = FALSE; break; case GST_STATE_CHANGE_READY_TO_NULL: @@ -449,6 +438,7 @@ gst_amc_audio_dec_set_src_caps (GstAmcAudioDec * self, GstAmcFormat * format) GstCaps *caps; gint rate, channels; guint32 channel_mask = 0; + GstAudioChannelPosition to[64]; if (!gst_amc_format_get_int (format, "sample-rate", &rate) || !gst_amc_format_get_int (format, "channel-count", &channels)) { @@ -465,26 +455,23 @@ gst_amc_audio_dec_set_src_caps (GstAmcAudioDec * self, GstAmcFormat * format) if (gst_amc_format_contains_key (format, "channel-mask")) gst_amc_format_get_int (format, "channel-mask", (gint *) & channel_mask); - if (self->positions) - g_free (self->positions); - self->positions = - gst_amc_audio_channel_mask_to_positions (channel_mask, channels); + gst_amc_audio_channel_mask_to_positions (channel_mask, channels, + self->positions); + memcpy (to, self->positions, sizeof (to)); + gst_audio_channel_positions_to_valid_order (to, channels); + self->needs_reorder = + (memcmp (self->positions, to, + sizeof (GstAudioChannelPosition) * channels) != 0); + if (self->needs_reorder) + gst_audio_get_channel_reorder_map (channels, self->positions, to, + self->reorder_map); + gst_audio_info_init (&self->info); + gst_audio_info_set_format (&self->info, GST_AUDIO_FORMAT_S16, rate, channels, + to); - caps = gst_caps_new_simple ("audio/x-raw-int", - "rate", G_TYPE_INT, rate, - "channels", G_TYPE_INT, channels, - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed", G_TYPE_BOOLEAN, TRUE, - "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL); + caps = gst_audio_info_to_caps (&self->info); - if (self->positions) - gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), - self->positions); - - self->channels = channels; - self->rate = rate; gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (self), caps); gst_caps_unref (caps); @@ -592,6 +579,7 @@ retry: GstAmcAudioDecClass *klass = GST_AMC_AUDIO_DEC_GET_CLASS (self); GstBuffer *outbuf; GstAmcBuffer *buf; + GstMapInfo minfo; /* This sometimes happens at EOS or if the input is not properly framed, * let's handle it gracefully by allocating a new buffer for the current @@ -610,13 +598,33 @@ retry: } } - outbuf = gst_buffer_try_new_and_alloc (buffer_info.size); + outbuf = + gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER (self), + buffer_info.size); if (!outbuf) goto failed_allocate; + gst_buffer_map (outbuf, &minfo, GST_MAP_WRITE); buf = &self->output_buffers[idx]; - orc_memcpy (GST_BUFFER_DATA (outbuf), buf->data + buffer_info.offset, - buffer_info.size); + if (self->needs_reorder) { + gint i, n_samples, c, n_channels; + gint *reorder_map = self->reorder_map; + gint16 *dest, *source; + + dest = (gint16 *) minfo.data; + source = (gint16 *) (buf->data + buffer_info.offset); + n_samples = buffer_info.size / self->info.bpf; + n_channels = self->info.channels; + + for (i = 0; i < n_samples; i++) { + for (c = 0; c < n_channels; c++) { + dest[i * n_channels + reorder_map[c]] = source[i * n_channels + c]; + } + } + } else { + orc_memcpy (minfo.data, buf->data + buffer_info.offset, buffer_info.size); + } + gst_buffer_unmap (outbuf, &minfo); /* FIXME: We should get one decoded input frame here for * every buffer. If this is not the case somewhere, we will @@ -630,7 +638,7 @@ done: if (!gst_amc_codec_release_output_buffer (self->codec, idx)) goto failed_release; - if (is_eos || flow_ret == GST_FLOW_UNEXPECTED) { + if (is_eos || flow_ret == GST_FLOW_EOS) { GST_AUDIO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (self->drain_lock); if (self->draining) { @@ -639,7 +647,7 @@ done: g_cond_broadcast (self->drain_cond); } else if (flow_ret == GST_FLOW_OK) { GST_DEBUG_OBJECT (self, "Component signalled EOS"); - flow_ret = GST_FLOW_UNEXPECTED; + flow_ret = GST_FLOW_EOS; } g_mutex_unlock (self->drain_lock); GST_AUDIO_DECODER_STREAM_LOCK (self); @@ -702,20 +710,19 @@ flushing: { GST_DEBUG_OBJECT (self, "Flushing -- stopping task"); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); - self->downstream_flow_ret = GST_FLOW_WRONG_STATE; + self->downstream_flow_ret = GST_FLOW_FLUSHING; GST_AUDIO_DECODER_STREAM_UNLOCK (self); return; } flow_error: { - if (flow_ret == GST_FLOW_UNEXPECTED) { + if (flow_ret == GST_FLOW_EOS) { GST_DEBUG_OBJECT (self, "EOS"); gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_AUDIO_DECODER_SRC_PAD (self)); - } else - if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_UNEXPECTED) { + } else if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_EOS) { GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", gst_flow_get_name (flow_ret))); @@ -786,20 +793,19 @@ gst_amc_audio_dec_stop (GstAudioDecoder * decoder) } gst_pad_stop_task (GST_AUDIO_DECODER_SRC_PAD (decoder)); - g_free (self->positions); - self->positions = NULL; + memset (self->positions, 0, sizeof (self->positions)); - g_list_foreach (self->codec_datas, (GFunc) gst_buffer_unref, NULL); + g_list_foreach (self->codec_datas, (GFunc) g_free, NULL); g_list_free (self->codec_datas); self->codec_datas = NULL; - self->downstream_flow_ret = GST_FLOW_WRONG_STATE; + self->downstream_flow_ret = GST_FLOW_FLUSHING; self->eos = FALSE; g_mutex_lock (self->drain_lock); self->draining = FALSE; g_cond_broadcast (self->drain_cond); g_mutex_unlock (self->drain_lock); - gst_buffer_replace (&self->codec_data, NULL); + GST_DEBUG_OBJECT (self, "Stopped decoder"); return TRUE; } @@ -883,10 +889,14 @@ gst_amc_audio_dec_set_format (GstAudioDecoder * decoder, GstCaps * caps) if (gst_structure_has_field (s, "codec_data")) { const GValue *h = gst_structure_get_value (s, "codec_data"); GstBuffer *codec_data = gst_value_get_buffer (h); - - self->codec_datas = - g_list_prepend (self->codec_datas, gst_buffer_ref (codec_data)); - gst_amc_format_set_buffer (format, "csd-0", codec_data); + GstMapInfo minfo; + guint8 *data; + + gst_buffer_map (codec_data, &minfo, GST_MAP_READ); + data = g_memdup (minfo.data, minfo.size); + self->codec_datas = g_list_prepend (self->codec_datas, data); + gst_amc_format_set_buffer (format, "csd-0", data, minfo.size); + gst_buffer_unmap (codec_data, &minfo); } else if (gst_structure_has_field (s, "streamheader")) { const GValue *sh = gst_structure_get_value (s, "streamheader"); gint nsheaders = gst_value_array_get_size (sh); @@ -894,13 +904,17 @@ gst_amc_audio_dec_set_format (GstAudioDecoder * decoder, GstCaps * caps) const GValue *h; gint i, j; gchar *fname; + GstMapInfo minfo; + guint8 *data; for (i = 0, j = 0; i < nsheaders; i++) { h = gst_value_array_get_value (sh, i); buf = gst_value_get_buffer (h); if (strcmp (mime, "audio/vorbis") == 0) { - guint8 header_type = GST_BUFFER_DATA (buf)[0]; + guint8 header_type; + + gst_buffer_extract (buf, 0, &header_type, 1); /* Only use the identification and setup packets */ if (header_type != 0x01 && header_type != 0x05) @@ -908,9 +922,11 @@ gst_amc_audio_dec_set_format (GstAudioDecoder * decoder, GstCaps * caps) } fname = g_strdup_printf ("csd-%d", j); - self->codec_datas = - g_list_prepend (self->codec_datas, gst_buffer_ref (buf)); - gst_amc_format_set_buffer (format, fname, buf); + gst_buffer_map (buf, &minfo, GST_MAP_READ); + data = g_memdup (minfo.data, minfo.size); + self->codec_datas = g_list_prepend (self->codec_datas, data); + gst_amc_format_set_buffer (format, fname, data, minfo.size); + gst_buffer_unmap (buf, &minfo); g_free (fname); j++; } @@ -949,7 +965,7 @@ gst_amc_audio_dec_set_format (GstAudioDecoder * decoder, GstCaps * caps) self->flushing = FALSE; self->downstream_flow_ret = GST_FLOW_OK; gst_pad_start_task (GST_AUDIO_DECODER_SRC_PAD (self), - (GstTaskFunction) gst_amc_audio_dec_loop, decoder); + (GstTaskFunction) gst_amc_audio_dec_loop, decoder, NULL); return TRUE; } @@ -985,7 +1001,7 @@ gst_amc_audio_dec_flush (GstAudioDecoder * decoder, gboolean hard) self->eos = FALSE; self->downstream_flow_ret = GST_FLOW_OK; gst_pad_start_task (GST_AUDIO_DECODER_SRC_PAD (self), - (GstTaskFunction) gst_amc_audio_dec_loop, decoder); + (GstTaskFunction) gst_amc_audio_dec_loop, decoder, NULL); GST_DEBUG_OBJECT (self, "Reset decoder"); } @@ -999,6 +1015,9 @@ gst_amc_audio_dec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf) GstAmcBufferInfo buffer_info; guint offset = 0; GstClockTime timestamp, duration, timestamp_offset = 0; + GstMapInfo minfo; + + memset (&minfo, 0, sizeof (minfo)); self = GST_AMC_AUDIO_DEC (decoder); @@ -1021,7 +1040,7 @@ gst_amc_audio_dec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf) GST_WARNING_OBJECT (self, "Got frame after EOS"); if (inbuf) gst_buffer_unref (inbuf); - return GST_FLOW_UNEXPECTED; + return GST_FLOW_EOS; } if (self->flushing) @@ -1033,10 +1052,12 @@ gst_amc_audio_dec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf) if (!inbuf) return gst_amc_audio_dec_drain (self); - timestamp = GST_BUFFER_TIMESTAMP (inbuf); + timestamp = GST_BUFFER_PTS (inbuf); duration = GST_BUFFER_DURATION (inbuf); - while (offset < GST_BUFFER_SIZE (inbuf)) { + gst_buffer_map (inbuf, &minfo, GST_MAP_READ); + + while (offset < minfo.size) { /* Make sure to release the base class stream lock, otherwise * _loop() can't call _finish_frame() and we might block forever * because no input buffers are released */ @@ -1085,15 +1106,14 @@ gst_amc_audio_dec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf) memset (&buffer_info, 0, sizeof (buffer_info)); buffer_info.offset = 0; - buffer_info.size = MIN (GST_BUFFER_SIZE (inbuf) - offset, buf->size); + buffer_info.size = MIN (minfo.size - offset, buf->size); - orc_memcpy (buf->data, GST_BUFFER_DATA (inbuf) + offset, buffer_info.size); + orc_memcpy (buf->data, minfo.data + offset, buffer_info.size); /* Interpolate timestamps if we're passing the buffer * in multiple chunks */ if (offset != 0 && duration != GST_CLOCK_TIME_NONE) { - timestamp_offset = - gst_util_uint64_scale (offset, duration, GST_BUFFER_SIZE (inbuf)); + timestamp_offset = gst_util_uint64_scale (offset, duration, minfo.size); } if (timestamp != GST_CLOCK_TIME_NONE) { @@ -1117,7 +1137,7 @@ gst_amc_audio_dec_handle_frame (GstAudioDecoder * decoder, GstBuffer * inbuf) if (!gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info)) goto queue_error; } - + gst_buffer_unmap (inbuf, &minfo); gst_buffer_unref (inbuf); return self->downstream_flow_ret; @@ -1126,6 +1146,8 @@ downstream_error: { GST_ERROR_OBJECT (self, "Downstream returned %s", gst_flow_get_name (self->downstream_flow_ret)); + if (minfo.data) + gst_buffer_unmap (inbuf, &minfo); if (inbuf) gst_buffer_unref (inbuf); return self->downstream_flow_ret; @@ -1134,6 +1156,8 @@ invalid_buffer_index: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Invalid input buffer index %d of %d", idx, self->n_input_buffers)); + if (minfo.data) + gst_buffer_unmap (inbuf, &minfo); if (inbuf) gst_buffer_unref (inbuf); return GST_FLOW_ERROR; @@ -1142,6 +1166,8 @@ dequeue_error: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Failed to dequeue input buffer")); + if (minfo.data) + gst_buffer_unmap (inbuf, &minfo); if (inbuf) gst_buffer_unref (inbuf); return GST_FLOW_ERROR; @@ -1150,16 +1176,20 @@ queue_error: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Failed to queue input buffer")); + if (minfo.data) + gst_buffer_unmap (inbuf, &minfo); if (inbuf) gst_buffer_unref (inbuf); return GST_FLOW_ERROR; } flushing: { - GST_DEBUG_OBJECT (self, "Flushing -- returning WRONG_STATE"); + GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING"); + if (minfo.data) + gst_buffer_unmap (inbuf, &minfo); if (inbuf) gst_buffer_unref (inbuf); - return GST_FLOW_WRONG_STATE; + return GST_FLOW_FLUSHING; } } diff --git a/sys/androidmedia/gstamcaudiodec.h b/sys/androidmedia/gstamcaudiodec.h index 5941a0114..0e0c6e10b 100644 --- a/sys/androidmedia/gstamcaudiodec.h +++ b/sys/androidmedia/gstamcaudiodec.h @@ -22,7 +22,7 @@ #define __GST_AMC_AUDIO_DEC_H__ #include <gst/gst.h> -#include <gst/audio/multichannel.h> +#include <gst/audio/audio.h> #include <gst/audio/gstaudiodecoder.h> #include "gstamc.h" @@ -59,10 +59,12 @@ struct _GstAmcAudioDec gboolean input_caps_changed; /* Output format of the codec */ - gint channels, rate; - GstAudioChannelPosition *positions; + GstAudioInfo info; + /* AMC positions, might need reordering */ + GstAudioChannelPosition positions[64]; + gboolean needs_reorder; + gint reorder_map[64]; - GstBuffer *codec_data; /* TRUE if the component is configured and saw * the first buffer */ gboolean started; diff --git a/sys/androidmedia/gstamcvideodec.c b/sys/androidmedia/gstamcvideodec.c index dc3d7b2db..e316b34c3 100644 --- a/sys/androidmedia/gstamcvideodec.c +++ b/sys/androidmedia/gstamcvideodec.c @@ -28,6 +28,8 @@ #endif #include <gst/gst.h> +#include <gst/video/gstvideometa.h> +#include <gst/video/gstvideopool.h> #include <string.h> #ifdef HAVE_ORC @@ -82,8 +84,11 @@ static gboolean gst_amc_video_dec_reset (GstVideoDecoder * decoder, static GstFlowReturn gst_amc_video_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame); static GstFlowReturn gst_amc_video_dec_finish (GstVideoDecoder * decoder); +static gboolean gst_amc_video_dec_decide_allocation (GstVideoDecoder * bdec, + GstQuery * query); -static GstFlowReturn gst_amc_video_dec_drain (GstAmcVideoDec * self); +static GstFlowReturn gst_amc_video_dec_drain (GstAmcVideoDec * self, + gboolean at_eos); enum { @@ -92,11 +97,11 @@ enum /* class initialization */ -#define DEBUG_INIT(bla) \ +#define DEBUG_INIT \ GST_DEBUG_CATEGORY_INIT (gst_amc_video_dec_debug_category, "amcvideodec", 0, \ "Android MediaCodec video decoder"); - -GST_BOILERPLATE_FULL (GstAmcVideoDec, gst_amc_video_dec, GstVideoDecoder, +#define parent_class gst_amc_video_dec_parent_class +G_DEFINE_TYPE_WITH_CODE (GstAmcVideoDec, gst_amc_video_dec, GST_TYPE_VIDEO_DECODER, DEBUG_INIT); static GstCaps * @@ -157,13 +162,13 @@ create_sink_caps (const GstAmcCodecInfo * codec_info) gst_structure_set_value (tmp2, "level", &va); g_value_unset (&va); g_value_unset (&v); - gst_caps_merge_structure (ret, tmp2); + ret = gst_caps_merge_structure (ret, tmp2); have_profile_level = TRUE; } } if (!have_profile_level) { - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else { gst_structure_free (tmp); } @@ -213,13 +218,13 @@ create_sink_caps (const GstAmcCodecInfo * codec_info) gst_structure_set_value (tmp2, "level", &va); g_value_unset (&va); g_value_unset (&v); - gst_caps_merge_structure (ret, tmp2); + ret = gst_caps_merge_structure (ret, tmp2); have_profile_level = TRUE; } } if (!have_profile_level) { - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else { gst_structure_free (tmp); } @@ -272,7 +277,7 @@ create_sink_caps (const GstAmcCodecInfo * codec_info) if (!alternative) g_value_unset (&va); g_value_unset (&v); - gst_caps_merge_structure (ret, tmp2); + ret = gst_caps_merge_structure (ret, tmp2); if (alternative) { tmp2 = gst_structure_copy (tmp); @@ -280,14 +285,14 @@ create_sink_caps (const GstAmcCodecInfo * codec_info) NULL); gst_structure_set_value (tmp2, "level", &va); g_value_unset (&va); - gst_caps_merge_structure (ret, tmp2); + ret = gst_caps_merge_structure (ret, tmp2); } have_profile_level = TRUE; } } if (!have_profile_level) { - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else { gst_structure_free (tmp); } @@ -299,7 +304,7 @@ create_sink_caps (const GstAmcCodecInfo * codec_info) "height", GST_TYPE_INT_RANGE, 16, 4096, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else if (strcmp (type->mime, "video/mpeg2") == 0) { GstStructure *tmp; @@ -312,7 +317,7 @@ create_sink_caps (const GstAmcCodecInfo * codec_info) "systemstream", G_TYPE_BOOLEAN, FALSE, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); - gst_caps_merge_structure (ret, tmp); + ret = gst_caps_merge_structure (ret, tmp); } else { GST_WARNING ("Unsupported mimetype '%s'", type->mime); } @@ -375,8 +380,13 @@ create_src_caps (const GstAmcCodecInfo * codec_info) GST_WARNING ("Unknown color format 0x%08x", type->color_formats[j]); continue; } - tmp = gst_video_format_new_template_caps (format); - gst_caps_merge (ret, tmp); + + tmp = gst_caps_new_simple ("video/x-raw", + "format", G_TYPE_STRING, gst_video_format_to_string (format), + "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + ret = gst_caps_merge (ret, tmp); } } @@ -384,22 +394,41 @@ create_src_caps (const GstAmcCodecInfo * codec_info) } static void -gst_amc_video_dec_base_init (gpointer g_class) +gst_amc_video_dec_class_init (GstAmcVideoDecClass * klass) { - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - GstAmcVideoDecClass *videodec_class = GST_AMC_VIDEO_DEC_CLASS (g_class); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstVideoDecoderClass *videodec_class = GST_VIDEO_DECODER_CLASS (klass); + GstAmcVideoDecClass *amcvideodec_class = GST_AMC_VIDEO_DEC_CLASS (klass); const GstAmcCodecInfo *codec_info; GstPadTemplate *templ; GstCaps *caps; gchar *longname; + gobject_class->finalize = gst_amc_video_dec_finalize; + + element_class->change_state = + GST_DEBUG_FUNCPTR (gst_amc_video_dec_change_state); + + videodec_class->start = GST_DEBUG_FUNCPTR (gst_amc_video_dec_start); + videodec_class->stop = GST_DEBUG_FUNCPTR (gst_amc_video_dec_stop); + videodec_class->open = GST_DEBUG_FUNCPTR (gst_amc_video_dec_open); + videodec_class->close = GST_DEBUG_FUNCPTR (gst_amc_video_dec_close); + videodec_class->reset = GST_DEBUG_FUNCPTR (gst_amc_video_dec_reset); + videodec_class->set_format = GST_DEBUG_FUNCPTR (gst_amc_video_dec_set_format); + videodec_class->handle_frame = + GST_DEBUG_FUNCPTR (gst_amc_video_dec_handle_frame); + videodec_class->finish = GST_DEBUG_FUNCPTR (gst_amc_video_dec_finish); + videodec_class->decide_allocation = + GST_DEBUG_FUNCPTR (gst_amc_video_dec_decide_allocation); + codec_info = - g_type_get_qdata (G_TYPE_FROM_CLASS (g_class), gst_amc_codec_info_quark); + g_type_get_qdata (G_TYPE_FROM_CLASS (klass), gst_amc_codec_info_quark); /* This happens for the base class and abstract subclasses */ if (!codec_info) return; - videodec_class->codec_info = codec_info; + amcvideodec_class->codec_info = codec_info; /* Add pad templates */ caps = create_sink_caps (codec_info); @@ -413,7 +442,7 @@ gst_amc_video_dec_base_init (gpointer g_class) gst_object_unref (templ); longname = g_strdup_printf ("Android MediaCodec %s", codec_info->name); - gst_element_class_set_details_simple (element_class, + gst_element_class_set_metadata (element_class, codec_info->name, "Codec/Decoder/Video", longname, "Sebastian Dröge <sebastian.droege@collabora.co.uk>"); @@ -421,30 +450,7 @@ gst_amc_video_dec_base_init (gpointer g_class) } static void -gst_amc_video_dec_class_init (GstAmcVideoDecClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstVideoDecoderClass *videodec_class = GST_VIDEO_DECODER_CLASS (klass); - - gobject_class->finalize = gst_amc_video_dec_finalize; - - element_class->change_state = - GST_DEBUG_FUNCPTR (gst_amc_video_dec_change_state); - - videodec_class->start = GST_DEBUG_FUNCPTR (gst_amc_video_dec_start); - videodec_class->stop = GST_DEBUG_FUNCPTR (gst_amc_video_dec_stop); - videodec_class->open = GST_DEBUG_FUNCPTR (gst_amc_video_dec_open); - videodec_class->close = GST_DEBUG_FUNCPTR (gst_amc_video_dec_close); - videodec_class->reset = GST_DEBUG_FUNCPTR (gst_amc_video_dec_reset); - videodec_class->set_format = GST_DEBUG_FUNCPTR (gst_amc_video_dec_set_format); - videodec_class->handle_frame = - GST_DEBUG_FUNCPTR (gst_amc_video_dec_handle_frame); - videodec_class->finish = GST_DEBUG_FUNCPTR (gst_amc_video_dec_finish); -} - -static void -gst_amc_video_dec_init (GstAmcVideoDec * self, GstAmcVideoDecClass * klass) +gst_amc_video_dec_init (GstAmcVideoDec * self) { gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE); @@ -545,7 +551,7 @@ gst_amc_video_dec_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: - self->downstream_flow_ret = GST_FLOW_WRONG_STATE; + self->downstream_flow_ret = GST_FLOW_FLUSHING; self->started = FALSE; break; case GST_STATE_CHANGE_READY_TO_NULL: @@ -710,6 +716,7 @@ gst_amc_video_dec_set_src_caps (GstAmcVideoDec * self, GstAmcFormat * format) self->crop_top = crop_top; self->crop_bottom = crop_bottom; + gst_video_decoder_negotiate (GST_VIDEO_DECODER (self)); gst_video_codec_state_unref (output_state); self->input_state_changed = FALSE; @@ -737,21 +744,25 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, } /* Same video format */ - if (buffer_info->size == GST_BUFFER_SIZE (outbuf)) { + if (buffer_info->size == gst_buffer_get_size (outbuf)) { + GstMapInfo minfo; + GST_DEBUG_OBJECT (self, "Buffer sizes equal, doing fast copy"); - orc_memcpy (GST_BUFFER_DATA (outbuf), buf->data + buffer_info->offset, - buffer_info->size); + gst_buffer_map (outbuf, &minfo, GST_MAP_WRITE); + orc_memcpy (minfo.data, buf->data + buffer_info->offset, buffer_info->size); + gst_buffer_unmap (outbuf, &minfo); ret = TRUE; goto done; } GST_DEBUG_OBJECT (self, "Sizes not equal (%d vs %d), doing slow line-by-line copying", - buffer_info->size, GST_BUFFER_SIZE (outbuf)); + buffer_info->size, gst_buffer_get_size (outbuf)); /* Different video format, try to convert */ switch (self->color_format) { case COLOR_FormatYUV420Planar:{ + GstVideoFrame vframe; gint i, j, height; guint8 *src, *dest; gint stride, slice_height; @@ -775,13 +786,14 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, } } + gst_video_frame_map (&vframe, info, outbuf, GST_MAP_WRITE); for (i = 0; i < 3; i++) { if (i == 0) { src_stride = stride; - dest_stride = GST_VIDEO_INFO_COMP_STRIDE (info, i); + dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); } else { src_stride = (stride + 1) / 2; - dest_stride = GST_VIDEO_INFO_COMP_STRIDE (info, i); + dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); } src = buf->data + buffer_info->offset; @@ -799,8 +811,8 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, if (i == 2) src += ((slice_height + 1) / 2) * ((stride + 1) / 2); - dest = GST_BUFFER_DATA (outbuf) + GST_VIDEO_INFO_COMP_OFFSET (info, i); - height = GST_VIDEO_INFO_COMP_HEIGHT (info, i); + dest = GST_VIDEO_FRAME_COMP_DATA (&vframe, i); + height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i); for (j = 0; j < height; j++) { orc_memcpy (dest, src, row_length); @@ -808,6 +820,7 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, dest += dest_stride; } } + gst_video_frame_unmap (&vframe); ret = TRUE; break; } @@ -817,6 +830,7 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, guint8 *src, *dest; gint src_stride, dest_stride; gint row_length; + GstVideoFrame vframe; /* This should always be set */ if (self->stride == 0 || self->slice_height == 0) { @@ -826,13 +840,14 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, /* FIXME: This does not work for odd widths or heights * but might as well be a bug in the codec */ + gst_video_frame_map (&vframe, info, outbuf, GST_MAP_WRITE); for (i = 0; i < 2; i++) { if (i == 0) { src_stride = self->stride; - dest_stride = GST_VIDEO_INFO_COMP_STRIDE (info, i); + dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); } else { src_stride = GST_ROUND_UP_2 (self->stride); - dest_stride = GST_VIDEO_INFO_COMP_STRIDE (info, i); + dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); } src = buf->data + buffer_info->offset; @@ -843,8 +858,8 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, row_length = GST_ROUND_UP_2 (self->width); } - dest = GST_BUFFER_DATA (outbuf) + GST_VIDEO_INFO_COMP_OFFSET (info, i); - height = GST_VIDEO_INFO_COMP_HEIGHT (info, i); + dest = GST_VIDEO_FRAME_COMP_DATA (&vframe, i); + height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i); for (j = 0; j < height; j++) { orc_memcpy (dest, src, row_length); @@ -852,6 +867,7 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, dest += dest_stride; } } + gst_video_frame_unmap (&vframe); ret = TRUE; break; } @@ -861,6 +877,7 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, guint8 *src, *dest; gint src_stride, dest_stride; gint row_length; + GstVideoFrame vframe; /* This should always be set */ if (self->stride == 0 || self->slice_height == 0) { @@ -869,14 +886,14 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, } /* FIXME: This is untested! */ - + gst_video_frame_map (&vframe, info, outbuf, GST_MAP_WRITE); for (i = 0; i < 2; i++) { if (i == 0) { src_stride = self->stride; - dest_stride = GST_VIDEO_INFO_COMP_STRIDE (info, i); + dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); } else { src_stride = self->stride; - dest_stride = GST_VIDEO_INFO_COMP_STRIDE (info, i); + dest_stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, i); } src = buf->data + buffer_info->offset; @@ -891,8 +908,8 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, row_length = self->width; } - dest = GST_BUFFER_DATA (outbuf) + GST_VIDEO_INFO_COMP_OFFSET (info, i); - height = GST_VIDEO_INFO_COMP_HEIGHT (info, i); + dest = GST_VIDEO_FRAME_COMP_DATA (&vframe, i); + height = GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, i); for (j = 0; j < height; j++) { orc_memcpy (dest, src, row_length); @@ -900,6 +917,7 @@ gst_amc_video_dec_fill_buffer (GstAmcVideoDec * self, gint idx, dest += dest_stride; } } + gst_video_frame_unmap (&vframe); ret = TRUE; break; } @@ -940,7 +958,7 @@ retry: /*} */ if (idx < 0) { - if (self->flushing || self->downstream_flow_ret == GST_FLOW_WRONG_STATE) + if (self->flushing || self->downstream_flow_ret == GST_FLOW_FLUSHING) goto flushing; switch (idx) { @@ -1032,7 +1050,8 @@ retry: */ GST_ERROR_OBJECT (self, "No corresponding frame found"); - outbuf = gst_video_decoder_alloc_output_buffer (GST_VIDEO_DECODER (self)); + outbuf = + gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (self)); if (!gst_amc_video_dec_fill_buffer (self, idx, &buffer_info, outbuf)) { gst_buffer_unref (outbuf); @@ -1042,12 +1061,12 @@ retry: goto invalid_buffer; } - GST_BUFFER_TIMESTAMP (outbuf) = + GST_BUFFER_PTS (outbuf) = gst_util_uint64_scale (buffer_info.presentation_time_us, GST_USECOND, 1); flow_ret = gst_pad_push (GST_VIDEO_DECODER_SRC_PAD (self), outbuf); } else if (buffer_info.size > 0) { - if ((flow_ret = gst_video_decoder_alloc_output_frame (GST_VIDEO_DECODER + if ((flow_ret = gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER (self), frame)) != GST_FLOW_OK) { GST_ERROR_OBJECT (self, "Failed to allocate buffer"); goto flow_error; @@ -1071,7 +1090,7 @@ retry: if (!gst_amc_codec_release_output_buffer (self->codec, idx)) goto failed_release; - if (is_eos || flow_ret == GST_FLOW_UNEXPECTED) { + if (is_eos || flow_ret == GST_FLOW_EOS) { GST_VIDEO_DECODER_STREAM_UNLOCK (self); g_mutex_lock (self->drain_lock); if (self->draining) { @@ -1080,7 +1099,7 @@ retry: g_cond_broadcast (self->drain_cond); } else if (flow_ret == GST_FLOW_OK) { GST_DEBUG_OBJECT (self, "Component signalled EOS"); - flow_ret = GST_FLOW_UNEXPECTED; + flow_ret = GST_FLOW_EOS; } g_mutex_unlock (self->drain_lock); GST_VIDEO_DECODER_STREAM_LOCK (self); @@ -1143,20 +1162,19 @@ flushing: { GST_DEBUG_OBJECT (self, "Flushing -- stopping task"); gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self)); - self->downstream_flow_ret = GST_FLOW_WRONG_STATE; + self->downstream_flow_ret = GST_FLOW_FLUSHING; GST_VIDEO_DECODER_STREAM_UNLOCK (self); return; } flow_error: { - if (flow_ret == GST_FLOW_UNEXPECTED) { + if (flow_ret == GST_FLOW_EOS) { GST_DEBUG_OBJECT (self, "EOS"); gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ()); gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self)); - } else - if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_UNEXPECTED) { + } else if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_EOS) { GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Internal data stream error."), ("stream stopped, reason %s", gst_flow_get_name (flow_ret))); @@ -1216,13 +1234,14 @@ gst_amc_video_dec_stop (GstVideoDecoder * decoder) } gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder)); - self->downstream_flow_ret = GST_FLOW_WRONG_STATE; + self->downstream_flow_ret = GST_FLOW_FLUSHING; self->eos = FALSE; g_mutex_lock (self->drain_lock); self->draining = FALSE; g_cond_broadcast (self->drain_cond); g_mutex_unlock (self->drain_lock); - gst_buffer_replace (&self->codec_data, NULL); + g_free (self->codec_data); + self->codec_data_size = 0; GST_DEBUG_OBJECT (self, "Stopped decoder"); return TRUE; } @@ -1237,6 +1256,8 @@ gst_amc_video_dec_set_format (GstVideoDecoder * decoder, gboolean is_format_change = FALSE; gboolean needs_disable = FALSE; gchar *format_string; + guint8 *codec_data = NULL; + gsize codec_data_size = 0; self = GST_AMC_VIDEO_DEC (decoder); @@ -1247,7 +1268,20 @@ gst_amc_video_dec_set_format (GstVideoDecoder * decoder, */ is_format_change |= self->width != state->info.width; is_format_change |= self->height != state->info.height; - is_format_change |= (self->codec_data != state->codec_data); + if (state->codec_data) { + GstMapInfo cminfo; + + gst_buffer_map (state->codec_data, &cminfo, GST_MAP_READ); + codec_data = g_memdup (cminfo.data, cminfo.size); + codec_data_size = cminfo.size; + + is_format_change |= (!self->codec_data + || self->codec_data_size != codec_data_size + || memcmp (self->codec_data, codec_data, codec_data_size) != 0); + gst_buffer_unmap (state->codec_data, &cminfo); + } else if (self->codec_data) { + is_format_change |= TRUE; + } needs_disable = self->started; @@ -1256,6 +1290,10 @@ gst_amc_video_dec_set_format (GstVideoDecoder * decoder, * happened we can just exit here. */ if (needs_disable && !is_format_change) { + g_free (codec_data); + codec_data = NULL; + codec_data_size = 0; + /* Framerate or something minor changed */ self->input_state_changed = TRUE; GST_DEBUG_OBJECT (self, @@ -1264,7 +1302,7 @@ gst_amc_video_dec_set_format (GstVideoDecoder * decoder, } if (needs_disable && is_format_change) { - gst_amc_video_dec_drain (self); + gst_amc_video_dec_drain (self, FALSE); GST_VIDEO_DECODER_STREAM_UNLOCK (self); gst_amc_video_dec_stop (GST_VIDEO_DECODER (self)); GST_VIDEO_DECODER_STREAM_LOCK (self); @@ -1280,7 +1318,9 @@ gst_amc_video_dec_set_format (GstVideoDecoder * decoder, } /* srcpad task is not running at this point */ - gst_buffer_replace (&self->codec_data, state->codec_data); + g_free (self->codec_data); + self->codec_data = codec_data; + self->codec_data_size = codec_data_size; mime = caps_to_mime (state->caps); if (!mime) { @@ -1297,7 +1337,8 @@ gst_amc_video_dec_set_format (GstVideoDecoder * decoder, /* FIXME: This buffer needs to be valid until the codec is stopped again */ if (self->codec_data) - gst_amc_format_set_buffer (format, "csd-0", self->codec_data); + gst_amc_format_set_buffer (format, "csd-0", self->codec_data, + self->codec_data_size); format_string = gst_amc_format_to_string (format); GST_DEBUG_OBJECT (self, "Configuring codec with format: %s", format_string); @@ -1331,7 +1372,7 @@ gst_amc_video_dec_set_format (GstVideoDecoder * decoder, self->flushing = FALSE; self->downstream_flow_ret = GST_FLOW_OK; gst_pad_start_task (GST_VIDEO_DECODER_SRC_PAD (self), - (GstTaskFunction) gst_amc_video_dec_loop, decoder); + (GstTaskFunction) gst_amc_video_dec_loop, decoder, NULL); return TRUE; } @@ -1367,7 +1408,7 @@ gst_amc_video_dec_reset (GstVideoDecoder * decoder, gboolean hard) self->eos = FALSE; self->downstream_flow_ret = GST_FLOW_OK; gst_pad_start_task (GST_VIDEO_DECODER_SRC_PAD (self), - (GstTaskFunction) gst_amc_video_dec_loop, decoder); + (GstTaskFunction) gst_amc_video_dec_loop, decoder, NULL); GST_DEBUG_OBJECT (self, "Reset decoder"); @@ -1384,6 +1425,9 @@ gst_amc_video_dec_handle_frame (GstVideoDecoder * decoder, GstAmcBufferInfo buffer_info; guint offset = 0; GstClockTime timestamp, duration, timestamp_offset = 0; + GstMapInfo minfo; + + memset (&minfo, 0, sizeof (minfo)); self = GST_AMC_VIDEO_DEC (decoder); @@ -1398,7 +1442,7 @@ gst_amc_video_dec_handle_frame (GstVideoDecoder * decoder, if (self->eos) { GST_WARNING_OBJECT (self, "Got frame after EOS"); gst_video_codec_frame_unref (frame); - return GST_FLOW_UNEXPECTED; + return GST_FLOW_EOS; } if (self->flushing) @@ -1410,7 +1454,9 @@ gst_amc_video_dec_handle_frame (GstVideoDecoder * decoder, timestamp = frame->pts; duration = frame->duration; - while (offset < GST_BUFFER_SIZE (frame->input_buffer)) { + gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ); + + while (offset < minfo.size) { /* Make sure to release the base class stream lock, otherwise * _loop() can't call _finish_frame() and we might block forever * because no input buffers are released */ @@ -1459,18 +1505,14 @@ gst_amc_video_dec_handle_frame (GstVideoDecoder * decoder, memset (&buffer_info, 0, sizeof (buffer_info)); buffer_info.offset = 0; - buffer_info.size = - MIN (GST_BUFFER_SIZE (frame->input_buffer) - offset, buf->size); + buffer_info.size = MIN (minfo.size - offset, buf->size); - orc_memcpy (buf->data, GST_BUFFER_DATA (frame->input_buffer) + offset, - buffer_info.size); + orc_memcpy (buf->data, minfo.data + offset, buffer_info.size); /* Interpolate timestamps if we're passing the buffer * in multiple chunks */ if (offset != 0 && duration != GST_CLOCK_TIME_NONE) { - timestamp_offset = - gst_util_uint64_scale (offset, duration, - GST_BUFFER_SIZE (frame->input_buffer)); + timestamp_offset = gst_util_uint64_scale (offset, duration, minfo.size); } if (timestamp != GST_CLOCK_TIME_NONE) { @@ -1499,6 +1541,7 @@ gst_amc_video_dec_handle_frame (GstVideoDecoder * decoder, goto queue_error; } + gst_buffer_unmap (frame->input_buffer, &minfo); gst_video_codec_frame_unref (frame); return self->downstream_flow_ret; @@ -1507,6 +1550,8 @@ downstream_error: { GST_ERROR_OBJECT (self, "Downstream returned %s", gst_flow_get_name (self->downstream_flow_ret)); + if (minfo.data) + gst_buffer_unmap (frame->input_buffer, &minfo); gst_video_codec_frame_unref (frame); return self->downstream_flow_ret; } @@ -1514,6 +1559,8 @@ invalid_buffer_index: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Invalid input buffer index %d of %d", idx, self->n_input_buffers)); + if (minfo.data) + gst_buffer_unmap (frame->input_buffer, &minfo); gst_video_codec_frame_unref (frame); return GST_FLOW_ERROR; } @@ -1521,6 +1568,8 @@ dequeue_error: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Failed to dequeue input buffer")); + if (minfo.data) + gst_buffer_unmap (frame->input_buffer, &minfo); gst_video_codec_frame_unref (frame); return GST_FLOW_ERROR; } @@ -1528,14 +1577,18 @@ queue_error: { GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL), ("Failed to queue input buffer")); + if (minfo.data) + gst_buffer_unmap (frame->input_buffer, &minfo); gst_video_codec_frame_unref (frame); return GST_FLOW_ERROR; } flushing: { - GST_DEBUG_OBJECT (self, "Flushing -- returning WRONG_STATE"); + GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING"); + if (minfo.data) + gst_buffer_unmap (frame->input_buffer, &minfo); gst_video_codec_frame_unref (frame); - return GST_FLOW_WRONG_STATE; + return GST_FLOW_FLUSHING; } } @@ -1543,54 +1596,14 @@ static GstFlowReturn gst_amc_video_dec_finish (GstVideoDecoder * decoder) { GstAmcVideoDec *self; - gint idx; self = GST_AMC_VIDEO_DEC (decoder); - GST_DEBUG_OBJECT (self, "Sending EOS to the component"); - - /* Don't send EOS buffer twice, this doesn't work */ - if (self->eos) { - GST_DEBUG_OBJECT (self, "Component is already EOS"); - return GST_VIDEO_DECODER_FLOW_DROPPED; - } - self->eos = TRUE; - - /* Make sure to release the base class stream lock, otherwise - * _loop() can't call _finish_frame() and we might block forever - * because no input buffers are released */ - GST_VIDEO_DECODER_STREAM_UNLOCK (self); - /* Send an EOS buffer to the component and let the base - * class drop the EOS event. We will send it later when - * the EOS buffer arrives on the output port. - * Wait at most 0.5s here. */ - idx = gst_amc_codec_dequeue_input_buffer (self->codec, 500000); - GST_VIDEO_DECODER_STREAM_LOCK (self); - - if (idx >= 0 && idx < self->n_input_buffers) { - GstAmcBufferInfo buffer_info; - memset (&buffer_info, 0, sizeof (buffer_info)); - buffer_info.size = 0; - buffer_info.presentation_time_us = - gst_util_uint64_scale (self->last_upstream_ts, 1, GST_USECOND); - buffer_info.flags |= BUFFER_FLAG_END_OF_STREAM; - - if (gst_amc_codec_queue_input_buffer (self->codec, idx, &buffer_info)) - GST_DEBUG_OBJECT (self, "Sent EOS to the codec"); - else - GST_ERROR_OBJECT (self, "Failed to send EOS to the codec"); - } else if (idx >= self->n_input_buffers) { - GST_ERROR_OBJECT (self, "Invalid input buffer index %d of %d", - idx, self->n_input_buffers); - } else { - GST_ERROR_OBJECT (self, "Failed to dequeue input buffer for EOS: %d", idx); - } - - return GST_VIDEO_DECODER_FLOW_DROPPED; + return gst_amc_video_dec_drain (self, TRUE); } static GstFlowReturn -gst_amc_video_dec_drain (GstAmcVideoDec * self) +gst_amc_video_dec_drain (GstAmcVideoDec * self, gboolean at_eos) { GstFlowReturn ret; gint idx; @@ -1606,6 +1619,8 @@ gst_amc_video_dec_drain (GstAmcVideoDec * self) GST_DEBUG_OBJECT (self, "Codec is EOS already"); return GST_FLOW_OK; } + if (at_eos) + self->eos = TRUE; /* Make sure to release the base class stream lock, otherwise * _loop() can't call _finish_frame() and we might block forever @@ -1654,3 +1669,27 @@ gst_amc_video_dec_drain (GstAmcVideoDec * self) return ret; } + +static gboolean +gst_amc_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query) +{ + GstBufferPool *pool; + GstStructure *config; + + if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (bdec, query)) + return FALSE; + + g_assert (gst_query_get_n_allocation_pools (query) > 0); + gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL); + g_assert (pool != NULL); + + config = gst_buffer_pool_get_config (pool); + if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) { + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_META); + } + gst_buffer_pool_set_config (pool, config); + gst_object_unref (pool); + + return TRUE; +} diff --git a/sys/androidmedia/gstamcvideodec.h b/sys/androidmedia/gstamcvideodec.h index 4a33e4830..8709d1169 100644 --- a/sys/androidmedia/gstamcvideodec.h +++ b/sys/androidmedia/gstamcvideodec.h @@ -64,7 +64,8 @@ struct _GstAmcVideoDec gint crop_left, crop_right; gint crop_top, crop_bottom; - GstBuffer *codec_data; + guint8 *codec_data; + gsize codec_data_size; /* TRUE if the component is configured and saw * the first buffer */ gboolean started; |