mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
androidmedia: Port to 1.0
This commit is contained in:
parent
36680b1190
commit
079c68e4de
8 changed files with 353 additions and 291 deletions
|
@ -310,7 +310,7 @@ AG_GST_DEFAULT_ELEMENTS
|
|||
dnl *** plug-ins to include ***
|
||||
dnl Non ported plugins (non-dependant, then dependant)
|
||||
dnl Make sure you have a space before and after all plugins
|
||||
GST_PLUGINS_NONPORTED=" androidmedia aiff \
|
||||
GST_PLUGINS_NONPORTED=" aiff \
|
||||
cdxaparse \
|
||||
dccp eglgles faceoverlay \
|
||||
freeverb \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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_PLUGIN_DEFINE (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",
|
||||
"Android Media plugin",
|
||||
plugin_init,
|
||||
PACKAGE_VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
GstMapInfo minfo;
|
||||
guint8 *data;
|
||||
|
||||
self->codec_datas =
|
||||
g_list_prepend (self->codec_datas, gst_buffer_ref (codec_data));
|
||||
gst_amc_format_set_buffer (format, "csd-0", codec_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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,57 +380,30 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_amc_video_dec_base_init (gpointer g_class)
|
||||
{
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
||||
GstAmcVideoDecClass *videodec_class = GST_AMC_VIDEO_DEC_CLASS (g_class);
|
||||
const GstAmcCodecInfo *codec_info;
|
||||
GstPadTemplate *templ;
|
||||
GstCaps *caps;
|
||||
gchar *longname;
|
||||
|
||||
codec_info =
|
||||
g_type_get_qdata (G_TYPE_FROM_CLASS (g_class), gst_amc_codec_info_quark);
|
||||
/* This happens for the base class and abstract subclasses */
|
||||
if (!codec_info)
|
||||
return;
|
||||
|
||||
videodec_class->codec_info = codec_info;
|
||||
|
||||
/* Add pad templates */
|
||||
caps = create_sink_caps (codec_info);
|
||||
templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
|
||||
gst_element_class_add_pad_template (element_class, templ);
|
||||
gst_object_unref (templ);
|
||||
|
||||
caps = create_src_caps (codec_info);
|
||||
templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
|
||||
gst_element_class_add_pad_template (element_class, templ);
|
||||
gst_object_unref (templ);
|
||||
|
||||
longname = g_strdup_printf ("Android MediaCodec %s", codec_info->name);
|
||||
gst_element_class_set_details_simple (element_class,
|
||||
codec_info->name,
|
||||
"Codec/Decoder/Video",
|
||||
longname, "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
|
||||
g_free (longname);
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
|
@ -441,10 +419,38 @@ gst_amc_video_dec_class_init (GstAmcVideoDecClass * klass)
|
|||
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 (klass), gst_amc_codec_info_quark);
|
||||
/* This happens for the base class and abstract subclasses */
|
||||
if (!codec_info)
|
||||
return;
|
||||
|
||||
amcvideodec_class->codec_info = codec_info;
|
||||
|
||||
/* Add pad templates */
|
||||
caps = create_sink_caps (codec_info);
|
||||
templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
|
||||
gst_element_class_add_pad_template (element_class, templ);
|
||||
gst_object_unref (templ);
|
||||
|
||||
caps = create_src_caps (codec_info);
|
||||
templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
|
||||
gst_element_class_add_pad_template (element_class, templ);
|
||||
gst_object_unref (templ);
|
||||
|
||||
longname = g_strdup_printf ("Android MediaCodec %s", codec_info->name);
|
||||
gst_element_class_set_metadata (element_class,
|
||||
codec_info->name,
|
||||
"Codec/Decoder/Video",
|
||||
longname, "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
|
||||
g_free (longname);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue