From 98ffdface2db429656b2f7b8f3cc5a301d498d75 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 3 Feb 2002 20:10:04 +0000 Subject: Assorted fixes. Original commit message from CVS: Assorted fixes. Use the new clocking stuff. --- gst/avi/gstavidecoder.c | 370 ++++++++++++++++++++++++++++++++++++++++++++++++ gst/avi/gstavidemux.c | 122 +++++++++++----- gst/avi/gstavidemux.h | 2 + 3 files changed, 458 insertions(+), 36 deletions(-) create mode 100644 gst/avi/gstavidecoder.c (limited to 'gst/avi') diff --git a/gst/avi/gstavidecoder.c b/gst/avi/gstavidecoder.c new file mode 100644 index 00000000..fdd283a6 --- /dev/null +++ b/gst/avi/gstavidecoder.c @@ -0,0 +1,370 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +/*#define GST_DEBUG_ENABLED */ +#include + +#include "gstavidecoder.h" + + + +/* elementfactory information */ +static GstElementDetails gst_avi_decoder_details = { + ".avi decoder", + "Decoder/Video", + "Decodes a .avi file into audio and video", + VERSION, + "Erik Walthinsen \n" + "Wim Taymans ", + "(C) 1999", +}; + +static GstCaps* avi_typefind (GstBuffer *buf, gpointer private); + +/* typefactory for 'avi' */ +static GstTypeDefinition avidefinition = { + "avidecoder_video/avi", + "video/avi", + ".avi", + avi_typefind, +}; + +/* AviDecoder signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_BITRATE, + ARG_MEDIA_TIME, + ARG_CURRENT_TIME, + /* FILL ME */ +}; + +GST_PADTEMPLATE_FACTORY (sink_templ, + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "avidecoder_sink", + "video/avi", + "RIFF", GST_PROPS_STRING ("AVI") + ) +) + +GST_PADTEMPLATE_FACTORY (src_video_templ, + "video_src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "wincodec_src", + "video/raw", + "format", GST_PROPS_LIST ( + GST_PROPS_FOURCC (GST_MAKE_FOURCC ('Y','U','Y','2')), + GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')), + GST_PROPS_FOURCC (GST_MAKE_FOURCC ('R','G','B',' ')) + ), + "width", GST_PROPS_INT_RANGE (16, 4096), + "height", GST_PROPS_INT_RANGE (16, 4096) + ) +) + +GST_PADTEMPLATE_FACTORY (src_audio_templ, + "audio_src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "src_audio", + "audio/raw", + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (0), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "signed", GST_PROPS_LIST ( + GST_PROPS_BOOLEAN (TRUE), + GST_PROPS_BOOLEAN (FALSE) + ), + "width", GST_PROPS_LIST ( + GST_PROPS_INT (8), + GST_PROPS_INT (16) + ), + "depth", GST_PROPS_LIST ( + GST_PROPS_INT (8), + GST_PROPS_INT (16) + ), + "rate", GST_PROPS_INT_RANGE (11025, 48000), + "channels", GST_PROPS_INT_RANGE (1, 2) + ) +) + +static void gst_avi_decoder_class_init (GstAviDecoderClass *klass); +static void gst_avi_decoder_init (GstAviDecoder *avi_decoder); + +static void gst_avi_decoder_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + + + +static GstElementClass *parent_class = NULL; +/*static guint gst_avi_decoder_signals[LAST_SIGNAL] = { 0 }; */ + +GType +gst_avi_decoder_get_type(void) +{ + static GType avi_decoder_type = 0; + + if (!avi_decoder_type) { + static const GTypeInfo avi_decoder_info = { + sizeof(GstAviDecoderClass), + NULL, + NULL, + (GClassInitFunc)gst_avi_decoder_class_init, + NULL, + NULL, + sizeof(GstAviDecoder), + 0, + (GInstanceInitFunc)gst_avi_decoder_init, + }; + avi_decoder_type = g_type_register_static(GST_TYPE_BIN, "GstAviDecoder", &avi_decoder_info, 0); + } + return avi_decoder_type; +} + +static void +gst_avi_decoder_class_init (GstAviDecoderClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_BITRATE, + g_param_spec_long ("bitrate","bitrate","bitrate", + G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */ + g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_MEDIA_TIME, + g_param_spec_long ("media_time","media_time","media_time", + G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */ + g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_CURRENT_TIME, + g_param_spec_long ("current_time","current_time","current_time", + G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */ + + parent_class = g_type_class_ref (GST_TYPE_BIN); + + gobject_class->get_property = gst_avi_decoder_get_property; +} + +static void +gst_avi_decoder_new_pad (GstElement *element, GstPad *pad, GstAviDecoder *avi_decoder) +{ + GstCaps *caps; + GstCaps *targetcaps = NULL; + const gchar *format; + gboolean type_found; + GstElement *type; + GstElement *new_element = NULL; + gchar *padname = NULL; + gchar *gpadname = NULL; +#define AVI_TYPE_VIDEO 1 +#define AVI_TYPE_AUDIO 2 + gint media_type = 0; + + GST_DEBUG (0, "avidecoder: new pad for element \"%s\"\n", gst_element_get_name (element)); + + caps = gst_pad_get_caps (pad); + format = gst_caps_get_string (caps, "format"); + + if (!strcmp (format, "strf_vids")) { + targetcaps = gst_padtemplate_get_caps (GST_PADTEMPLATE_GET (src_video_templ)); + media_type = AVI_TYPE_VIDEO; + gpadname = g_strdup_printf ("video_%02d", avi_decoder->video_count++); + } + else if (!strcmp (format, "strf_auds")) { + targetcaps = gst_padtemplate_get_caps (GST_PADTEMPLATE_GET (src_audio_templ)); + media_type = AVI_TYPE_AUDIO; + gpadname = g_strdup_printf ("audio_%02d", avi_decoder->audio_count++); + } + else if (!strcmp (format, "strf_iavs")) { + targetcaps = gst_padtemplate_get_caps (GST_PADTEMPLATE_GET (src_video_templ)); + media_type = AVI_TYPE_VIDEO; + gpadname = g_strdup_printf ("video_%02d", avi_decoder->video_count++); + } + else { + g_assert_not_reached (); + } + + gst_element_set_state (GST_ELEMENT (avi_decoder), GST_STATE_PAUSED); + + type = gst_elementfactory_make ("avitypes", + g_strdup_printf ("typeconvert%d", avi_decoder->count)); + + /* brin the element to the READY state so it can do our caps negotiation */ + gst_element_set_state (type, GST_STATE_READY); + + gst_pad_connect (pad, gst_element_get_pad (type, "sink")); + type_found = gst_util_get_bool_arg (G_OBJECT (type), "type_found"); + + if (type_found) { + + gst_bin_add (GST_BIN (avi_decoder), type); + + pad = gst_element_get_pad (type, "src"); + caps = gst_pad_get_caps (pad); + + if (gst_caps_check_compatibility (caps, targetcaps)) { + gst_element_add_ghost_pad (GST_ELEMENT (avi_decoder), + gst_element_get_pad (type, "src"), gpadname); + + avi_decoder->count++; + goto done; + } +#ifndef GST_DISABLE_AUTOPLUG + else { + GstAutoplug *autoplug; + autoplug = gst_autoplugfactory_make("static"); + + new_element = gst_autoplug_to_caps (autoplug, caps, targetcaps, NULL); + + padname = "src_00"; + } +#endif /* GST_DISABLE_AUTOPLUG */ + } + + if (!new_element && (media_type == AVI_TYPE_VIDEO)) { + padname = "src"; + } + else if (!new_element && (media_type == AVI_TYPE_AUDIO)) { + /*FIXME */ + padname = "src"; + } + + if (new_element) { + gst_pad_connect (pad, gst_element_get_pad (new_element, "sink")); + gst_element_set_name (new_element, g_strdup_printf ("element%d", avi_decoder->count)); + gst_bin_add (GST_BIN (avi_decoder), new_element); + + gst_element_add_ghost_pad (GST_ELEMENT (avi_decoder), + gst_element_get_pad (new_element, padname), gpadname); + + avi_decoder->count++; + } + else { + g_warning ("avidecoder: could not autoplug\n"); + } + +done: + gst_element_set_state (GST_ELEMENT (avi_decoder), GST_STATE_PLAYING); +} + +static void +gst_avi_decoder_init (GstAviDecoder *avi_decoder) +{ + avi_decoder->demuxer = gst_elementfactory_make ("avidemux", "demux"); + + if (avi_decoder->demuxer) { + gst_bin_add (GST_BIN (avi_decoder), avi_decoder->demuxer); + + gst_element_add_ghost_pad (GST_ELEMENT (avi_decoder), + gst_element_get_pad (avi_decoder->demuxer, "sink"), "sink"); + + g_signal_connect (G_OBJECT (avi_decoder->demuxer),"new_pad", G_CALLBACK (gst_avi_decoder_new_pad), + avi_decoder); + } + else { + g_warning ("wow!, no avi demuxer found. help me\n"); + } + + avi_decoder->count = 0; + avi_decoder->audio_count = 0; + avi_decoder->video_count = 0; +} + +static GstCaps* +avi_typefind (GstBuffer *buf, + gpointer private) +{ + gchar *data = GST_BUFFER_DATA (buf); + GstCaps *new; + + GST_DEBUG (0,"avi_decoder: typefind\n"); + if (strncmp (&data[0], "RIFF", 4)) return NULL; + if (strncmp (&data[8], "AVI ", 4)) return NULL; + + new = GST_CAPS_NEW ("avi_typefind", + "video/avi", + "RIFF", GST_PROPS_STRING ("AVI")); + + return new; +} + +static void +gst_avi_decoder_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstAviDecoder *src; + + g_return_if_fail (GST_IS_AVI_DECODER (object)); + + src = GST_AVI_DECODER (object); + + switch(prop_id) { + case ARG_BITRATE: + break; + case ARG_MEDIA_TIME: + g_value_set_long (value, gst_util_get_long_arg (G_OBJECT (src->demuxer), "media_time")); + break; + case ARG_CURRENT_TIME: + g_value_set_long (value, gst_util_get_long_arg (G_OBJECT (src->demuxer), "current_time")); + break; + default: + break; + } +} + + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + GstTypeFactory *type; + + /* create an elementfactory for the avi_decoder element */ + factory = gst_elementfactory_new ("avidecoder", GST_TYPE_AVI_DECODER, + &gst_avi_decoder_details); + g_return_val_if_fail (factory != NULL, FALSE); + + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_audio_templ)); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_video_templ)); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sink_templ)); + + type = gst_typefactory_new (&avidefinition); + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "avidecoder", + plugin_init +}; + diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c index 60820120..302bb6ec 100644 --- a/gst/avi/gstavidemux.c +++ b/gst/avi/gstavidemux.c @@ -229,7 +229,9 @@ gst_avi_demux_init (GstAviDemux *avi_demux) avi_demux->state = GST_AVI_DEMUX_UNKNOWN; avi_demux->num_audio_pads = 0; avi_demux->num_video_pads = 0; + //avi_demux->next_time = 500000; avi_demux->next_time = 0; + avi_demux->init_audio = 0; avi_demux->flags = 0; avi_demux->index_entries = NULL; avi_demux->index_size = 0; @@ -324,6 +326,27 @@ gst_avi_demux_strh (GstAviDemux *avi_demux) GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: samplesize %d", GUINT32_FROM_LE (strh->samplesize)); avi_demux->fcc_type = GUINT32_FROM_LE (strh->type); + if (strh->type == GST_RIFF_FCC_auds) { + guint32 scale; + + scale = GUINT32_FROM_LE (strh->scale); + avi_demux->init_audio = GUINT32_FROM_LE (strh->init_frames); + if (!scale) + scale = 1; + avi_demux->audio_rate = GUINT32_FROM_LE (strh->rate) / scale; + } + else if (strh->type == GST_RIFF_FCC_vids) { + gfloat frame_rate; + guint32 scale; + + scale = GUINT32_FROM_LE (strh->scale); + if (!scale) + scale = 1; + frame_rate = (gfloat)GUINT32_FROM_LE (strh->rate) / scale; + + gst_element_send_event (GST_ELEMENT (avi_demux), + gst_event_new_info ("frame_rate", GST_PROPS_FLOAT (frame_rate), NULL)); + } return TRUE; } @@ -538,14 +561,26 @@ gst_avi_demux_strf_iavs (GstAviDemux *avi_demux) static void gst_avidemux_parse_index (GstAviDemux *avi_demux, - gulong offset) + gulong filepos, gulong offset) { GstBuffer *buf; gulong index_size; - buf = gst_pad_pullregion (avi_demux->sinkpad, GST_REGION_OFFSET_LEN, offset, 8); + if (!gst_bytestream_seek (avi_demux->bs, GST_SEEK_BYTEOFFSET_SET, filepos + offset)) { + GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not seek to index"); + return; + } + buf = gst_bytestream_read (avi_demux->bs, 8); + while (!buf) { + guint32 remaining; + GstEvent *event; + + gst_bytestream_get_status (avi_demux->bs, &remaining, &event); - if (!buf || GST_BUFFER_OFFSET (buf) != offset || GST_BUFFER_SIZE (buf) != 8) { + buf = gst_bytestream_read (avi_demux->bs, 8); + } + + if (GST_BUFFER_OFFSET (buf) != filepos + offset || GST_BUFFER_SIZE (buf) != 8) { GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not get index"); return; } @@ -556,8 +591,9 @@ gst_avidemux_parse_index (GstAviDemux *avi_demux, } index_size = GUINT32_FROM_LE(*(guint32 *)(GST_BUFFER_DATA (buf) + 4)); + gst_buffer_unref (buf); - buf = gst_pad_pullregion(avi_demux->sinkpad, GST_REGION_OFFSET_LEN, offset+8, index_size); + buf = gst_bytestream_read (avi_demux->bs, index_size); avi_demux->index_size = index_size/sizeof(gst_riff_index_entry); @@ -565,28 +601,11 @@ gst_avidemux_parse_index (GstAviDemux *avi_demux, avi_demux->index_entries = g_malloc (GST_BUFFER_SIZE (buf)); memcpy (avi_demux->index_entries, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + gst_buffer_unref (buf); - buf = gst_pad_pullregion(avi_demux->sinkpad, GST_REGION_OFFSET_LEN, avi_demux->index_offset, 0); -} - -static void -gst_avidemux_forall_pads (GstAviDemux *avi_demux, GFunc func, gpointer user_data) -{ - gint i; - GstPad *pad; - - for(i=0; iaudio_pad[i]; - if (pad && GST_PAD_IS_CONNECTED (pad)) { - (*func) (pad, user_data); - } - } - - for(i=0; ivideo_pad[i]; - if (pad && GST_PAD_IS_CONNECTED (pad)) { - (*func) (pad, user_data); - } + if (!gst_bytestream_seek (avi_demux->bs, GST_SEEK_BYTEOFFSET_SET, filepos)) { + GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not seek back to movi"); + return; } } @@ -628,16 +647,19 @@ gst_avidemux_read_chunk (GstAviDemux *avi_demux, guint32 *id, guint32 *size) gst_riff_chunk *chunk; GstByteStream *bs = avi_demux->bs; - chunk = (gst_riff_chunk *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_chunk)); - if (chunk) { - *id = GUINT32_FROM_LE (chunk->id); - *size = GUINT32_FROM_LE (chunk->size); + do { + chunk = (gst_riff_chunk *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_chunk)); + if (chunk) { + *id = GUINT32_FROM_LE (chunk->id); + *size = GUINT32_FROM_LE (chunk->size); - gst_bytestream_flush (bs, sizeof (gst_riff_chunk)); + gst_bytestream_flush (bs, sizeof (gst_riff_chunk)); - return TRUE; - } - return gst_avidemux_handle_event (avi_demux); + return TRUE; + } + } while (gst_avidemux_handle_event (avi_demux)); + + return TRUE; } static gboolean @@ -672,16 +694,34 @@ gst_avidemux_process_chunk (GstAviDemux *avi_demux, guint64 *filepos, { guint32 datashowed; guint32 subchunksize = 0; /* size of a read subchunk */ + gchar *formtype; - /* flush the form type */ - if (!gst_bytestream_flush (bs, sizeof (guint32))) + formtype = gst_bytestream_peek_bytes (bs, sizeof (guint32)); + if (!formtype) return FALSE; + switch (GUINT32_FROM_LE (*((guint32*)formtype))) { + case GST_RIFF_LIST_movi: + gst_avidemux_parse_index (avi_demux, *filepos, *chunksize); + while (!gst_bytestream_flush (bs, sizeof (guint32))) { + guint32 remaining; + GstEvent *event; + + gst_bytestream_get_status (avi_demux->bs, &remaining, &event); + } + break; + default: + /* flush the form type */ + gst_bytestream_flush_fast (bs, sizeof (guint32)); + break; + } + datashowed = sizeof (guint32); /* we showed the form type */ *filepos += datashowed; /* for the rest of the routine */ while (datashowed < *chunksize) { /* while not showed all: */ + GST_INFO (GST_CAT_PLUGIN_INFO, "process chunk filepos %08llx", *filepos); /* recurse for subchunks of RIFF and LIST chunks: */ if (!gst_avidemux_process_chunk (avi_demux, filepos, 0, rec_depth + 1, &subchunksize)) @@ -690,7 +730,8 @@ gst_avidemux_process_chunk (GstAviDemux *avi_demux, guint64 *filepos, subchunksize = ((subchunksize + 1) & ~1); datashowed += (sizeof (guint32) + sizeof (guint32) + subchunksize); - *filepos += subchunksize; + GST_INFO (GST_CAT_PLUGIN_INFO, "process chunk done filepos %08llx, subchunksize %08x", + *filepos, subchunksize); } if (datashowed != *chunksize) { g_warning ("error parsing AVI"); @@ -737,6 +778,7 @@ gst_avidemux_process_chunk (GstAviDemux *avi_demux, guint64 *filepos, buf = gst_bytestream_peek (bs, *chunksize); GST_BUFFER_TIMESTAMP (buf) = avi_demux->next_time; + avi_demux->next_time += avi_demux->time_interval; if (avi_demux->video_need_flush[0]) { @@ -759,12 +801,19 @@ gst_avidemux_process_chunk (GstAviDemux *avi_demux, guint64 *filepos, GST_DEBUG (0,"gst_avi_demux_chain: tag found %08x size %08x\n", chunkid, *chunksize); + if (avi_demux->init_audio) { + //avi_demux->next_time += (*chunksize) * 1000000LL / avi_demux->audio_rate; + avi_demux->init_audio--; + } + if (GST_PAD_IS_CONNECTED (avi_demux->audio_pad[0])) { GstBuffer *buf; if (*chunksize) { buf = gst_bytestream_peek (bs, *chunksize); + GST_BUFFER_TIMESTAMP (buf) = -1LL; + if (avi_demux->audio_need_flush[0]) { GST_DEBUG (0,"audio flush\n"); avi_demux->audio_need_flush[0] = FALSE; @@ -787,6 +836,7 @@ gst_avidemux_process_chunk (GstAviDemux *avi_demux, guint64 *filepos, GST_INFO (GST_CAT_PLUGIN_INFO, "chunkid %s, flush %08x, filepos %08llx", gst_riff_id_to_fourcc (chunkid), *chunksize, *filepos); + *filepos += *chunksize; if (!gst_bytestream_flush (bs, *chunksize)) { return gst_avidemux_handle_event (avi_demux); } diff --git a/gst/avi/gstavidemux.h b/gst/avi/gstavidemux.h index 4703aad0..67a9333d 100644 --- a/gst/avi/gstavidemux.h +++ b/gst/avi/gstavidemux.h @@ -82,6 +82,8 @@ struct _GstAviDemux { gulong current_frame; guint32 flags; + guint32 init_audio; + guint32 audio_rate; guint num_audio_pads; guint num_video_pads; -- cgit