# HG changeset patch # User hgs # Date 1281130610 18000 # Node ID 69c7080681bfb1fbe9ff575f7fb9368fc8575377 # Parent bc39b352897ed76e719f389d124a8cdfc093e438 201031 diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/bwins/libgstalawu.def --- a/gst_plugins_good/bwins/libgstalawu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_alaw_dec_get_type @ 2 NONAME - gst_alaw_enc_get_type @ 3 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/bwins/libgstalphacoloru.def --- a/gst_plugins_good/bwins/libgstalphacoloru.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_alpha_color_get_type @ 2 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/bwins/libgstalphau.def --- a/gst_plugins_good/bwins/libgstalphau.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_alpha_get_type @ 2 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/bwins/libgstaudiofxu.def --- a/gst_plugins_good/bwins/libgstaudiofxu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - asinh @ 2 NONAME - cosh @ 3 NONAME - gst_audio_amplify_get_type @ 4 NONAME - gst_audio_cheb_band_get_type @ 5 NONAME - gst_audio_cheb_limit_get_type @ 6 NONAME - gst_audio_dynamic_get_type @ 7 NONAME - gst_audio_echo_get_type @ 8 NONAME - gst_audio_fir_filter_get_type @ 9 NONAME - gst_audio_fx_base_fir_filter_get_type @ 10 NONAME - gst_audio_fx_base_iir_filter_get_type @ 11 NONAME - gst_audio_iir_filter_get_type @ 12 NONAME - gst_audio_invert_get_type @ 13 NONAME - gst_audio_karaoke_get_type @ 14 NONAME - gst_audio_panorama_get_type @ 15 NONAME - gst_audio_wsincband_get_type @ 16 NONAME - gst_audio_wsinclimit_get_type @ 17 NONAME - sinh @ 18 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/bwins/libgstauparseu.def --- a/gst_plugins_good/bwins/libgstauparseu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_au_parse_get_type @ 2 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/bwins/libgstautodetectu.def --- a/gst_plugins_good/bwins/libgstautodetectu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_auto_audio_sink_get_type @ 2 NONAME - gst_auto_video_sink_get_type @ 3 NONAME - gst_auto_audio_src_get_type @ 4 NONAME - gst_auto_video_src_get_type @ 5 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/bwins/libgstaviu.def --- a/gst_plugins_good/bwins/libgstaviu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_avi_subtitle_get_type @ 2 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/bwins/libgstjpegU.DEF --- a/gst_plugins_good/bwins/libgstjpegU.DEF Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/bwins/libgstmpegaudioparseu.def --- a/gst_plugins_good/bwins/libgstmpegaudioparseu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_mp3parse_get_type @ 2 NONAME - gst_xing_mux_get_type @ 3 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/bwins/libgstmulawu.def --- a/gst_plugins_good/bwins/libgstmulawu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/bwins/libgstpngu.def --- a/gst_plugins_good/bwins/libgstpngu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_pngenc_get_type @ 2 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/bwins/libgstqtdemuxu.def --- a/gst_plugins_good/bwins/libgstqtdemuxu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_rtp_xqt_depay_get_type @ 2 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/eabi/libgstalawu.def --- a/gst_plugins_good/eabi/libgstalawu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_alaw_dec_get_type @ 2 NONAME - gst_alaw_enc_get_type @ 3 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/eabi/libgstalphacoloru.def --- a/gst_plugins_good/eabi/libgstalphacoloru.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_alpha_color_get_type @ 2 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/eabi/libgstalphau.def --- a/gst_plugins_good/eabi/libgstalphau.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_alpha_get_type @ 2 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/eabi/libgstaudiofxu.def --- a/gst_plugins_good/eabi/libgstaudiofxu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_audio_amplify_get_type @ 2 NONAME - gst_audio_cheb_band_get_type @ 3 NONAME - gst_audio_cheb_limit_get_type @ 4 NONAME - gst_audio_dynamic_get_type @ 5 NONAME - gst_audio_echo_get_type @ 6 NONAME - gst_audio_fir_filter_get_type @ 7 NONAME - gst_audio_fx_base_fir_filter_get_type @ 8 NONAME - gst_audio_fx_base_iir_filter_get_type @ 9 NONAME - gst_audio_iir_filter_get_type @ 10 NONAME - gst_audio_invert_get_type @ 11 NONAME - gst_audio_karaoke_get_type @ 12 NONAME - gst_audio_panorama_get_type @ 13 NONAME - gst_audio_wsincband_get_type @ 14 NONAME - gst_audio_wsinclimit_get_type @ 15 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/eabi/libgstauparseu.def --- a/gst_plugins_good/eabi/libgstauparseu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_au_parse_get_type @ 2 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/eabi/libgstautodetectu.def --- a/gst_plugins_good/eabi/libgstautodetectu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_auto_audio_sink_get_type @ 2 NONAME - gst_auto_video_sink_get_type @ 3 NONAME - gst_auto_audio_src_get_type @ 4 NONAME - gst_auto_video_src_get_type @ 5 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/eabi/libgstaviu.def --- a/gst_plugins_good/eabi/libgstaviu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_avi_subtitle_get_type @ 2 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/eabi/libgstjpegU.DEF --- a/gst_plugins_good/eabi/libgstjpegU.DEF Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/eabi/libgstmpegaudioparseu.def --- a/gst_plugins_good/eabi/libgstmpegaudioparseu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_mp3parse_get_type @ 2 NONAME - gst_xing_mux_get_type @ 3 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/eabi/libgstmulawu.def --- a/gst_plugins_good/eabi/libgstmulawu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/eabi/libgstpngu.def --- a/gst_plugins_good/eabi/libgstpngu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_pngenc_get_type @ 2 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/eabi/libgstqtdemuxu.def --- a/gst_plugins_good/eabi/libgstqtdemuxu.def Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -EXPORTS - _GST_PLUGIN_DESC @ 1 NONAME - gst_rtp_xqt_depay_get_type @ 2 NONAME - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/ext/libpng/gstpng.c --- a/gst_plugins_good/ext/libpng/gstpng.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * Filter: - * Copyright (C) 2000 Donald A. Graft - * - * 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. - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "gstpngdec.h" -#include "gstpngenc.h" - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "pngdec", GST_RANK_PRIMARY, - GST_TYPE_PNGDEC)) - return FALSE; - - if (!gst_element_register (plugin, "pngenc", GST_RANK_PRIMARY, - GST_TYPE_PNGENC)) - return FALSE; - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "png", - "PNG plugin library", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, - GST_PACKAGE_ORIGIN) - -#ifdef __SYMBIAN32__ -EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC() -{ - return &gst_plugin_desc; -} -#endif diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/ext/libpng/gstpngdec.c --- a/gst_plugins_good/ext/libpng/gstpngdec.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,881 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * 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. - * - */ -/** - * SECTION:element-pngdec - * - * Decodes png images. If there is no framerate set on sink caps, it sends EOS - * after the first picture. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstpngdec.h" - -#include -#include -#include -#include - -static const GstElementDetails gst_pngdec_details = -GST_ELEMENT_DETAILS ("PNG image decoder", - "Codec/Decoder/Image", - "Decode a png video frame to a raw image", - "Wim Taymans "); - -GST_DEBUG_CATEGORY_STATIC (pngdec_debug); -#define GST_CAT_DEFAULT pngdec_debug - -static void gst_pngdec_base_init (gpointer g_class); -static void gst_pngdec_class_init (GstPngDecClass * klass); -static void gst_pngdec_init (GstPngDec * pngdec); - -static gboolean gst_pngdec_libpng_init (GstPngDec * pngdec); -static gboolean gst_pngdec_libpng_clear (GstPngDec * pngdec); - -static GstStateChangeReturn gst_pngdec_change_state (GstElement * element, - GstStateChange transition); - -static gboolean gst_pngdec_sink_activate_push (GstPad * sinkpad, - gboolean active); -static gboolean gst_pngdec_sink_activate_pull (GstPad * sinkpad, - gboolean active); -static gboolean gst_pngdec_sink_activate (GstPad * sinkpad); - -static GstFlowReturn gst_pngdec_caps_create_and_set (GstPngDec * pngdec); - -static void gst_pngdec_task (GstPad * pad); -static GstFlowReturn gst_pngdec_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_pngdec_sink_event (GstPad * pad, GstEvent * event); -static gboolean gst_pngdec_sink_setcaps (GstPad * pad, GstCaps * caps); - -static GstElementClass *parent_class = NULL; - -GType -gst_pngdec_get_type (void) -{ - static GType pngdec_type = 0; - - if (!pngdec_type) { - static const GTypeInfo pngdec_info = { - sizeof (GstPngDecClass), - gst_pngdec_base_init, - NULL, - (GClassInitFunc) gst_pngdec_class_init, - NULL, - NULL, - sizeof (GstPngDec), - 0, - (GInstanceInitFunc) gst_pngdec_init, - }; - - pngdec_type = g_type_register_static (GST_TYPE_ELEMENT, "GstPngDec", - &pngdec_info, 0); - } - return pngdec_type; -} - -static GstStaticPadTemplate gst_pngdec_src_pad_template = - GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_RGB) - ); - -static GstStaticPadTemplate gst_pngdec_sink_pad_template = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("image/png") - ); - -static void -gst_pngdec_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_pngdec_src_pad_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_pngdec_sink_pad_template)); - gst_element_class_set_details (element_class, &gst_pngdec_details); -} - -static void -gst_pngdec_class_init (GstPngDecClass * klass) -{ - GstElementClass *gstelement_class; - - gstelement_class = (GstElementClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - gstelement_class->change_state = gst_pngdec_change_state; - - GST_DEBUG_CATEGORY_INIT (pngdec_debug, "pngdec", 0, "PNG image decoder"); -} - -static void -gst_pngdec_init (GstPngDec * pngdec) -{ - pngdec->sinkpad = - gst_pad_new_from_static_template (&gst_pngdec_sink_pad_template, "sink"); - gst_pad_set_activate_function (pngdec->sinkpad, gst_pngdec_sink_activate); - gst_pad_set_activatepush_function (pngdec->sinkpad, - gst_pngdec_sink_activate_push); - gst_pad_set_activatepull_function (pngdec->sinkpad, - gst_pngdec_sink_activate_pull); - gst_pad_set_chain_function (pngdec->sinkpad, gst_pngdec_chain); - gst_pad_set_event_function (pngdec->sinkpad, gst_pngdec_sink_event); - gst_pad_set_setcaps_function (pngdec->sinkpad, gst_pngdec_sink_setcaps); - gst_element_add_pad (GST_ELEMENT (pngdec), pngdec->sinkpad); - - pngdec->srcpad = - gst_pad_new_from_static_template (&gst_pngdec_src_pad_template, "src"); - gst_pad_use_fixed_caps (pngdec->srcpad); - gst_element_add_pad (GST_ELEMENT (pngdec), pngdec->srcpad); - - pngdec->buffer_out = NULL; - pngdec->png = NULL; - pngdec->info = NULL; - pngdec->endinfo = NULL; - pngdec->setup = FALSE; - - pngdec->color_type = -1; - pngdec->width = -1; - pngdec->height = -1; - pngdec->bpp = -1; - pngdec->fps_n = 0; - pngdec->fps_d = 1; - - pngdec->in_timestamp = GST_CLOCK_TIME_NONE; - pngdec->in_duration = GST_CLOCK_TIME_NONE; - - gst_segment_init (&pngdec->segment, GST_FORMAT_UNDEFINED); - - pngdec->image_ready = FALSE; -} - -static void -user_error_fn (png_structp png_ptr, png_const_charp error_msg) -{ - GST_ERROR ("%s", error_msg); -} - -static void -user_warning_fn (png_structp png_ptr, png_const_charp warning_msg) -{ - GST_WARNING ("%s", warning_msg); -} - -static void -user_info_callback (png_structp png_ptr, png_infop info) -{ - GstPngDec *pngdec = NULL; - GstFlowReturn ret = GST_FLOW_OK; - size_t buffer_size; - GstBuffer *buffer = NULL; - - pngdec = GST_PNGDEC (png_ptr->io_ptr); - - GST_LOG ("info ready"); - - /* Generate the caps and configure */ - ret = gst_pngdec_caps_create_and_set (pngdec); - if (ret != GST_FLOW_OK) { - goto beach; - } - - /* Allocate output buffer */ - pngdec->rowbytes = png_get_rowbytes (pngdec->png, pngdec->info); - buffer_size = pngdec->height * GST_ROUND_UP_4 (pngdec->rowbytes); - ret = - gst_pad_alloc_buffer_and_set_caps (pngdec->srcpad, GST_BUFFER_OFFSET_NONE, - buffer_size, GST_PAD_CAPS (pngdec->srcpad), &buffer); - if (ret != GST_FLOW_OK) { - goto beach; - } - - pngdec->buffer_out = buffer; - -beach: - pngdec->ret = ret; -} - -static void -user_endrow_callback (png_structp png_ptr, png_bytep new_row, - png_uint_32 row_num, int pass) -{ - GstPngDec *pngdec = NULL; - - pngdec = GST_PNGDEC (png_ptr->io_ptr); - - /* FIXME: implement interlaced pictures */ - - /* If buffer_out doesn't exist, it means buffer_alloc failed, which - * will already have set the return code */ - if (GST_IS_BUFFER (pngdec->buffer_out)) { - size_t offset = row_num * GST_ROUND_UP_4 (pngdec->rowbytes); - - GST_LOG ("got row %u, copying in buffer %p at offset %" G_GSIZE_FORMAT, - (guint) row_num, pngdec->buffer_out, offset); - memcpy (GST_BUFFER_DATA (pngdec->buffer_out) + offset, new_row, - pngdec->rowbytes); - pngdec->ret = GST_FLOW_OK; - } -} - -static gboolean -buffer_clip (GstPngDec * dec, GstBuffer * buffer) -{ - gboolean res = TRUE; - gint64 cstart, cstop; - - - if ((!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) || - (!GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) || - (dec->segment.format != GST_FORMAT_TIME)) - goto beach; - - cstart = GST_BUFFER_TIMESTAMP (buffer); - cstop = GST_BUFFER_DURATION (buffer); - - if ((res = gst_segment_clip (&dec->segment, GST_FORMAT_TIME, - cstart, cstart + cstop, &cstart, &cstop))) { - GST_BUFFER_TIMESTAMP (buffer) = cstart; - GST_BUFFER_DURATION (buffer) = cstop - cstart; - } - -beach: - return res; -} - -static void -user_end_callback (png_structp png_ptr, png_infop info) -{ - GstPngDec *pngdec = NULL; - - pngdec = GST_PNGDEC (png_ptr->io_ptr); - - GST_LOG_OBJECT (pngdec, "and we are done reading this image"); - - if (!pngdec->buffer_out) - return; - - if (GST_CLOCK_TIME_IS_VALID (pngdec->in_timestamp)) - GST_BUFFER_TIMESTAMP (pngdec->buffer_out) = pngdec->in_timestamp; - if (GST_CLOCK_TIME_IS_VALID (pngdec->in_duration)) - GST_BUFFER_DURATION (pngdec->buffer_out) = pngdec->in_duration; - - /* buffer clipping */ - if (buffer_clip (pngdec, pngdec->buffer_out)) { - /* Push our buffer and then EOS if needed */ - GST_LOG_OBJECT (pngdec, "pushing buffer with ts=%" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (pngdec->buffer_out))); - - pngdec->ret = gst_pad_push (pngdec->srcpad, pngdec->buffer_out); - } else { - GST_LOG_OBJECT (pngdec, "dropped decoded buffer"); - gst_buffer_unref (pngdec->buffer_out); - } - pngdec->buffer_out = NULL; - pngdec->image_ready = TRUE; -} - -static void -user_read_data (png_structp png_ptr, png_bytep data, png_size_t length) -{ - GstPngDec *pngdec; - GstBuffer *buffer; - GstFlowReturn ret = GST_FLOW_OK; - guint size; - - pngdec = GST_PNGDEC (png_ptr->io_ptr); - - GST_LOG ("reading %" G_GSIZE_FORMAT " bytes of data at offset %d", length, - pngdec->offset); - - ret = gst_pad_pull_range (pngdec->sinkpad, pngdec->offset, length, &buffer); - if (ret != GST_FLOW_OK) - goto pause; - - size = GST_BUFFER_SIZE (buffer); - - if (size != length) - goto short_buffer; - - memcpy (data, GST_BUFFER_DATA (buffer), size); - - gst_buffer_unref (buffer); - - pngdec->offset += length; - - return; - - /* ERRORS */ -pause: - { - GST_INFO_OBJECT (pngdec, "pausing task, reason %s", - gst_flow_get_name (ret)); - gst_pad_pause_task (pngdec->sinkpad); - if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) { - GST_ELEMENT_ERROR (pngdec, STREAM, FAILED, - (_("Internal data stream error.")), - ("stream stopped, reason %s", gst_flow_get_name (ret))); - gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ()); - } - return; - } -short_buffer: - { - gst_buffer_unref (buffer); - GST_ELEMENT_ERROR (pngdec, STREAM, FAILED, - (_("Internal data stream error.")), - ("Read %u, needed %" G_GSIZE_FORMAT "bytes", size, length)); - ret = GST_FLOW_ERROR; - goto pause; - } -} - -static GstFlowReturn -gst_pngdec_caps_create_and_set (GstPngDec * pngdec) -{ - GstFlowReturn ret = GST_FLOW_OK; - GstCaps *caps = NULL, *res = NULL; - GstPadTemplate *templ = NULL; - gint bpc = 0, color_type; - png_uint_32 width, height; - - g_return_val_if_fail (GST_IS_PNGDEC (pngdec), GST_FLOW_ERROR); - - /* Get bits per channel */ - bpc = png_get_bit_depth (pngdec->png, pngdec->info); - - /* We don't handle 16 bits per color, strip down to 8 */ - if (bpc == 16) { - GST_LOG_OBJECT (pngdec, - "this is a 16 bits per channel PNG image, strip down to 8 bits"); - png_set_strip_16 (pngdec->png); - } - - /* Get Color type */ - color_type = png_get_color_type (pngdec->png, pngdec->info); - -#if 0 - /* We used to have this HACK to reverse the outgoing bytes, but the problem - * that originally required the hack seems to have been in ffmpegcolorspace's - * RGBA descriptions. It doesn't seem needed now that's fixed, but might - * still be needed on big-endian systems, I'm not sure. J.S. 6/7/2007 */ - if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) - png_set_bgr (pngdec->png); -#endif - - /* Gray scale converted to RGB and upscaled to 8 bits */ - if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || - (color_type == PNG_COLOR_TYPE_GRAY)) { - GST_LOG_OBJECT (pngdec, "converting grayscale png to RGB"); - png_set_gray_to_rgb (pngdec->png); - if (bpc < 8) { /* Convert to 8 bits */ - GST_LOG_OBJECT (pngdec, "converting grayscale image to 8 bits"); - png_set_gray_1_2_4_to_8 (pngdec->png); - } - } - - /* Palette converted to RGB */ - if (color_type == PNG_COLOR_TYPE_PALETTE) { - GST_LOG_OBJECT (pngdec, "converting palette png to RGB"); - png_set_palette_to_rgb (pngdec->png); - } - - /* Update the info structure */ - png_read_update_info (pngdec->png, pngdec->info); - - /* Get IHDR header again after transformation settings */ - - png_get_IHDR (pngdec->png, pngdec->info, &width, &height, - &bpc, &pngdec->color_type, NULL, NULL, NULL); - - pngdec->width = width; - pngdec->height = height; - - GST_LOG_OBJECT (pngdec, "this is a %dx%d PNG image", pngdec->width, - pngdec->height); - - switch (pngdec->color_type) { - case PNG_COLOR_TYPE_RGB: - GST_LOG_OBJECT (pngdec, "we have no alpha channel, depth is 24 bits"); - pngdec->bpp = 24; - break; - case PNG_COLOR_TYPE_RGB_ALPHA: - GST_LOG_OBJECT (pngdec, "we have an alpha channel, depth is 32 bits"); - pngdec->bpp = 32; - break; - default: - GST_ELEMENT_ERROR (pngdec, STREAM, NOT_IMPLEMENTED, (NULL), - ("pngdec does not support this color type")); - ret = GST_FLOW_NOT_SUPPORTED; - goto beach; - } - - caps = gst_caps_new_simple ("video/x-raw-rgb", - "width", G_TYPE_INT, pngdec->width, - "height", G_TYPE_INT, pngdec->height, - "bpp", G_TYPE_INT, pngdec->bpp, - "framerate", GST_TYPE_FRACTION, pngdec->fps_n, pngdec->fps_d, NULL); - - templ = gst_static_pad_template_get (&gst_pngdec_src_pad_template); - - res = gst_caps_intersect (caps, gst_pad_template_get_caps (templ)); - - gst_caps_unref (caps); - gst_object_unref (templ); - - if (!gst_pad_set_caps (pngdec->srcpad, res)) - ret = GST_FLOW_NOT_NEGOTIATED; - - GST_DEBUG_OBJECT (pngdec, "our caps %" GST_PTR_FORMAT, res); - - gst_caps_unref (res); - - /* Push a newsegment event */ - if (pngdec->need_newsegment) { - gst_pad_push_event (pngdec->srcpad, - gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0)); - pngdec->need_newsegment = FALSE; - } - -beach: - return ret; -} - -static void -gst_pngdec_task (GstPad * pad) -{ - GstPngDec *pngdec; - GstBuffer *buffer = NULL; - size_t buffer_size = 0; - gint i = 0; - png_bytep *rows, inp; - png_uint_32 rowbytes; - GstFlowReturn ret = GST_FLOW_OK; - - pngdec = GST_PNGDEC (GST_OBJECT_PARENT (pad)); - - GST_LOG_OBJECT (pngdec, "read frame"); - - /* Let libpng come back here on error */ - if (setjmp (png_jmpbuf (pngdec->png))) { - ret = GST_FLOW_ERROR; - goto pause; - } - - /* Set reading callback */ - png_set_read_fn (pngdec->png, pngdec, user_read_data); - - /* Read info */ - png_read_info (pngdec->png, pngdec->info); - - /* Generate the caps and configure */ - ret = gst_pngdec_caps_create_and_set (pngdec); - if (ret != GST_FLOW_OK) { - goto pause; - } - - /* Allocate output buffer */ - rowbytes = png_get_rowbytes (pngdec->png, pngdec->info); - buffer_size = pngdec->height * GST_ROUND_UP_4 (rowbytes); - ret = - gst_pad_alloc_buffer_and_set_caps (pngdec->srcpad, GST_BUFFER_OFFSET_NONE, - buffer_size, GST_PAD_CAPS (pngdec->srcpad), &buffer); - if (ret != GST_FLOW_OK) - goto pause; - - rows = (png_bytep *) g_malloc (sizeof (png_bytep) * pngdec->height); - - inp = GST_BUFFER_DATA (buffer); - - for (i = 0; i < pngdec->height; i++) { - rows[i] = inp; - inp += GST_ROUND_UP_4 (rowbytes); - } - - /* Read the actual picture */ - png_read_image (pngdec->png, rows); - free (rows); - - /* Push the raw RGB frame */ - ret = gst_pad_push (pngdec->srcpad, buffer); - if (ret != GST_FLOW_OK) - goto pause; - - /* And we are done */ - gst_pad_pause_task (pngdec->sinkpad); - gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ()); - return; - -pause: - { - GST_INFO_OBJECT (pngdec, "pausing task, reason %s", - gst_flow_get_name (ret)); - gst_pad_pause_task (pngdec->sinkpad); - if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) { - GST_ELEMENT_ERROR (pngdec, STREAM, FAILED, - (_("Internal data stream error.")), - ("stream stopped, reason %s", gst_flow_get_name (ret))); - gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ()); - } - } -} - -static GstFlowReturn -gst_pngdec_chain (GstPad * pad, GstBuffer * buffer) -{ - GstPngDec *pngdec; - GstFlowReturn ret = GST_FLOW_OK; - - pngdec = GST_PNGDEC (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (pngdec, "Got buffer, size=%u", GST_BUFFER_SIZE (buffer)); - - if (G_UNLIKELY (!pngdec->setup)) - goto not_configured; - - /* Something is going wrong in our callbacks */ - ret = pngdec->ret; - if (G_UNLIKELY (ret != GST_FLOW_OK)) { - GST_WARNING_OBJECT (pngdec, "we have a pending return code of %d", ret); - goto beach; - } - - /* Let libpng come back here on error */ - if (setjmp (png_jmpbuf (pngdec->png))) { - GST_WARNING_OBJECT (pngdec, "error during decoding"); - ret = GST_FLOW_ERROR; - goto beach; - } - - pngdec->in_timestamp = GST_BUFFER_TIMESTAMP (buffer); - pngdec->in_duration = GST_BUFFER_DURATION (buffer); - - /* Progressive loading of the PNG image */ - png_process_data (pngdec->png, pngdec->info, GST_BUFFER_DATA (buffer), - GST_BUFFER_SIZE (buffer)); - - if (pngdec->image_ready) { - if (pngdec->framed) { - /* Reset ourselves for the next frame */ - gst_pngdec_libpng_clear (pngdec); - gst_pngdec_libpng_init (pngdec); - GST_LOG_OBJECT (pngdec, "setting up callbacks for next frame"); - png_set_progressive_read_fn (pngdec->png, pngdec, - user_info_callback, user_endrow_callback, user_end_callback); - } else { - GST_LOG_OBJECT (pngdec, "sending EOS"); - pngdec->ret = gst_pad_push_event (pngdec->srcpad, gst_event_new_eos ()); - } - pngdec->image_ready = FALSE; - } - - /* grab new return code */ - ret = pngdec->ret; - - /* And release the buffer */ - gst_buffer_unref (buffer); - -beach: - gst_object_unref (pngdec); - - return ret; - - /* ERRORS */ -not_configured: - { - GST_LOG_OBJECT (pngdec, "we are not configured yet"); - ret = GST_FLOW_WRONG_STATE; - goto beach; - } -} - -static gboolean -gst_pngdec_sink_setcaps (GstPad * pad, GstCaps * caps) -{ - GstStructure *s; - GstPngDec *pngdec; - gint num, denom; - - pngdec = GST_PNGDEC (gst_pad_get_parent (pad)); - - s = gst_caps_get_structure (caps, 0); - if (gst_structure_get_fraction (s, "framerate", &num, &denom)) { - GST_DEBUG_OBJECT (pngdec, "framed input"); - pngdec->framed = TRUE; - pngdec->fps_n = num; - pngdec->fps_d = denom; - } else { - GST_DEBUG_OBJECT (pngdec, "single picture input"); - pngdec->framed = FALSE; - pngdec->fps_n = 0; - pngdec->fps_d = 1; - } - - gst_object_unref (pngdec); - return TRUE; -} - -static gboolean -gst_pngdec_sink_event (GstPad * pad, GstEvent * event) -{ - GstPngDec *pngdec; - gboolean res; - - pngdec = GST_PNGDEC (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT:{ - gdouble rate, arate; - gboolean update; - gint64 start, stop, position; - GstFormat fmt; - - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt, - &start, &stop, &position); - - gst_segment_set_newsegment_full (&pngdec->segment, update, rate, arate, - fmt, start, stop, position); - - GST_LOG_OBJECT (pngdec, "NEWSEGMENT (%s)", gst_format_get_name (fmt)); - - if (fmt == GST_FORMAT_TIME) { - pngdec->need_newsegment = FALSE; - res = gst_pad_push_event (pngdec->srcpad, event); - } else { - gst_event_unref (event); - res = TRUE; - } - break; - } - case GST_EVENT_FLUSH_STOP: - { - gst_pngdec_libpng_clear (pngdec); - gst_pngdec_libpng_init (pngdec); - png_set_progressive_read_fn (pngdec->png, pngdec, - user_info_callback, user_endrow_callback, user_end_callback); - pngdec->ret = GST_FLOW_OK; - gst_segment_init (&pngdec->segment, GST_FORMAT_UNDEFINED); - res = gst_pad_push_event (pngdec->srcpad, event); - break; - } - case GST_EVENT_EOS: - { - GST_LOG_OBJECT (pngdec, "EOS"); - gst_pngdec_libpng_clear (pngdec); - pngdec->ret = GST_FLOW_UNEXPECTED; - res = gst_pad_push_event (pngdec->srcpad, event); - break; - } - default: - res = gst_pad_push_event (pngdec->srcpad, event); - break; - } - - gst_object_unref (pngdec); - return res; -} - - -/* Clean up the libpng structures */ -static gboolean -gst_pngdec_libpng_clear (GstPngDec * pngdec) -{ - png_infopp info = NULL, endinfo = NULL; - - g_return_val_if_fail (GST_IS_PNGDEC (pngdec), FALSE); - - GST_LOG ("cleaning up libpng structures"); - - if (pngdec->info) { - info = &pngdec->info; - } - - if (pngdec->endinfo) { - endinfo = &pngdec->endinfo; - } - - if (pngdec->png) { - png_destroy_read_struct (&(pngdec->png), info, endinfo); - pngdec->png = NULL; - pngdec->info = NULL; - pngdec->endinfo = NULL; - } - - pngdec->bpp = pngdec->color_type = pngdec->height = pngdec->width = -1; - pngdec->offset = 0; - pngdec->rowbytes = 0; - pngdec->buffer_out = NULL; - - pngdec->setup = FALSE; - - pngdec->in_timestamp = GST_CLOCK_TIME_NONE; - pngdec->in_duration = GST_CLOCK_TIME_NONE; - - return TRUE; -} - -static gboolean -gst_pngdec_libpng_init (GstPngDec * pngdec) -{ - g_return_val_if_fail (GST_IS_PNGDEC (pngdec), FALSE); - - if (pngdec->setup) - return TRUE; - - GST_LOG ("init libpng structures"); - - /* initialize png struct stuff */ - pngdec->png = png_create_read_struct (PNG_LIBPNG_VER_STRING, - (png_voidp) NULL, user_error_fn, user_warning_fn); - - if (pngdec->png == NULL) - goto init_failed; - - pngdec->info = png_create_info_struct (pngdec->png); - if (pngdec->info == NULL) - goto info_failed; - - pngdec->endinfo = png_create_info_struct (pngdec->png); - if (pngdec->endinfo == NULL) - goto endinfo_failed; - - pngdec->setup = TRUE; - - return TRUE; - - /* ERRORS */ -init_failed: - { - GST_ELEMENT_ERROR (pngdec, LIBRARY, INIT, (NULL), - ("Failed to initialize png structure")); - return FALSE; - } -info_failed: - { - gst_pngdec_libpng_clear (pngdec); - GST_ELEMENT_ERROR (pngdec, LIBRARY, INIT, (NULL), - ("Failed to initialize info structure")); - return FALSE; - } -endinfo_failed: - { - gst_pngdec_libpng_clear (pngdec); - GST_ELEMENT_ERROR (pngdec, LIBRARY, INIT, (NULL), - ("Failed to initialize endinfo structure")); - return FALSE; - } -} - -static GstStateChangeReturn -gst_pngdec_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret; - GstPngDec *pngdec; - - pngdec = GST_PNGDEC (element); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_pngdec_libpng_init (pngdec); - pngdec->need_newsegment = TRUE; - pngdec->framed = FALSE; - pngdec->ret = GST_FLOW_OK; - gst_segment_init (&pngdec->segment, GST_FORMAT_UNDEFINED); - break; - default: - break; - } - - ret = parent_class->change_state (element, transition); - if (ret != GST_STATE_CHANGE_SUCCESS) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_pngdec_libpng_clear (pngdec); - break; - default: - break; - } - - return ret; -} - -/* this function gets called when we activate ourselves in push mode. */ -static gboolean -gst_pngdec_sink_activate_push (GstPad * sinkpad, gboolean active) -{ - GstPngDec *pngdec; - - pngdec = GST_PNGDEC (GST_OBJECT_PARENT (sinkpad)); - - pngdec->ret = GST_FLOW_OK; - - if (active) { - /* Let libpng come back here on error */ - if (setjmp (png_jmpbuf (pngdec->png))) - goto setup_failed; - - GST_LOG ("setting up progressive loading callbacks"); - png_set_progressive_read_fn (pngdec->png, pngdec, - user_info_callback, user_endrow_callback, user_end_callback); - } - return TRUE; - -setup_failed: - { - GST_LOG ("failed setting up libpng jmpbuf"); - gst_pngdec_libpng_clear (pngdec); - return FALSE; - } -} - -/* this function gets called when we activate ourselves in pull mode. - * We can perform random access to the resource and we start a task - * to start reading */ -static gboolean -gst_pngdec_sink_activate_pull (GstPad * sinkpad, gboolean active) -{ - if (active) { - return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_pngdec_task, - sinkpad); - } else { - return gst_pad_stop_task (sinkpad); - } -} - -/* this function is called when the pad is activated and should start - * processing data. - * - * We check if we can do random access to decide if we work push or - * pull based. - */ -static gboolean -gst_pngdec_sink_activate (GstPad * sinkpad) -{ - if (gst_pad_check_pull_range (sinkpad)) { - return gst_pad_activate_pull (sinkpad, TRUE); - } else { - return gst_pad_activate_push (sinkpad, TRUE); - } -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/ext/libpng/gstpngdec.h --- a/gst_plugins_good/ext/libpng/gstpngdec.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* GStreamer - * 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. - */ - - -#ifndef __GST_PNGDEC_H__ -#define __GST_PNGDEC_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define GST_TYPE_PNGDEC (gst_pngdec_get_type()) -#define GST_PNGDEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PNGDEC,GstPngDec)) -#define GST_PNGDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PNGDEC,GstPngDecClass)) -#define GST_IS_PNGDEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PNGDEC)) -#define GST_IS_PNGDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PNGDEC)) - -typedef struct _GstPngDec GstPngDec; -typedef struct _GstPngDecClass GstPngDecClass; - -struct _GstPngDec -{ - GstElement element; - - GstPad *sinkpad, *srcpad; - - gboolean need_newsegment; - - /* Progressive */ - GstBuffer *buffer_out; - GstFlowReturn ret; - png_uint_32 rowbytes; - - /* Pull range */ - gint offset; - - png_structp png; - png_infop info; - png_infop endinfo; - gboolean setup; - - gint width; - gint height; - gint bpp; - gint color_type; - gint fps_n; - gint fps_d; - - /* Chain */ - gboolean framed; - GstClockTime in_timestamp; - GstClockTime in_duration; - - GstSegment segment; - gboolean image_ready; -}; - -struct _GstPngDecClass -{ - GstElementClass parent_class; -}; - -GType gst_pngdec_get_type(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - -#endif /* __GST_PNGDEC_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/ext/libpng/gstpngenc.c --- a/gst_plugins_good/ext/libpng/gstpngenc.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,394 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * Filter: - * Copyright (C) 2000 Donald A. Graft - * - * 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. - * - */ -/** - * SECTION:element-pngenc - * - * Encodes png images. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include -#include "gstpngenc.h" -#include -#include - -#define MAX_HEIGHT 4096 - - -static const GstElementDetails gst_pngenc_details = -GST_ELEMENT_DETAILS ("PNG image encoder", - "Codec/Encoder/Image", - "Encode a video frame to a .png image", - "Jeremy SIMON "); - -GST_DEBUG_CATEGORY_STATIC (pngenc_debug); -#define GST_CAT_DEFAULT pngenc_debug - -/* Filter signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -#define DEFAULT_SNAPSHOT TRUE -/* #define DEFAULT_NEWMEDIA FALSE */ -#define DEFAULT_COMPRESSION_LEVEL 6 - -enum -{ - ARG_0, - ARG_SNAPSHOT, -/* ARG_NEWMEDIA, */ - ARG_COMPRESSION_LEVEL -}; - -static GstStaticPadTemplate pngenc_src_template = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("image/png, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0.0, MAX ]") - ); - -static GstStaticPadTemplate pngenc_sink_template = - GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_RGB) - ); - -/* static GstElementClass *parent_class = NULL; */ - -GST_BOILERPLATE (GstPngEnc, gst_pngenc, GstElement, GST_TYPE_ELEMENT); - -static void gst_pngenc_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_pngenc_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); - -static GstFlowReturn gst_pngenc_chain (GstPad * pad, GstBuffer * data); - -static void -user_error_fn (png_structp png_ptr, png_const_charp error_msg) -{ - g_warning ("%s", error_msg); -} - -static void -user_warning_fn (png_structp png_ptr, png_const_charp warning_msg) -{ - g_warning ("%s", warning_msg); -} - -static void -gst_pngenc_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template - (element_class, gst_static_pad_template_get (&pngenc_sink_template)); - gst_element_class_add_pad_template - (element_class, gst_static_pad_template_get (&pngenc_src_template)); - gst_element_class_set_details (element_class, &gst_pngenc_details); -} - -static void -gst_pngenc_class_init (GstPngEncClass * klass) -{ - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->get_property = gst_pngenc_get_property; - gobject_class->set_property = gst_pngenc_set_property; - - g_object_class_install_property (gobject_class, ARG_SNAPSHOT, - g_param_spec_boolean ("snapshot", "Snapshot", - "Send EOS after encoding a frame, useful for snapshots", - DEFAULT_SNAPSHOT, (GParamFlags) G_PARAM_READWRITE)); - -/* g_object_class_install_property (gobject_class, ARG_NEWMEDIA, */ -/* g_param_spec_boolean ("newmedia", "newmedia", */ -/* "Send new media discontinuity after encoding each frame", */ -/* DEFAULT_NEWMEDIA, (GParamFlags) G_PARAM_READWRITE)); */ - - g_object_class_install_property - (gobject_class, ARG_COMPRESSION_LEVEL, - g_param_spec_uint ("compression-level", "compression-level", - "PNG compression level", - Z_NO_COMPRESSION, Z_BEST_COMPRESSION, - DEFAULT_COMPRESSION_LEVEL, (GParamFlags) G_PARAM_READWRITE)); - - GST_DEBUG_CATEGORY_INIT (pngenc_debug, "pngenc", 0, "PNG image encoder"); -} - - -static gboolean -gst_pngenc_setcaps (GstPad * pad, GstCaps * caps) -{ - GstPngEnc *pngenc; - const GValue *fps; - GstStructure *structure; - GstCaps *pcaps; - gboolean ret = TRUE; - - pngenc = GST_PNGENC (gst_pad_get_parent (pad)); - - structure = gst_caps_get_structure (caps, 0); - gst_structure_get_int (structure, "width", &pngenc->width); - gst_structure_get_int (structure, "height", &pngenc->height); - fps = gst_structure_get_value (structure, "framerate"); - gst_structure_get_int (structure, "bpp", &pngenc->bpp); - - if (pngenc->bpp == 32) - pngenc->stride = pngenc->width * 4; - else - pngenc->stride = GST_ROUND_UP_4 (pngenc->width * 3); - - pcaps = gst_caps_new_simple ("image/png", - "width", G_TYPE_INT, pngenc->width, - "height", G_TYPE_INT, pngenc->height, NULL); - structure = gst_caps_get_structure (pcaps, 0); - gst_structure_set_value (structure, "framerate", fps); - - ret = gst_pad_set_caps (pngenc->srcpad, pcaps); - - gst_caps_unref (pcaps); - gst_object_unref (pngenc); - - return ret; -} - -static void -gst_pngenc_init (GstPngEnc * pngenc, GstPngEncClass * g_class) -{ - /* sinkpad */ - pngenc->sinkpad = gst_pad_new_from_static_template - (&pngenc_sink_template, "sink"); - gst_pad_set_chain_function (pngenc->sinkpad, gst_pngenc_chain); - /* gst_pad_set_link_function (pngenc->sinkpad, gst_pngenc_sinklink); */ - /* gst_pad_set_getcaps_function (pngenc->sinkpad, gst_pngenc_sink_getcaps); */ - gst_pad_set_setcaps_function (pngenc->sinkpad, gst_pngenc_setcaps); - gst_element_add_pad (GST_ELEMENT (pngenc), pngenc->sinkpad); - - /* srcpad */ - pngenc->srcpad = gst_pad_new_from_static_template - (&pngenc_src_template, "src"); - /* pngenc->srcpad = gst_pad_new ("src", GST_PAD_SRC); */ - /* gst_pad_set_getcaps_function (pngenc->srcpad, gst_pngenc_src_getcaps); */ - /* gst_pad_set_setcaps_function (pngenc->srcpad, gst_pngenc_setcaps); */ - gst_element_add_pad (GST_ELEMENT (pngenc), pngenc->srcpad); - - /* init settings */ - pngenc->png_struct_ptr = NULL; - pngenc->png_info_ptr = NULL; - - pngenc->snapshot = DEFAULT_SNAPSHOT; -/* pngenc->newmedia = FALSE; */ - pngenc->compression_level = DEFAULT_COMPRESSION_LEVEL; -} - -static void -user_flush_data (png_structp png_ptr G_GNUC_UNUSED) -{ -} - -static void -user_write_data (png_structp png_ptr, png_bytep data, png_uint_32 length) -{ - GstPngEnc *pngenc; - - pngenc = (GstPngEnc *) png_get_io_ptr (png_ptr); - - if (pngenc->written + length >= GST_BUFFER_SIZE (pngenc->buffer_out)) { - GST_ERROR_OBJECT (pngenc, "output buffer bigger than the input buffer!?"); - /* yuck */ - longjmp (pngenc->png_struct_ptr->jmpbuf, 1); - - /* never reached */ - return; - } - - memcpy (GST_BUFFER_DATA (pngenc->buffer_out) + pngenc->written, data, length); - pngenc->written += length; -} - -static GstFlowReturn -gst_pngenc_chain (GstPad * pad, GstBuffer * buf) -{ - GstPngEnc *pngenc; - gint row_index; - png_byte *row_pointers[MAX_HEIGHT]; - GstFlowReturn ret = GST_FLOW_OK; - GstBuffer *encoded_buf = NULL; - - pngenc = GST_PNGENC (gst_pad_get_parent (pad)); - - GST_DEBUG_OBJECT (pngenc, "BEGINNING"); - - /* initialize png struct stuff */ - pngenc->png_struct_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, - (png_voidp) NULL, user_error_fn, user_warning_fn); - if (pngenc->png_struct_ptr == NULL) { - gst_buffer_unref (buf); - GST_ELEMENT_ERROR (pngenc, LIBRARY, INIT, (NULL), - ("Failed to initialize png structure")); - ret = GST_FLOW_ERROR; - goto done; - } - - pngenc->png_info_ptr = png_create_info_struct (pngenc->png_struct_ptr); - if (!pngenc->png_info_ptr) { - gst_buffer_unref (buf); - png_destroy_write_struct (&(pngenc->png_struct_ptr), (png_infopp) NULL); - GST_ELEMENT_ERROR (pngenc, LIBRARY, INIT, (NULL), - ("Failed to initialize the png info structure")); - ret = GST_FLOW_ERROR; - goto done; - } - - /* non-0 return is from a longjmp inside of libpng */ - if (setjmp (pngenc->png_struct_ptr->jmpbuf) != 0) { - gst_buffer_unref (buf); - png_destroy_write_struct (&pngenc->png_struct_ptr, &pngenc->png_info_ptr); - GST_ELEMENT_ERROR (pngenc, LIBRARY, FAILED, (NULL), - ("returning from longjmp")); - ret = GST_FLOW_ERROR; - goto done; - } - - png_set_filter (pngenc->png_struct_ptr, 0, - PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE); - png_set_compression_level (pngenc->png_struct_ptr, pngenc->compression_level); - - png_set_IHDR (pngenc->png_struct_ptr, - pngenc->png_info_ptr, - pngenc->width, - pngenc->height, - 8, - (pngenc->bpp == 32) ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - png_set_write_fn (pngenc->png_struct_ptr, pngenc, - (png_rw_ptr) user_write_data, user_flush_data); - - for (row_index = 0; row_index < pngenc->height; row_index++) { - row_pointers[row_index] = GST_BUFFER_DATA (buf) + - (row_index * pngenc->stride); - } - - /* allocate the output buffer */ - pngenc->buffer_out = - gst_buffer_new_and_alloc (pngenc->height * pngenc->stride); - pngenc->written = 0; - - png_write_info (pngenc->png_struct_ptr, pngenc->png_info_ptr); - png_write_image (pngenc->png_struct_ptr, row_pointers); - png_write_end (pngenc->png_struct_ptr, NULL); - - encoded_buf = gst_buffer_create_sub (pngenc->buffer_out, 0, pngenc->written); - - png_destroy_info_struct (pngenc->png_struct_ptr, &pngenc->png_info_ptr); - png_destroy_write_struct (&pngenc->png_struct_ptr, (png_infopp) NULL); - gst_buffer_copy_metadata (encoded_buf, buf, GST_BUFFER_COPY_TIMESTAMPS); - gst_buffer_unref (buf); - gst_buffer_set_caps (encoded_buf, GST_PAD_CAPS (pngenc->srcpad)); - - if ((ret = gst_pad_push (pngenc->srcpad, encoded_buf)) != GST_FLOW_OK) - goto done; - - if (pngenc->snapshot) { - GstEvent *event; - - GST_DEBUG_OBJECT (pngenc, "snapshot mode, sending EOS"); - /* send EOS event, since a frame has been pushed out */ - event = gst_event_new_eos (); - - gst_pad_push_event (pngenc->srcpad, event); - ret = GST_FLOW_UNEXPECTED; - } - -done: - GST_DEBUG_OBJECT (pngenc, "END, ret:%d", ret); - - if (pngenc->buffer_out != NULL) { - gst_buffer_unref (pngenc->buffer_out); - pngenc->buffer_out = NULL; - } - - gst_object_unref (pngenc); - return ret; -} - - -static void -gst_pngenc_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec) -{ - GstPngEnc *pngenc; - - pngenc = GST_PNGENC (object); - - switch (prop_id) { - case ARG_SNAPSHOT: - g_value_set_boolean (value, pngenc->snapshot); - break; -/* case ARG_NEWMEDIA: */ -/* g_value_set_boolean (value, pngenc->newmedia); */ -/* break; */ - case ARG_COMPRESSION_LEVEL: - g_value_set_uint (value, pngenc->compression_level); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - - -static void -gst_pngenc_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ - GstPngEnc *pngenc; - - pngenc = GST_PNGENC (object); - - switch (prop_id) { - case ARG_SNAPSHOT: - pngenc->snapshot = g_value_get_boolean (value); - break; -/* case ARG_NEWMEDIA: */ -/* pngenc->newmedia = g_value_get_boolean (value); */ -/* break; */ - case ARG_COMPRESSION_LEVEL: - pngenc->compression_level = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/ext/libpng/gstpngenc.h --- a/gst_plugins_good/ext/libpng/gstpngenc.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* GStreamer - * 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. - */ - - -#ifndef __GST_PNGENC_H__ -#define __GST_PNGENC_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -#define GST_TYPE_PNGENC (gst_pngenc_get_type()) -#define GST_PNGENC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PNGENC,GstPngEnc)) -#define GST_PNGENC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PNGENC,GstPngEncClass)) -#define GST_IS_PNGENC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PNGENC)) -#define GST_IS_PNGENC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PNGENC)) - -typedef struct _GstPngEnc GstPngEnc; -typedef struct _GstPngEncClass GstPngEncClass; - -struct _GstPngEnc -{ - GstElement element; - - GstPad *sinkpad, *srcpad; - GstBuffer *buffer_out; - guint written; - - png_structp png_struct_ptr; - png_infop png_info_ptr; - - gint width; - gint height; - gint bpp; - gint stride; - guint compression_level; - - gboolean snapshot; - gboolean newmedia; -}; - -struct _GstPngEncClass -{ - GstElementClass parent_class; -}; - -GType gst_pngenc_get_type(void); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - -#endif /* __GST_PNGENC_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/group/bld.inf --- a/gst_plugins_good/group/bld.inf Fri Jul 09 16:26:45 2010 -0500 +++ b/gst_plugins_good/group/bld.inf Fri Aug 06 16:36:50 2010 -0500 @@ -6,8 +6,4 @@ PRJ_MMPFILES gstwavparse.mmp gstwavenc.mmp -gstautodetect.mmp -gstavi.mmp gstqtmux.mmp -gstqtdemux.mmp -gstmpegaudioparse.mmp diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/group/gstalaw.mmp --- a/gst_plugins_good/group/gstalaw.mmp Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -// Gstreamer.MMP -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - - -#include - -TARGET libgstalaw.dll -TARGETTYPE DLL -UID 0x20004c47 0x0DE80A1D - -#ifdef EKA2 -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT -#endif - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO __SYMBIAN32__ -MACRO HAVE_CONFIG_H -MACRO __SYMBIAN32__ - -USERINCLUDE .. -USERINCLUDE ../gst/law -USERINCLUDE ../gst-libs -USERINCLUDE ../gst-libs/gst - - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE -MW_LAYER_GSTREAMER_SYSTEMINCLUDE - -SOURCEPATH ../gst/law -SOURCE alaw.c -SOURCE alaw-decode.c -SOURCE alaw-encode.c - -LIBRARY libc.lib -LIBRARY libglib.lib -LIBRARY libgobject.lib -LIBRARY libgstreamer.lib -LIBRARY libgstbase.lib - - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/group/gstalpha.mmp --- a/gst_plugins_good/group/gstalpha.mmp Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ -/* -============================================================================ - Name : gstalpha.mmp - Author : - Copyright : Your copyright notice - Description : This is the project specification file for alpha. -============================================================================ -*/ - -#include -TARGET libgstalpha.dll -TARGETTYPE dll -UID 0x1000008d 0x0B6AF79A - -#ifdef EKA2 -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT -#endif - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO SYMBIAN -MACRO HAVE_CONFIG_H -MACRO __SYMBIAN32__ - -USERINCLUDE ../../.. -USERINCLUDE .. -USERINCLUDE ../gst/alpha -USERINCLUDE ../gst-libs -USERINCLUDE ../gst-libs/gst - - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE -MW_LAYER_GSTREAMER_SYSTEMINCLUDE - -SOURCEPATH ../gst/alpha -SOURCE gstalpha.c - -LIBRARY libc.lib -LIBRARY libm.lib -LIBRARY libglib.lib -LIBRARY libgobject.lib -LIBRARY libgstreamer.lib -LIBRARY libgstbase.lib -LIBRARY libgstriff.lib -LIBRARY libgstcontroller.lib -LIBRARY libgstvideo.lib \ No newline at end of file diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/group/gstalphacolor.mmp --- a/gst_plugins_good/group/gstalphacolor.mmp Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ -/* -============================================================================ - Name : alphacolor.mmp - Author : - Copyright : Your copyright notice - Description : This is the project specification file for alpha. -============================================================================ -*/ -#include -TARGET libgstalphacolor.dll -TARGETTYPE dll -UID 0x1000008d 0x0B6AF79B - -#ifdef EKA2 -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT -#endif - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO SYMBIAN -MACRO HAVE_CONFIG_H -MACRO __SYMBIAN32__ - -USERINCLUDE ../../.. -USERINCLUDE .. -USERINCLUDE ../gst/alpha -USERINCLUDE ../gst-libs -USERINCLUDE ../gst-libs/gst - - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE -MW_LAYER_GSTREAMER_SYSTEMINCLUDE - -SOURCEPATH ../gst/alpha -SOURCE gstalphacolor.c - -LIBRARY libc.lib -LIBRARY libm.lib -LIBRARY libglib.lib -LIBRARY libgobject.lib -LIBRARY libgstreamer.lib -LIBRARY libgstbase.lib -LIBRARY libgstriff.lib -LIBRARY libgstcontroller.lib -LIBRARY libgstvideo.lib \ No newline at end of file diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/group/gstaudiofx.mmp --- a/gst_plugins_good/group/gstaudiofx.mmp Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -// Gstreamer.MMP -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - - -#include - -TARGET libgstaudiofx.dll -TARGETTYPE DLL -UID 0x20004c49 0x0DE80A1F - -#ifdef EKA2 -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT -#endif - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO __SYMBIAN32__ -MACRO HAVE_CONFIG_H -MACRO __SYMBIAN32__ - -USERINCLUDE .. -USERINCLUDE ../gst/audiofx -USERINCLUDE ../gst-libs -USERINCLUDE ../gst-libs/gst - - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE -MW_LAYER_GSTREAMER_SYSTEMINCLUDE - -SOURCEPATH ../gst/audiofx -SOURCE audioamplify.c - -SOURCE audiocheblimit.c -SOURCE audiodynamic.c -SOURCE audioecho.c -SOURCE audiofirfilter.c -SOURCE audiofx.c -SOURCE audiofxbasefirfilter.c -SOURCE audiofxbaseiirfilter.c -SOURCE audioiirfilter.c -SOURCE audioinvert.c -SOURCE audiokaraoke.c -SOURCE audiochebband.c -SOURCE audiopanorama.c -SOURCE audiowsinclimit.c -SOURCE audiowsincband.c - - -LIBRARY libc.lib -LIBRARY libglib.lib -LIBRARY libgobject.lib -LIBRARY libgstreamer.lib -LIBRARY libgstbase.lib -LIBRARY libgstcontroller.lib -LIBRARY libgstaudio.lib -LIBRARY libm.lib - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/group/gstauparse.mmp --- a/gst_plugins_good/group/gstauparse.mmp Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -// Gstreamer.MMP -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - - -#include - -TARGET libgstauparse.dll -TARGETTYPE DLL -UID 0x20004c46 0x0DE80A1C - -#ifdef EKA2 -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT -#endif - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO __SYMBIAN32__ -MACRO HAVE_CONFIG_H -MACRO __SYMBIAN32__ - -USERINCLUDE .. -USERINCLUDE ../gst/auparse -USERINCLUDE ../gst-libs -USERINCLUDE ../gst-libs/gst - - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE -MW_LAYER_GSTREAMER_SYSTEMINCLUDE - - -SOURCEPATH ../gst/auparse -SOURCE gstauparse.c - -LIBRARY libc.lib -LIBRARY libglib.lib -LIBRARY libgobject.lib -LIBRARY libgstreamer.lib -LIBRARY libgstbase.lib - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/group/gstautodetect.mmp --- a/gst_plugins_good/group/gstautodetect.mmp Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -// gstautodetect.mmp -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - -#include - -TARGET libgstautodetect.dll -TARGETTYPE DLL -UID 0x1000008d 0x2001F446 -//TARGETTYPE STDDLL -//UID 0x20004c45 0x0DE80A1D - - -LANG SC -CAPABILITY All -TCB -VENDORID VID_DEFAULT - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO HAVE_CONFIG_H - - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE -MW_LAYER_GSTREAMER_SYSTEMINCLUDE - -USERINCLUDE ../ - - - -SOURCEPATH ../gst/autodetect -SOURCE gstautodetect.c -SOURCE gstautoaudiosrc.c -SOURCE gstautovideosrc.c -SOURCE gstautoaudiosink.c -SOURCE gstautovideosink.c - -LIBRARY libc.lib -LIBRARY libglib.lib -LIBRARY libgobject.lib -LIBRARY libgstreamer.lib - -#ifdef WINSCW -LIBRARY ewsd.lib //wsd solution -#endif - - -SMPSAFE diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/group/gstavi.mmp --- a/gst_plugins_good/group/gstavi.mmp Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - -#include - -TARGET libgstavi.dll -TARGETTYPE DLL -UID 0x20004c46 0x0DE80A1C - -#ifdef EKA2 -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT -#endif - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO SYMBIAN -MACRO HAVE_CONFIG_H -MACRO __SYMBIAN32__ - -USERINCLUDE ../../.. -USERINCLUDE .. -USERINCLUDE ../gst/avi -USERINCLUDE ../gst-libs -USERINCLUDE ../gst-libs/gst - - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE -MW_LAYER_GSTREAMER_SYSTEMINCLUDE - -SOURCEPATH ../gst/avi -SOURCE gstavi.c gstavimux.c gstavidemux.c gstavisubtitle.c - -LIBRARY libc.lib -LIBRARY libglib.lib -LIBRARY libgobject.lib -LIBRARY libgstreamer.lib -LIBRARY libgstbase.lib -LIBRARY libgstriff.lib - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/group/gstjpeg.mmp --- a/gst_plugins_good/group/gstjpeg.mmp Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - - -#include - -TARGET libgstjpeg.dll -TARGETTYPE DLL -UID 0x1000008d 0x0FDE0317 - -#ifdef EKA2 -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT -#endif - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -USERINCLUDE ../ext/jpeg/. -USERINCLUDE ../gst-libs/gst/. -USERINCLUDE ../. - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE - -MW_LAYER_GSTREAMER_SYSTEMINCLUDE - -SYSTEMINCLUDE /epoc32/include/jpeg-6b - -SOURCEPATH ../ext/jpeg -SOURCE gstjpeg.c -SOURCE gstjpegdec.c -SOURCE gstjpegenc.c -SOURCE gstsmokedec.c -SOURCE gstsmokeenc.c -SOURCE smokecodec.c - -LIBRARY euser.lib -LIBRARY libc.lib libm.lib -LIBRARY libgobject.lib libglib.lib -LIBRARY libgstreamer.lib -LIBRARY libjpeg.lib - -MACRO __SYMBIAN32__ -MACRO HAVE_CONFIG_H -MACRO __SYMBIAN32__ - -EPOCSTACKSIZE 0x12000 \ No newline at end of file diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/group/gstmpegaudioparse.mmp --- a/gst_plugins_good/group/gstmpegaudioparse.mmp Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - -#include - -TARGET libgstmpegaudioparse.dll -TARGETTYPE DLL -UID 0x1000008d 0x10207C45 -CAPABILITY All -TCB -VENDORID VID_DEFAULT -LANG SC - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - - -MACRO HAVE_CONFIG_H - - -USERINCLUDE ../gst/mpegaudioparse - - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE -MW_LAYER_GSTREAMER_SYSTEMINCLUDE - -SOURCEPATH ../gst/mpegaudioparse -SOURCE gstmpegaudioparse.c -SOURCE gstxingmux.c -SOURCE plugin.c - -LIBRARY euser.lib -LIBRARY libc.lib -LIBRARY libpthread.lib -LIBRARY libglib.lib -LIBRARY libgobject.lib -LIBRARY libgstreamer.lib -LIBRARY libgstbase.lib -LIBRARY libgthread.lib - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/group/gstmulaw.mmp --- a/gst_plugins_good/group/gstmulaw.mmp Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - -#include - -TARGET libgstmulaw.dll -TARGETTYPE DLL -UID 0x20004c48 0x0DE80A1E - -#ifdef EKA2 -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT -#endif - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO __SYMBIAN32__ -MACRO HAVE_CONFIG_H -MACRO __SYMBIAN32__ - -USERINCLUDE .. -USERINCLUDE ../gst/law -USERINCLUDE ../gst-libs -USERINCLUDE ../gst-libs/gst - - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE -MW_LAYER_GSTREAMER_SYSTEMINCLUDE - -SOURCEPATH ../gst/law -SOURCE mulaw.c -SOURCE mulaw-conversion.c -SOURCE mulaw-decode.c -SOURCE mulaw-encode.c - - -LIBRARY libc.lib -LIBRARY libglib.lib -LIBRARY libgobject.lib -LIBRARY libgstreamer.lib -LIBRARY libgstbase.lib - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/group/gstpng.mmp --- a/gst_plugins_good/group/gstpng.mmp Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ -/* -============================================================================ - Name : libgstpng.mmp - Author : - Copyright : Your copyright notice - Description : This is the project specification file for libpng. -============================================================================ -*/ - -#include - -TARGET libgstpng.dll -TARGETTYPE dll -UID 0x1000008d 0x011746FD - -#ifdef EKA2 -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT -#endif - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO SYMBIAN -MACRO HAVE_CONFIG_H -MACRO __SYMBIAN32__ - -USERINCLUDE ../../.. -USERINCLUDE .. -USERINCLUDE ../ext/libpng -USERINCLUDE ../gst-libs -USERINCLUDE ../gst-libs/gst - - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE -MW_LAYER_GSTREAMER_SYSTEMINCLUDE -USERINCLUDE /epoc32/include/libpng - -SOURCEPATH ../ext/libpng -SOURCE gstpng.c gstpngdec.c gstpngenc.c - -LIBRARY libc.lib -LIBRARY libm.lib -LIBRARY libglib.lib -LIBRARY libgobject.lib -LIBRARY libgstreamer.lib -LIBRARY libgstbase.lib -LIBRARY libgstriff.lib -LIBRARY libgstcontroller.lib -LIBRARY libgstvideo.lib -LIBRARY libpng.lib \ No newline at end of file diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/group/gstqtdemux.mmp --- a/gst_plugins_good/group/gstqtdemux.mmp Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -// Gstreamer.MMP -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser 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. -* -* Description: -* -*/ - - -#include - -TARGET libgstqtdemux.dll -TARGETTYPE DLL -UID 0x20004c49 0x0DE80E1F - -#ifdef EKA2 -LANG SC -CAPABILITY All -Tcb -VENDORID VID_DEFAULT -#endif - -#if !defined(__WINSCW__) && !defined(__WINS__) -EpocAllowDllData -#endif - -MACRO SYMBIAN -MACRO HAVE_CONFIG_H -MACRO __SYMBIAN32__ - -USERINCLUDE .. -USERINCLUDE ../gst/qtdemux -USERINCLUDE ../gst-libs -USERINCLUDE ../gst-libs/gst - - -MW_LAYER_SYSTEMINCLUDE -OS_LAYER_LIBC_SYSTEMINCLUDE -OS_LAYER_GLIB_SYSTEMINCLUDE -MW_LAYER_GSTREAMER_SYSTEMINCLUDE - -SOURCEPATH ../gst/qtdemux -SOURCE quicktime.c gstrtpxqtdepay.c qtdemux.c qtdemux_types.c qtdemux_dump.c - - -LIBRARY libc.lib -LIBRARY libglib.lib -LIBRARY libgobject.lib -LIBRARY libgstreamer.lib -LIBRARY libgstbase.lib -LIBRARY libgstcontroller.lib -LIBRARY libgstaudio.lib -LIBRARY libm.lib libgstrtp.lib libgsttag.lib - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/alpha/gstalpha.c --- a/gst_plugins_good/gst/alpha/gstalpha.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,930 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2007> Wim Taymans - * Copyright (C) <2007> Edward Hervey - * Copyright (C) <2007> Jan Schmidt - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include -#include -#include - -#include -#include -#include - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#define GST_TYPE_ALPHA \ - (gst_alpha_get_type()) -#define GST_ALPHA(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALPHA,GstAlpha)) -#define GST_ALPHA_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALPHA,GstAlphaClass)) -#define GST_IS_ALPHA(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALPHA)) -#define GST_IS_ALPHA_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALPHA)) - -typedef struct _GstAlpha GstAlpha; -typedef struct _GstAlphaClass GstAlphaClass; - -typedef enum -{ - ALPHA_METHOD_SET, - ALPHA_METHOD_GREEN, - ALPHA_METHOD_BLUE, - ALPHA_METHOD_CUSTOM, -} -GstAlphaMethod; - -GST_DEBUG_CATEGORY_STATIC (gst_alpha_debug); -#define GST_CAT_DEFAULT gst_alpha_debug - -struct _GstAlpha -{ - GstBaseTransform parent; - - /* caps */ - GstVideoFormat format; - gint width, height; - gboolean ayuv; - - gdouble alpha; - - guint target_r; - guint target_g; - guint target_b; - - GstAlphaMethod method; - - gfloat angle; - gfloat noise_level; - guint black_sensitivity; - guint white_sensitivity; - - gfloat y; /* chroma color */ - gint8 cb, cr; - gint8 kg; - gfloat accept_angle_cos; - gfloat accept_angle_sin; - guint8 accept_angle_tg; - guint8 accept_angle_ctg; - guint8 one_over_kc; - guint8 kfgy_scale; -}; - -struct _GstAlphaClass -{ - GstBaseTransformClass parent_class; -}; - -/* elementfactory information */ -static const GstElementDetails gst_alpha_details = -GST_ELEMENT_DETAILS ("Alpha filter", - "Filter/Effect/Video", - "Adds an alpha channel to video - uniform or via chroma-keying", - "Wim Taymans \n" - "Edward Hervey \n" - "Jan Schmidt "); - -/* Alpha signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -#define DEFAULT_METHOD ALPHA_METHOD_SET -#define DEFAULT_ALPHA 1.0 -#define DEFAULT_TARGET_R 0 -#define DEFAULT_TARGET_G 255 -#define DEFAULT_TARGET_B 0 -#define DEFAULT_ANGLE 20.0 -#define DEFAULT_NOISE_LEVEL 2.0 -#define DEFAULT_BLACK_SENSITIVITY 100 -#define DEFAULT_WHITE_SENSITIVITY 100 - -enum -{ - PROP_0, - PROP_METHOD, - PROP_ALPHA, - PROP_TARGET_R, - PROP_TARGET_G, - PROP_TARGET_B, - PROP_ANGLE, - PROP_NOISE_LEVEL, - PROP_BLACK_SENSITIVITY, - PROP_WHITE_SENSITIVITY, - PROP_LAST -}; - -static GstStaticPadTemplate gst_alpha_src_template = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV")) - ); - -static GstStaticPadTemplate gst_alpha_sink_template = - GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";" GST_VIDEO_CAPS_YUV ("I420") - ) - ); - -static gboolean gst_alpha_start (GstBaseTransform * trans); -static gboolean gst_alpha_get_unit_size (GstBaseTransform * btrans, - GstCaps * caps, guint * size); -static GstCaps *gst_alpha_transform_caps (GstBaseTransform * btrans, - GstPadDirection direction, GstCaps * caps); -static gboolean gst_alpha_set_caps (GstBaseTransform * btrans, - GstCaps * incaps, GstCaps * outcaps); -static GstFlowReturn gst_alpha_transform (GstBaseTransform * btrans, - GstBuffer * in, GstBuffer * out); - -static void gst_alpha_init_params (GstAlpha * alpha); - -static void gst_alpha_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_alpha_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -GST_BOILERPLATE (GstAlpha, gst_alpha, GstBaseTransform, - GST_TYPE_BASE_TRANSFORM); - -#define GST_TYPE_ALPHA_METHOD (gst_alpha_method_get_type()) -static GType -gst_alpha_method_get_type (void) -{ - static GType alpha_method_type = 0; - static const GEnumValue alpha_method[] = { - {ALPHA_METHOD_SET, "Set/adjust alpha channel", "set"}, - {ALPHA_METHOD_GREEN, "Chroma Key green", "green"}, - {ALPHA_METHOD_BLUE, "Chroma Key blue", "blue"}, - {ALPHA_METHOD_CUSTOM, "Chroma Key on target_r/g/b", "custom"}, - {0, NULL, NULL}, - }; - - if (!alpha_method_type) { - alpha_method_type = g_enum_register_static ("GstAlphaMethod", alpha_method); - } - return alpha_method_type; -} - -static void -gst_alpha_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &gst_alpha_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_alpha_sink_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_alpha_src_template)); - - GST_DEBUG_CATEGORY_INIT (gst_alpha_debug, "alpha", 0, - "alpha - Element for adding alpha channel to streams"); -} -static void -gst_alpha_class_init (GstAlphaClass * klass) -{ - GObjectClass *gobject_class; - GstBaseTransformClass *btrans_class; - - gobject_class = (GObjectClass *) klass; - btrans_class = (GstBaseTransformClass *) klass; - - gobject_class->set_property = gst_alpha_set_property; - gobject_class->get_property = gst_alpha_get_property; - - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_METHOD, - g_param_spec_enum ("method", "Method", - "How the alpha channels should be created", GST_TYPE_ALPHA_METHOD, - DEFAULT_METHOD, (GParamFlags) G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA, - g_param_spec_double ("alpha", "Alpha", "The value for the alpha channel", - 0.0, 1.0, DEFAULT_ALPHA, - (GParamFlags) G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_R, - g_param_spec_uint ("target_r", "Target Red", "The Red target", 0, 255, - DEFAULT_TARGET_R, - (GParamFlags) G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_G, - g_param_spec_uint ("target_g", "Target Green", "The Green target", 0, 255, - DEFAULT_TARGET_G, - (GParamFlags) G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_B, - g_param_spec_uint ("target_b", "Target Blue", "The Blue target", 0, 255, - DEFAULT_TARGET_B, - (GParamFlags) G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ANGLE, - g_param_spec_float ("angle", "Angle", "Size of the colorcube to change", - 0.0, 90.0, DEFAULT_ANGLE, - (GParamFlags) G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NOISE_LEVEL, - g_param_spec_float ("noise_level", "Noise Level", "Size of noise radius", - 0.0, 64.0, DEFAULT_NOISE_LEVEL, - (GParamFlags) G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), - PROP_BLACK_SENSITIVITY, g_param_spec_uint ("black-sensitivity", - "Black Sensitivity", "Sensitivity to dark colors", 0, 128, - DEFAULT_BLACK_SENSITIVITY, - (GParamFlags) G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), - PROP_WHITE_SENSITIVITY, g_param_spec_uint ("white-sensitivity", - "Sensitivity", "Sensitivity to bright colors", 0, 128, - DEFAULT_WHITE_SENSITIVITY, - (GParamFlags) G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - - - btrans_class->start = GST_DEBUG_FUNCPTR (gst_alpha_start); - btrans_class->transform = GST_DEBUG_FUNCPTR (gst_alpha_transform); - btrans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_alpha_get_unit_size); - btrans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_alpha_transform_caps); - btrans_class->set_caps = GST_DEBUG_FUNCPTR (gst_alpha_set_caps); -} - -static void -gst_alpha_init (GstAlpha * alpha, GstAlphaClass * klass) -{ - alpha->alpha = DEFAULT_ALPHA; - alpha->method = DEFAULT_METHOD; - alpha->target_r = DEFAULT_TARGET_R; - alpha->target_g = DEFAULT_TARGET_G; - alpha->target_b = DEFAULT_TARGET_B; - alpha->angle = DEFAULT_ANGLE; - alpha->noise_level = DEFAULT_NOISE_LEVEL; - alpha->black_sensitivity = DEFAULT_BLACK_SENSITIVITY; - alpha->white_sensitivity = DEFAULT_WHITE_SENSITIVITY; -} - -/* do we need this function? */ -static void -gst_alpha_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAlpha *alpha; - - g_return_if_fail (GST_IS_ALPHA (object)); - - alpha = GST_ALPHA (object); - - switch (prop_id) { - case PROP_METHOD: - alpha->method = g_value_get_enum (value); - switch (alpha->method) { - case ALPHA_METHOD_GREEN: - alpha->target_r = 0; - alpha->target_g = 255; - alpha->target_b = 0; - break; - case ALPHA_METHOD_BLUE: - alpha->target_r = 0; - alpha->target_g = 0; - alpha->target_b = 255; - break; - default: - break; - } - gst_alpha_init_params (alpha); - break; - case PROP_ALPHA: - alpha->alpha = g_value_get_double (value); - break; - case PROP_TARGET_R: - alpha->target_r = g_value_get_uint (value); - gst_alpha_init_params (alpha); - break; - case PROP_TARGET_G: - alpha->target_g = g_value_get_uint (value); - gst_alpha_init_params (alpha); - break; - case PROP_TARGET_B: - alpha->target_b = g_value_get_uint (value); - gst_alpha_init_params (alpha); - break; - case PROP_ANGLE: - alpha->angle = g_value_get_float (value); - gst_alpha_init_params (alpha); - break; - case PROP_NOISE_LEVEL: - alpha->noise_level = g_value_get_float (value); - gst_alpha_init_params (alpha); - break; - case PROP_BLACK_SENSITIVITY: - alpha->black_sensitivity = g_value_get_uint (value); - break; - case PROP_WHITE_SENSITIVITY: - alpha->white_sensitivity = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} -static void -gst_alpha_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstAlpha *alpha; - - g_return_if_fail (GST_IS_ALPHA (object)); - - alpha = GST_ALPHA (object); - - switch (prop_id) { - case PROP_METHOD: - g_value_set_enum (value, alpha->method); - break; - case PROP_ALPHA: - g_value_set_double (value, alpha->alpha); - break; - case PROP_TARGET_R: - g_value_set_uint (value, alpha->target_r); - break; - case PROP_TARGET_G: - g_value_set_uint (value, alpha->target_g); - break; - case PROP_TARGET_B: - g_value_set_uint (value, alpha->target_b); - break; - case PROP_ANGLE: - g_value_set_float (value, alpha->angle); - break; - case PROP_NOISE_LEVEL: - g_value_set_float (value, alpha->noise_level); - break; - case PROP_BLACK_SENSITIVITY: - g_value_set_uint (value, alpha->black_sensitivity); - break; - case PROP_WHITE_SENSITIVITY: - g_value_set_uint (value, alpha->white_sensitivity); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gboolean -gst_alpha_get_unit_size (GstBaseTransform * btrans, - GstCaps * caps, guint * size) -{ - GstVideoFormat format; - gint width, height; - - if (!gst_video_format_parse_caps (caps, &format, &width, &height)) - return FALSE; - - *size = gst_video_format_get_size (format, width, height); - - GST_DEBUG_OBJECT (btrans, "unit size = %d for format %d w %d height %d", - *size, format, width, height); - - return TRUE; -} - -static GstCaps * -gst_alpha_transform_caps (GstBaseTransform * btrans, - GstPadDirection direction, GstCaps * caps) -{ - GstCaps *ret; - GstStructure *structure; - gint i; - - ret = gst_caps_copy (caps); - - /* When going from the SINK pad to the src, we just need to make sure the - * format is AYUV */ - if (direction == GST_PAD_SINK) { - for (i = 0; i < gst_caps_get_size (ret); i++) { - structure = gst_caps_get_structure (ret, i); - gst_structure_set (structure, "format", - GST_TYPE_FOURCC, GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'), NULL); - } - } else { - GstCaps *ayuv_caps; - - /* In the other direction, prepend a copy of the caps with format AYUV, - * and set the first to I420 */ - ayuv_caps = gst_caps_copy (ret); - - for (i = 0; i < gst_caps_get_size (ret); i++) { - structure = gst_caps_get_structure (ret, i); - gst_structure_set (structure, "format", - GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'), NULL); - } - - gst_caps_append (ret, ayuv_caps); - } - - gst_caps_do_simplify (ret); - - return ret; -} - -static gboolean -gst_alpha_set_caps (GstBaseTransform * btrans, - GstCaps * incaps, GstCaps * outcaps) -{ - GstAlpha *alpha = GST_ALPHA (btrans); - - if (!gst_video_format_parse_caps (incaps, &alpha->format, - &alpha->width, &alpha->height)) - return FALSE; - - if (alpha->format == GST_VIDEO_FORMAT_AYUV) - alpha->ayuv = TRUE; - else - alpha->ayuv = FALSE; - - return TRUE; -} - -static void -gst_alpha_set_ayuv (guint8 * src, guint8 * dest, gint width, gint height, - gdouble alpha) -{ - gint b_alpha = (gint) (alpha * 255); - gint y, x; - - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - *dest++ = (*src++ * b_alpha) >> 8; - *dest++ = *src++; - *dest++ = *src++; - *dest++ = *src++; - } - } -} - -static void -gst_alpha_set_i420 (guint8 * src, guint8 * dest, gint width, gint height, - gdouble alpha) -{ - gint b_alpha = (gint) (alpha * 255); - guint8 *srcY; - guint8 *srcU; - guint8 *srcV; - gint i, j; - gint src_wrap, src_uv_wrap; - gint y_stride, uv_stride; - gboolean odd_width; - - y_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, width); - uv_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, width); - - src_wrap = y_stride - width; - src_uv_wrap = uv_stride - (width / 2); - - srcY = src; - srcU = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, - 1, width, height); - srcV = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, - 2, width, height); - - odd_width = (width % 2 != 0); - - for (i = 0; i < height; i++) { - for (j = 0; j < width / 2; j++) { - *dest++ = b_alpha; - *dest++ = *srcY++; - *dest++ = *srcU; - *dest++ = *srcV; - *dest++ = b_alpha; - *dest++ = *srcY++; - *dest++ = *srcU++; - *dest++ = *srcV++; - } - /* Might have one odd column left to do */ - if (odd_width) { - *dest++ = b_alpha; - *dest++ = *srcY++; - *dest++ = *srcU; - *dest++ = *srcV; - } - if (i % 2 == 0) { - srcU -= width / 2; - srcV -= width / 2; - } else { - srcU += src_uv_wrap; - srcV += src_uv_wrap; - } - srcY += src_wrap; - } -} - -static void -gst_alpha_chroma_key_ayuv (guint8 * src, guint8 * dest, gint width, gint height, - GstAlpha * alpha) -{ - gint b_alpha; - guint8 *src1; - guint8 *dest1; - gint i, j; - gint x, z, u, v, y, a; - gint tmp, tmp1; - gint x1, y1; - gint smin, smax; - - smin = 128 - alpha->black_sensitivity; - smax = 128 + alpha->white_sensitivity; - - src1 = src; - dest1 = dest; - - for (i = 0; i < height; i++) { - for (j = 0; j < width; j++) { - a = *src1++ * (alpha->alpha); - y = *src1++; - u = *src1++ - 128; - v = *src1++ - 128; - - if (y < smin || y > smax) { - /* too dark or too bright, keep alpha */ - b_alpha = a; - } else { - /* Convert foreground to XZ coords where X direction is defined by - the key color */ - tmp = ((short) u * alpha->cb + (short) v * alpha->cr) >> 7; - x = CLAMP (tmp, -128, 127); - tmp = ((short) v * alpha->cb - (short) u * alpha->cr) >> 7; - z = CLAMP (tmp, -128, 127); - - /* WARNING: accept angle should never be set greater than "somewhat less - than 90 degrees" to avoid dealing with negative/infinite tg. In reality, - 80 degrees should be enough if foreground is reasonable. If this seems - to be a problem, go to alternative ways of checking point position - (scalar product or line equations). This angle should not be too small - either to avoid infinite ctg (used to suppress foreground without use of - division) */ - - tmp = ((short) (x) * alpha->accept_angle_tg) >> 4; - tmp = MIN (tmp, 127); - - if (abs (z) > tmp) { - /* keep foreground Kfg = 0 */ - b_alpha = a; - } else { - /* Compute Kfg (implicitly) and Kbg, suppress foreground in XZ coord - according to Kfg */ - tmp = ((short) (z) * alpha->accept_angle_ctg) >> 4; - tmp = CLAMP (tmp, -128, 127); - x1 = abs (tmp); - y1 = z; - - tmp1 = x - x1; - tmp1 = MAX (tmp1, 0); - b_alpha = (((unsigned char) (tmp1) * - (unsigned short) (alpha->one_over_kc)) / 2); - b_alpha = 255 - CLAMP (b_alpha, 0, 255); - b_alpha = (a * b_alpha) >> 8; - - tmp = ((unsigned short) (tmp1) * alpha->kfgy_scale) >> 4; - tmp1 = MIN (tmp, 255); - - tmp = y - tmp1; - y = MAX (tmp, 0); - - /* Convert suppressed foreground back to CbCr */ - tmp = ((char) (x1) * (short) (alpha->cb) - - (char) (y1) * (short) (alpha->cr)) >> 7; - u = CLAMP (tmp, -128, 127); - - tmp = ((char) (x1) * (short) (alpha->cr) + - (char) (y1) * (short) (alpha->cb)) >> 7; - v = CLAMP (tmp, -128, 127); - - /* Deal with noise. For now, a circle around the key color with - radius of noise_level treated as exact key color. Introduces - sharp transitions. - */ - tmp = z * (short) (z) + (x - alpha->kg) * (short) (x - alpha->kg); - tmp = MIN (tmp, 0xffff); - - if (tmp < alpha->noise_level * alpha->noise_level) { - b_alpha = 0; - } - } - } - - u += 128; - v += 128; - - *dest1++ = b_alpha; - *dest1++ = y; - *dest1++ = u; - *dest1++ = v; - } - } -} - -static void -gst_alpha_chromakey_row_i420 (GstAlpha * alpha, guint8 * dest1, guint8 * dest2, - guint8 * srcY1, guint8 * srcY2, guint8 * srcU, guint8 * srcV, gint width) -{ - gint xpos; - gint b_alpha; - gint x, z, u, v, y11, y12, y21, y22, a; - gint tmp, tmp1; - gint x1, y1; - gint smin, smax; - - a = 255 * alpha->alpha; - smin = 128 - alpha->black_sensitivity; - smax = 128 + alpha->white_sensitivity; - - for (xpos = 0; xpos < width / 2; xpos++) { - y11 = *srcY1++; - y12 = *srcY1++; - y21 = *srcY2++; - y22 = *srcY2++; - u = *srcU++ - 128; - v = *srcV++ - 128; - - if (y11 < smin || y11 > smax || - y12 < smin || y12 > smax || - y21 < smin || y21 > smax || y22 < smin || y22 > smax) { - /* too dark or too bright, make opaque */ - b_alpha = 255; - } else { - /* Convert foreground to XZ coords where X direction is defined by - the key color */ - tmp = ((short) u * alpha->cb + (short) v * alpha->cr) >> 7; - x = CLAMP (tmp, -128, 127); - tmp = ((short) v * alpha->cb - (short) u * alpha->cr) >> 7; - z = CLAMP (tmp, -128, 127); - - /* WARNING: accept angle should never be set greater than "somewhat less - than 90 degrees" to avoid dealing with negative/infinite tg. In reality, - 80 degrees should be enough if foreground is reasonable. If this seems - to be a problem, go to alternative ways of checking point position - (scalar product or line equations). This angle should not be too small - either to avoid infinite ctg (used to suppress foreground without use of - division) */ - - tmp = ((short) (x) * alpha->accept_angle_tg) >> 4; - tmp = MIN (tmp, 127); - - if (abs (z) > tmp) { - /* keep foreground Kfg = 0 */ - b_alpha = 255; - } else { - /* Compute Kfg (implicitly) and Kbg, suppress foreground in XZ coord - according to Kfg */ - tmp = ((short) (z) * alpha->accept_angle_ctg) >> 4; - tmp = CLAMP (tmp, -128, 127); - x1 = abs (tmp); - y1 = z; - - tmp1 = x - x1; - tmp1 = MAX (tmp1, 0); - b_alpha = (((unsigned char) (tmp1) * - (unsigned short) (alpha->one_over_kc)) / 2); - b_alpha = 255 - CLAMP (b_alpha, 0, 255); - b_alpha = (a * b_alpha) >> 8; - - tmp = ((unsigned short) (tmp1) * alpha->kfgy_scale) >> 4; - tmp1 = MIN (tmp, 255); - - tmp = y11 - tmp1; - y11 = MAX (tmp, 0); - tmp = y12 - tmp1; - y12 = MAX (tmp, 0); - tmp = y21 - tmp1; - y21 = MAX (tmp, 0); - tmp = y22 - tmp1; - y22 = MAX (tmp, 0); - - /* Convert suppressed foreground back to CbCr */ - tmp = ((char) (x1) * (short) (alpha->cb) - - (char) (y1) * (short) (alpha->cr)) >> 7; - u = CLAMP (tmp, -128, 127); - - tmp = ((char) (x1) * (short) (alpha->cr) + - (char) (y1) * (short) (alpha->cb)) >> 7; - v = CLAMP (tmp, -128, 127); - - /* Deal with noise. For now, a circle around the key color with - radius of noise_level treated as exact key color. Introduces - sharp transitions. - */ - tmp = z * (short) (z) + (x - alpha->kg) * (short) (x - alpha->kg); - tmp = MIN (tmp, 0xffff); - - if (tmp < alpha->noise_level * alpha->noise_level) { - /* Uncomment this if you want total suppression within the noise circle */ - b_alpha = 0; - } - } - } - - u += 128; - v += 128; - - *dest1++ = b_alpha; - *dest1++ = y11; - *dest1++ = u; - *dest1++ = v; - *dest1++ = b_alpha; - *dest1++ = y12; - *dest1++ = u; - *dest1++ = v; - - *dest2++ = b_alpha; - *dest2++ = y21; - *dest2++ = u; - *dest2++ = v; - *dest2++ = b_alpha; - *dest2++ = y22; - *dest2++ = u; - *dest2++ = v; - } -} - -/* based on http://www.cs.utah.edu/~michael/chroma/ - */ -static void -gst_alpha_chroma_key_i420 (guint8 * src, guint8 * dest, gint width, gint height, - GstAlpha * alpha) -{ - guint8 *srcY1, *srcY2, *srcU, *srcV; - guint8 *dest1, *dest2; - gint ypos; - gint dest_stride, src_y_stride, src_uv_stride; - - dest_stride = - gst_video_format_get_row_stride (GST_VIDEO_FORMAT_AYUV, 0, width); - src_y_stride = - gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, width); - src_uv_stride = - gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, width); - - srcY1 = src; - srcY2 = src + src_y_stride; - - srcU = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, - 1, width, height); - srcV = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, - 2, width, height); - - dest1 = dest; - dest2 = dest + dest_stride; - - /* Redefine Y strides to skip 2 lines at a time ... */ - dest_stride *= 2; - src_y_stride *= 2; - - for (ypos = 0; ypos < height / 2; ypos++) { - - gst_alpha_chromakey_row_i420 (alpha, dest1, dest2, - srcY1, srcY2, srcU, srcV, width); - - dest1 += dest_stride; - dest2 += dest_stride; - srcY1 += src_y_stride; - srcY2 += src_y_stride; - srcU += src_uv_stride; - srcV += src_uv_stride; - } -} - -static void -gst_alpha_init_params (GstAlpha * alpha) -{ - float kgl; - float tmp; - float tmp1, tmp2; - - alpha->y = - 0.257 * alpha->target_r + 0.504 * alpha->target_g + - 0.098 * alpha->target_b; - tmp1 = - -0.148 * alpha->target_r - 0.291 * alpha->target_g + - 0.439 * alpha->target_b; - tmp2 = - 0.439 * alpha->target_r - 0.368 * alpha->target_g - - 0.071 * alpha->target_b; - kgl = sqrt (tmp1 * tmp1 + tmp2 * tmp2); - alpha->cb = 127 * (tmp1 / kgl); - alpha->cr = 127 * (tmp2 / kgl); - - alpha->accept_angle_cos = cos (M_PI * alpha->angle / 180); - alpha->accept_angle_sin = sin (M_PI * alpha->angle / 180); - tmp = 15 * tan (M_PI * alpha->angle / 180); - tmp = MIN (tmp, 255); - alpha->accept_angle_tg = tmp; - tmp = 15 / tan (M_PI * alpha->angle / 180); - tmp = MIN (tmp, 255); - alpha->accept_angle_ctg = tmp; - tmp = 1 / (kgl); - alpha->one_over_kc = 255 * 2 * tmp - 255; - tmp = 15 * (float) (alpha->y) / kgl; - tmp = MIN (tmp, 255); - alpha->kfgy_scale = tmp; - alpha->kg = MIN (kgl, 127); -} - -static gboolean -gst_alpha_start (GstBaseTransform * btrans) -{ - GstAlpha *alpha = GST_ALPHA (btrans); - - gst_alpha_init_params (alpha); - - return TRUE; -} - -static GstFlowReturn -gst_alpha_transform (GstBaseTransform * btrans, GstBuffer * in, GstBuffer * out) -{ - GstAlpha *alpha = GST_ALPHA (btrans); - gint width, height; - GstClockTime timestamp; - - width = alpha->width; - height = alpha->height; - - GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_TIMESTAMP (in); - GST_BUFFER_DURATION (out) = GST_BUFFER_DURATION (in); - timestamp = gst_segment_to_stream_time (&btrans->segment, GST_FORMAT_TIME, - GST_BUFFER_TIMESTAMP (in)); - GST_LOG ("Got stream time of %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); - if (GST_CLOCK_TIME_IS_VALID (timestamp)) - gst_object_sync_values (G_OBJECT (alpha), timestamp); - - switch (alpha->method) { - case ALPHA_METHOD_SET: - if (alpha->ayuv) { - gst_alpha_set_ayuv (GST_BUFFER_DATA (in), - GST_BUFFER_DATA (out), width, height, alpha->alpha); - } else { - gst_alpha_set_i420 (GST_BUFFER_DATA (in), - GST_BUFFER_DATA (out), width, height, alpha->alpha); - } - break; - case ALPHA_METHOD_GREEN: - case ALPHA_METHOD_BLUE: - case ALPHA_METHOD_CUSTOM: - if (alpha->ayuv) { - gst_alpha_chroma_key_ayuv (GST_BUFFER_DATA (in), - GST_BUFFER_DATA (out), width, height, alpha); - } else { - gst_alpha_chroma_key_i420 (GST_BUFFER_DATA (in), - GST_BUFFER_DATA (out), width, height, alpha); - } - break; - default: - break; - } - - return GST_FLOW_OK; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - gst_controller_init (NULL, NULL); - - return gst_element_register (plugin, "alpha", GST_RANK_NONE, GST_TYPE_ALPHA); -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "alpha", - "adds an alpha channel to video - constant or via chroma-keying", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) - - -#ifdef __SYMBIAN32__ -EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC() -{ - return &gst_plugin_desc; -} - -#endif diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/alpha/gstalphacolor.c --- a/gst_plugins_good/gst/alpha/gstalphacolor.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,279 +0,0 @@ -/* GStreamer - * 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. - */ - -/** - * SECTION:element-alphacolor - * - * The alphacolor element does memory-efficient (in-place) colourspace - * conversion from RGBA to AYUV, preserving the alpha channel. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstalphacolor.h" - -#include -#include - -#include - -GST_DEBUG_CATEGORY_STATIC (alpha_color_debug); -#define GST_CAT_DEFAULT alpha_color_debug - -/* elementfactory information */ -static const GstElementDetails gst_alpha_color_details = -GST_ELEMENT_DETAILS ("Alpha color filter", - "Filter/Effect/Video", - "RGBA to AYUV colorspace conversion preserving the alpha channel", - "Wim Taymans "); - -static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA) - ); - -static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV")) - ); - -GST_BOILERPLATE (GstAlphaColor, gst_alpha_color, GstBaseTransform, - GST_TYPE_BASE_TRANSFORM); - -static GstCaps *gst_alpha_color_transform_caps (GstBaseTransform * btrans, - GstPadDirection direction, GstCaps * caps); -static gboolean gst_alpha_color_set_caps (GstBaseTransform * btrans, - GstCaps * incaps, GstCaps * outcaps); -static GstFlowReturn gst_alpha_color_transform_ip (GstBaseTransform * btrans, - GstBuffer * inbuf); - -static void -gst_alpha_color_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details (element_class, &gst_alpha_color_details); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_template)); -} - -static void -gst_alpha_color_class_init (GstAlphaColorClass * klass) -{ - GstBaseTransformClass *gstbasetransform_class; - - gstbasetransform_class = (GstBaseTransformClass *) klass; - - gstbasetransform_class->transform_caps = - GST_DEBUG_FUNCPTR (gst_alpha_color_transform_caps); - gstbasetransform_class->set_caps = - GST_DEBUG_FUNCPTR (gst_alpha_color_set_caps); - gstbasetransform_class->transform_ip = - GST_DEBUG_FUNCPTR (gst_alpha_color_transform_ip); - - GST_DEBUG_CATEGORY_INIT (alpha_color_debug, "alphacolor", 0, - "RGB->YUV colorspace conversion preserving the alpha channels"); -} - -static void -gst_alpha_color_init (GstAlphaColor * alpha, GstAlphaColorClass * g_class) -{ - GstBaseTransform *btrans = NULL; - - btrans = GST_BASE_TRANSFORM (alpha); - - btrans->always_in_place = TRUE; -} - -static GstCaps * -gst_alpha_color_transform_caps (GstBaseTransform * btrans, - GstPadDirection direction, GstCaps * caps) -{ - const GstCaps *tmpl_caps = NULL; - GstCaps *result = NULL, *local_caps = NULL; - guint i; - - local_caps = gst_caps_copy (caps); - - for (i = 0; i < gst_caps_get_size (local_caps); i++) { - GstStructure *structure = gst_caps_get_structure (local_caps, i); - - /* Throw away the structure name and set it to transformed format */ - if (direction == GST_PAD_SINK) { - gst_structure_set_name (structure, "video/x-raw-yuv"); - } else if (direction == GST_PAD_SRC) { - gst_structure_set_name (structure, "video/x-raw-rgb"); - } - /* Remove any specific parameter from the structure */ - gst_structure_remove_field (structure, "format"); - gst_structure_remove_field (structure, "endianness"); - gst_structure_remove_field (structure, "depth"); - gst_structure_remove_field (structure, "bpp"); - gst_structure_remove_field (structure, "red_mask"); - gst_structure_remove_field (structure, "green_mask"); - gst_structure_remove_field (structure, "blue_mask"); - gst_structure_remove_field (structure, "alpha_mask"); - } - - /* Get the appropriate template */ - if (direction == GST_PAD_SINK) { - tmpl_caps = gst_static_pad_template_get_caps (&src_template); - } else if (direction == GST_PAD_SRC) { - tmpl_caps = gst_static_pad_template_get_caps (&sink_template); - } - - /* Intersect with our template caps */ - result = gst_caps_intersect (local_caps, tmpl_caps); - - gst_caps_unref (local_caps); - gst_caps_do_simplify (result); - - GST_LOG ("transformed %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT, caps, result); - - return result; -} - -static gboolean -gst_alpha_color_set_caps (GstBaseTransform * btrans, GstCaps * incaps, - GstCaps * outcaps) -{ - GstAlphaColor *alpha; - GstStructure *structure; - gboolean ret; - const GValue *fps; - gint red_mask, alpha_mask; - gint w, h, depth, bpp; - - alpha = GST_ALPHA_COLOR (btrans); - structure = gst_caps_get_structure (incaps, 0); - - ret = gst_structure_get_int (structure, "width", &w); - ret &= gst_structure_get_int (structure, "height", &h); - fps = gst_structure_get_value (structure, "framerate"); - ret &= (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps)); - ret &= gst_structure_get_int (structure, "red_mask", &red_mask); - - /* make sure these are really full RGBA caps */ - ret &= gst_structure_get_int (structure, "alpha_mask", &alpha_mask); - ret &= gst_structure_get_int (structure, "depth", &depth); - ret &= gst_structure_get_int (structure, "bpp", &bpp); - - if (!ret || alpha_mask == 0 || red_mask == 0 || depth != 32 || bpp != 32) { - GST_DEBUG_OBJECT (alpha, "incomplete or non-RGBA input caps!"); - return FALSE; - } - - alpha->in_width = w; - alpha->in_height = h; - alpha->in_rgba = TRUE; -#if (G_BYTE_ORDER == G_BIG_ENDIAN) - if (red_mask != 0x000000ff) -#else - if (red_mask != 0xff000000) -#endif - alpha->in_rgba = FALSE; - - return TRUE; -} - -static void -transform_rgb (guint8 * data, gint size) -{ - guint8 y, u, v; - - while (size > 0) { - y = data[0] * 0.299 + data[1] * 0.587 + data[2] * 0.114 + 0; - u = data[0] * -0.169 + data[1] * -0.332 + data[2] * 0.500 + 128; - v = data[0] * 0.500 + data[1] * -0.419 + data[2] * -0.0813 + 128; - - data[0] = data[3]; - data[1] = y; - data[2] = u; - data[3] = v; - - data += 4; - size -= 4; - } -} - -static void -transform_bgr (guint8 * data, gint size) -{ - guint8 y, u, v; - - while (size > 0) { - y = data[2] * 0.299 + data[1] * 0.587 + data[0] * 0.114 + 0; - u = data[2] * -0.169 + data[1] * -0.332 + data[0] * 0.500 + 128; - v = data[2] * 0.500 + data[1] * -0.419 + data[0] * -0.0813 + 128; - - data[0] = data[3]; - data[1] = y; - data[2] = u; - data[3] = v; - - data += 4; - size -= 4; - } -} - -static GstFlowReturn -gst_alpha_color_transform_ip (GstBaseTransform * btrans, GstBuffer * inbuf) -{ - GstFlowReturn ret = GST_FLOW_OK; - GstAlphaColor *alpha; - - alpha = GST_ALPHA_COLOR (btrans); - - /* Transform in place */ - if (alpha->in_rgba) - transform_rgb (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf)); - else - transform_bgr (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf)); - - return ret; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - return gst_element_register (plugin, "alphacolor", GST_RANK_NONE, - GST_TYPE_ALPHA_COLOR); -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "alphacolor", - "RGBA to AYUV colorspace conversion preserving the alpha channel", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) - - -#ifdef __SYMBIAN32__ -EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC() -{ - return &gst_plugin_desc; -} - -#endif diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/alpha/gstalphacolor.h --- a/gst_plugins_good/gst/alpha/gstalphacolor.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* GStreamer alphacolor element - * Copyright (C) 2005 Wim Taymans - * - * 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. - */ - -#ifndef _GST_ALPHA_COLOR_H_ -#define _GST_ALPHA_COLOR_H_ - -#include - -#define GST_TYPE_ALPHA_COLOR \ - (gst_alpha_color_get_type()) -#define GST_ALPHA_COLOR(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALPHA_COLOR,GstAlphaColor)) -#define GST_ALPHA_COLOR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALPHA_COLOR,GstAlphaColorClass)) -#define GST_IS_ALPHA_COLOR(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALPHA_COLOR)) -#define GST_IS_ALPHA_COLOR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALPHA_COLOR)) - -typedef struct _GstAlphaColor GstAlphaColor; -typedef struct _GstAlphaColorClass GstAlphaColorClass; - -struct _GstAlphaColor -{ - GstBaseTransform element; - - /*< private >*/ - /* caps */ - gint in_width, in_height; - gboolean in_rgba; - gint out_width, out_height; -}; - -struct _GstAlphaColorClass -{ - GstBaseTransformClass parent_class; -}; - -GType gst_alpha_color_get_type (void); - -#endif /* _GST_ALPHA_COLOR_H_ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audioamplify.c --- a/gst_plugins_good/gst/audiofx/audioamplify.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,495 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2007 Sebastian Dröge - * Copyright (C) 2006 Stefan Kost - * - * 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. - */ - -/** - * SECTION:element-audioamplify - * - * Amplifies an audio stream by a given factor and allows the selection of different clipping modes. - * The difference between the clipping modes is best evaluated by testing. - * Example launch line - * - * |[ - * gst-launch audiotestsrc wave=saw ! audioamplify amplification=1.5 ! alsasink - * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audioamplify amplification=1.5 method=wrap-negative ! alsasink - * gst-launch audiotestsrc wave=saw ! audioconvert ! audioamplify amplification=1.5 method=wrap-positive ! audioconvert ! alsasink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "audioamplify.h" - -#define GST_CAT_DEFAULT gst_audio_amplify_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -static const GstElementDetails element_details = -GST_ELEMENT_DETAILS ("Audio amplifier", - "Filter/Effect/Audio", - "Amplifies an audio stream by a given factor", - "Sebastian Dröge "); - -/* Filter signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - PROP_0, - PROP_AMPLIFICATION, - PROP_CLIPPING_METHOD -}; - -enum -{ - METHOD_CLIP = 0, - METHOD_WRAP_NEGATIVE, - METHOD_WRAP_POSITIVE, - METHOD_NOCLIP, - NUM_METHODS -}; - -#define GST_TYPE_AUDIO_AMPLIFY_CLIPPING_METHOD (gst_audio_amplify_clipping_method_get_type ()) -static GType -gst_audio_amplify_clipping_method_get_type (void) -{ - static GType gtype = 0; - - if (gtype == 0) { - static const GEnumValue values[] = { - {METHOD_CLIP, "Normal clipping (default)", "clip"}, - {METHOD_WRAP_NEGATIVE, - "Push overdriven values back from the opposite side", - "wrap-negative"}, - {METHOD_WRAP_POSITIVE, "Push overdriven values back from the same side", - "wrap-positive"}, - {METHOD_NOCLIP, "No clipping", "none"}, - {0, NULL, NULL} - }; - - /* FIXME 0.11: rename to GstAudioAmplifyClippingMethod */ - gtype = g_enum_register_static ("GstAudioPanoramaClippingMethod", values); - } - return gtype; -} - -#define ALLOWED_CAPS \ - "audio/x-raw-int," \ - " depth=(int)8," \ - " width=(int)8," \ - " endianness=(int)BYTE_ORDER," \ - " signed=(bool)TRUE," \ - " rate=(int)[1,MAX]," \ - " channels=(int)[1,MAX]; " \ - "audio/x-raw-int," \ - " depth=(int)16," \ - " width=(int)16," \ - " endianness=(int)BYTE_ORDER," \ - " signed=(bool)TRUE," \ - " rate=(int)[1,MAX]," \ - " channels=(int)[1,MAX]; " \ - "audio/x-raw-int," \ - " depth=(int)32," \ - " width=(int)32," \ - " endianness=(int)BYTE_ORDER," \ - " signed=(bool)TRUE," \ - " rate=(int)[1,MAX]," \ - " channels=(int)[1,MAX]; " \ - "audio/x-raw-float," \ - " width=(int){32,64}," \ - " endianness=(int)BYTE_ORDER," \ - " rate=(int)[1,MAX]," \ - " channels=(int)[1,MAX]" - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_audio_amplify_debug, "audioamplify", 0, "audioamplify element"); - -GST_BOILERPLATE_FULL (GstAudioAmplify, gst_audio_amplify, GstAudioFilter, - GST_TYPE_AUDIO_FILTER, DEBUG_INIT); - -static gboolean gst_audio_amplify_set_process_function (GstAudioAmplify * - filter, gint clipping, gint format, gint width); -static void gst_audio_amplify_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_audio_amplify_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static gboolean gst_audio_amplify_setup (GstAudioFilter * filter, - GstRingBufferSpec * format); -static GstFlowReturn gst_audio_amplify_transform_ip (GstBaseTransform * base, - GstBuffer * buf); - -#define MIN_gint8 G_MININT8 -#define MAX_gint8 G_MAXINT8 -#define MIN_gint16 G_MININT16 -#define MAX_gint16 G_MAXINT16 -#define MIN_gint32 G_MININT32 -#define MAX_gint32 G_MAXINT32 - -#define MAKE_INT_FUNCS(type,largetype) \ -static void \ -gst_audio_amplify_transform_##type##_clip (GstAudioAmplify * filter, \ - void * data, guint num_samples) \ -{ \ - type *d = data; \ - \ - while (num_samples--) { \ - largetype val = *d * filter->amplification; \ - *d++ = CLAMP (val, MIN_##type, MAX_##type); \ - } \ -} \ -static void \ -gst_audio_amplify_transform_##type##_wrap_negative (GstAudioAmplify * filter, \ - void * data, guint num_samples) \ -{ \ - type *d = data; \ - \ - while (num_samples--) { \ - largetype val = *d * filter->amplification; \ - if (val > MAX_##type) \ - val = MIN_##type + (val - MIN_##type) % ((largetype) MAX_##type + 1 - \ - MIN_##type); \ - else if (val < MIN_##type) \ - val = MAX_##type - (MAX_##type - val) % ((largetype) MAX_##type + 1 - \ - MIN_##type); \ - *d++ = val; \ - } \ -} \ -static void \ -gst_audio_amplify_transform_##type##_wrap_positive (GstAudioAmplify * filter, \ - void * data, guint num_samples) \ -{ \ - type *d = data; \ - \ - while (num_samples--) { \ - largetype val = *d * filter->amplification; \ - do { \ - if (val > MAX_##type) \ - val = MAX_##type - (val - MAX_##type); \ - else if (val < MIN_##type) \ - val = MIN_##type + (MIN_##type - val); \ - else \ - break; \ - } while (1); \ - *d++ = val; \ - } \ -} \ -static void \ -gst_audio_amplify_transform_##type##_noclip (GstAudioAmplify * filter, \ - void * data, guint num_samples) \ -{ \ - type *d = data; \ - \ - while (num_samples--) \ - *d++ *= filter->amplification; \ -} - -#define MAKE_FLOAT_FUNCS(type) \ -static void \ -gst_audio_amplify_transform_##type##_clip (GstAudioAmplify * filter, \ - void * data, guint num_samples) \ -{ \ - type *d = data; \ - \ - while (num_samples--) { \ - type val = *d* filter->amplification; \ - *d++ = CLAMP (val, -1.0, +1.0); \ - } \ -} \ -static void \ -gst_audio_amplify_transform_##type##_wrap_negative (GstAudioAmplify * \ - filter, void * data, guint num_samples) \ -{ \ - type *d = data; \ - \ - while (num_samples--) { \ - type val = *d * filter->amplification; \ - do { \ - if (val > 1.0) \ - val = -1.0 + (val - 1.0); \ - else if (val < -1.0) \ - val = 1.0 - (1.0 - val); \ - else \ - break; \ - } while (1); \ - *d++ = val; \ - } \ -} \ -static void \ -gst_audio_amplify_transform_##type##_wrap_positive (GstAudioAmplify * filter, \ - void * data, guint num_samples) \ -{ \ - type *d = data; \ - \ - while (num_samples--) { \ - type val = *d* filter->amplification; \ - do { \ - if (val > 1.0) \ - val = 1.0 - (val - 1.0); \ - else if (val < -1.0) \ - val = -1.0 + (-1.0 - val); \ - else \ - break; \ - } while (1); \ - *d++ = val; \ - } \ -} \ -static void \ -gst_audio_amplify_transform_##type##_noclip (GstAudioAmplify * filter, \ - void * data, guint num_samples) \ -{ \ - type *d = data; \ - \ - while (num_samples--) \ - *d++ *= filter->amplification; \ -} - -/* *INDENT-OFF* */ -MAKE_INT_FUNCS (gint8,gint) -MAKE_INT_FUNCS (gint16,gint) -MAKE_INT_FUNCS (gint32,gint64) -MAKE_FLOAT_FUNCS (gfloat) -MAKE_FLOAT_FUNCS (gdouble) -/* *INDENT-ON* */ - -/* GObject vmethod implementations */ - -static void -gst_audio_amplify_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstCaps *caps; - - gst_element_class_set_details (element_class, &element_details); - - caps = gst_caps_from_string (ALLOWED_CAPS); - gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass), - caps); - gst_caps_unref (caps); -} - -static void -gst_audio_amplify_class_init (GstAudioAmplifyClass * klass) -{ - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - gobject_class->set_property = gst_audio_amplify_set_property; - gobject_class->get_property = gst_audio_amplify_get_property; - - g_object_class_install_property (gobject_class, PROP_AMPLIFICATION, - g_param_spec_float ("amplification", "Amplification", - "Factor of amplification", 0.0, G_MAXFLOAT, - 1.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - - /** - * GstAudioAmplify:clipping-method - * - * Clipping method: clip mode set values higher than the maximum to the - * maximum. The wrap-negative mode pushes those values back from the - * opposite side, wrap-positive pushes them back from the same side. - * - **/ - g_object_class_install_property (gobject_class, PROP_CLIPPING_METHOD, - g_param_spec_enum ("clipping-method", "Clipping method", - "Selects how to handle values higher than the maximum", - GST_TYPE_AUDIO_AMPLIFY_CLIPPING_METHOD, METHOD_CLIP, - G_PARAM_READWRITE)); - - GST_AUDIO_FILTER_CLASS (klass)->setup = - GST_DEBUG_FUNCPTR (gst_audio_amplify_setup); - GST_BASE_TRANSFORM_CLASS (klass)->transform_ip = - GST_DEBUG_FUNCPTR (gst_audio_amplify_transform_ip); -} - -static void -gst_audio_amplify_init (GstAudioAmplify * filter, GstAudioAmplifyClass * klass) -{ - filter->amplification = 1.0; - gst_audio_amplify_set_process_function (filter, METHOD_CLIP, - GST_BUFTYPE_LINEAR, 16); - gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE); - gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE); -} - -static GstAudioAmplifyProcessFunc -gst_audio_amplify_process_function (gint clipping, gint format, gint width) -{ - static const struct process - { - gint format; - gint width; - gint clipping; - GstAudioAmplifyProcessFunc func; - } process[] = { - { - GST_BUFTYPE_FLOAT, 32, METHOD_CLIP, - gst_audio_amplify_transform_gfloat_clip}, { - GST_BUFTYPE_FLOAT, 32, METHOD_WRAP_NEGATIVE, - gst_audio_amplify_transform_gfloat_wrap_negative}, { - GST_BUFTYPE_FLOAT, 32, METHOD_WRAP_POSITIVE, - gst_audio_amplify_transform_gfloat_wrap_positive}, { - GST_BUFTYPE_FLOAT, 32, METHOD_NOCLIP, - gst_audio_amplify_transform_gfloat_noclip}, { - GST_BUFTYPE_FLOAT, 64, METHOD_CLIP, - gst_audio_amplify_transform_gdouble_clip}, { - GST_BUFTYPE_FLOAT, 64, METHOD_WRAP_NEGATIVE, - gst_audio_amplify_transform_gdouble_wrap_negative}, { - GST_BUFTYPE_FLOAT, 64, METHOD_WRAP_POSITIVE, - gst_audio_amplify_transform_gdouble_wrap_positive}, { - GST_BUFTYPE_FLOAT, 64, METHOD_NOCLIP, - gst_audio_amplify_transform_gdouble_noclip}, { - GST_BUFTYPE_LINEAR, 8, METHOD_CLIP, gst_audio_amplify_transform_gint8_clip}, { - GST_BUFTYPE_LINEAR, 8, METHOD_WRAP_NEGATIVE, - gst_audio_amplify_transform_gint8_wrap_negative}, { - GST_BUFTYPE_LINEAR, 8, METHOD_WRAP_POSITIVE, - gst_audio_amplify_transform_gint8_wrap_positive}, { - GST_BUFTYPE_LINEAR, 8, METHOD_NOCLIP, - gst_audio_amplify_transform_gint8_noclip}, { - GST_BUFTYPE_LINEAR, 16, METHOD_CLIP, - gst_audio_amplify_transform_gint16_clip}, { - GST_BUFTYPE_LINEAR, 16, METHOD_WRAP_NEGATIVE, - gst_audio_amplify_transform_gint16_wrap_negative}, { - GST_BUFTYPE_LINEAR, 16, METHOD_WRAP_POSITIVE, - gst_audio_amplify_transform_gint16_wrap_positive}, { - GST_BUFTYPE_LINEAR, 16, METHOD_NOCLIP, - gst_audio_amplify_transform_gint16_noclip}, { - GST_BUFTYPE_LINEAR, 32, METHOD_CLIP, - gst_audio_amplify_transform_gint32_clip}, { - GST_BUFTYPE_LINEAR, 32, METHOD_WRAP_NEGATIVE, - gst_audio_amplify_transform_gint32_wrap_negative}, { - GST_BUFTYPE_LINEAR, 32, METHOD_WRAP_POSITIVE, - gst_audio_amplify_transform_gint32_wrap_positive}, { - GST_BUFTYPE_LINEAR, 32, METHOD_NOCLIP, - gst_audio_amplify_transform_gint32_noclip}, { - 0, 0, 0, NULL} - }; - const struct process *p; - - for (p = process; p->func; p++) - if (p->format == format && p->width == width && p->clipping == clipping) - return p->func; - return NULL; -} - -static gboolean -gst_audio_amplify_set_process_function (GstAudioAmplify * filter, gint - clipping_method, gint format, gint width) -{ - GstAudioAmplifyProcessFunc process; - - /* set processing function */ - - process = gst_audio_amplify_process_function (clipping_method, format, width); - if (!process) { - GST_DEBUG ("wrong format"); - return FALSE; - } - - filter->process = process; - filter->clipping_method = clipping_method; - filter->format = format; - filter->width = width; - - return TRUE; -} - -static void -gst_audio_amplify_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAudioAmplify *filter = GST_AUDIO_AMPLIFY (object); - - switch (prop_id) { - case PROP_AMPLIFICATION: - filter->amplification = g_value_get_float (value); - gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), - filter->amplification == 1.0); - break; - case PROP_CLIPPING_METHOD: - gst_audio_amplify_set_process_function (filter, g_value_get_enum (value), - filter->format, filter->width); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_audio_amplify_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAudioAmplify *filter = GST_AUDIO_AMPLIFY (object); - - switch (prop_id) { - case PROP_AMPLIFICATION: - g_value_set_float (value, filter->amplification); - break; - case PROP_CLIPPING_METHOD: - g_value_set_enum (value, filter->clipping_method); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* GstAudioFilter vmethod implementations */ -static gboolean -gst_audio_amplify_setup (GstAudioFilter * base, GstRingBufferSpec * format) -{ - GstAudioAmplify *filter = GST_AUDIO_AMPLIFY (base); - - return gst_audio_amplify_set_process_function (filter, - filter->clipping_method, format->type, format->width); -} - -/* GstBaseTransform vmethod implementations */ -static GstFlowReturn -gst_audio_amplify_transform_ip (GstBaseTransform * base, GstBuffer * buf) -{ - GstAudioAmplify *filter = GST_AUDIO_AMPLIFY (base); - guint num_samples = - GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8); - - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) - gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (buf)); - - if (gst_base_transform_is_passthrough (base) || - G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP))) - return GST_FLOW_OK; - - filter->process (filter, GST_BUFFER_DATA (buf), num_samples); - - return GST_FLOW_OK; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audioamplify.h --- a/gst_plugins_good/gst/audiofx/audioamplify.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2007 Sebastian Dröge - * Copyright (C) 2006 Stefan Kost - * - * 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. - */ - -#ifndef __GST_AUDIO_AMPLIFY_H__ -#define __GST_AUDIO_AMPLIFY_H__ - -#include -#include -#include -#include - -G_BEGIN_DECLS -#define GST_TYPE_AUDIO_AMPLIFY (gst_audio_amplify_get_type()) -#define GST_AUDIO_AMPLIFY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_AMPLIFY,GstAudioAmplify)) -#define GST_IS_AUDIO_AMPLIFY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_AMPLIFY)) -#define GST_AUDIO_AMPLIFY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_AMPLIFY,GstAudioAmplifyClass)) -#define GST_IS_AUDIO_AMPLIFY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_AMPLIFY)) -#define GST_AUDIO_AMPLIFY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_AMPLIFY,GstAudioAmplifyClass)) -typedef struct _GstAudioAmplify GstAudioAmplify; -typedef struct _GstAudioAmplifyClass GstAudioAmplifyClass; - -typedef void (*GstAudioAmplifyProcessFunc) (GstAudioAmplify *, void *, guint); - -struct _GstAudioAmplify -{ - GstAudioFilter audiofilter; - - gfloat amplification; - - /* < private > */ - GstAudioAmplifyProcessFunc process; - gint clipping_method; - gint format; - gint width; -}; - -struct _GstAudioAmplifyClass -{ - GstAudioFilterClass parent; -}; - -GType gst_audio_amplify_get_type (void); - -G_END_DECLS -#endif /* __GST_AUDIO_AMPLIFY_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiochebband.c --- a/gst_plugins_good/gst/audiofx/audiochebband.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,666 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2007-2009 Sebastian Dröge - * - * 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. - */ - -/* - * Chebyshev type 1 filter design based on - * "The Scientist and Engineer's Guide to DSP", Chapter 20. - * http://www.dspguide.com/ - * - * For type 2 and Chebyshev filters in general read - * http://en.wikipedia.org/wiki/Chebyshev_filter - * - * Transformation from lowpass to bandpass/bandreject: - * http://docs.dewresearch.com/DspHelp/html/IDH_LinearSystems_LowpassToBandPassZ.htm - * http://docs.dewresearch.com/DspHelp/html/IDH_LinearSystems_LowpassToBandStopZ.htm - * - */ - -/** - * SECTION:element-audiochebband - * - * Attenuates all frequencies outside (bandpass) or inside (bandreject) of a frequency - * band. The number of poles and the ripple parameter control the rolloff. - * - * This element has the advantage over the windowed sinc bandpass and bandreject filter that it is - * much faster and produces almost as good results. It's only disadvantages are the highly - * non-linear phase and the slower rolloff compared to a windowed sinc filter with a large kernel. - * - * For type 1 the ripple parameter specifies how much ripple in dB is allowed in the passband, i.e. - * some frequencies in the passband will be amplified by that value. A higher ripple value will allow - * a faster rolloff. - * - * For type 2 the ripple parameter specifies the stopband attenuation. In the stopband the gain will - * be at most this value. A lower ripple value will allow a faster rolloff. - * - * As a special case, a Chebyshev type 1 filter with no ripple is a Butterworth filter. - * - * - * Be warned that a too large number of poles can produce noise. The most poles are possible with - * a cutoff frequency at a quarter of the sampling rate. - * - * - * - * Example launch line - * |[ - * gst-launch audiotestsrc freq=1500 ! audioconvert ! audiochebband mode=band-pass lower-frequency=1000 upper-frequenc=6000 poles=4 ! audioconvert ! alsasink - * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiochebband mode=band-reject lower-frequency=1000 upper-frequency=4000 ripple=0.2 ! audioconvert ! alsasink - * gst-launch audiotestsrc wave=white-noise ! audioconvert ! audiochebband mode=band-pass lower-frequency=1000 upper-frequency=4000 type=2 ! audioconvert ! alsasink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include - -#include "math_compat.h" - -#include "audiochebband.h" - -#define GST_CAT_DEFAULT gst_audio_cheb_band_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -enum -{ - PROP_0, - PROP_MODE, - PROP_TYPE, - PROP_LOWER_FREQUENCY, - PROP_UPPER_FREQUENCY, - PROP_RIPPLE, - PROP_POLES -}; - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_audio_cheb_band_debug, "audiochebband", 0, "audiochebband element"); - -GST_BOILERPLATE_FULL (GstAudioChebBand, gst_audio_cheb_band, - GstAudioFXBaseIIRFilter, GST_TYPE_AUDIO_FX_BASE_IIR_FILTER, DEBUG_INIT); - -static void gst_audio_cheb_band_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_audio_cheb_band_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); -static void gst_audio_cheb_band_finalize (GObject * object); - -static gboolean gst_audio_cheb_band_setup (GstAudioFilter * filter, - GstRingBufferSpec * format); - -enum -{ - MODE_BAND_PASS = 0, - MODE_BAND_REJECT -}; - -#define GST_TYPE_AUDIO_CHEBYSHEV_FREQ_BAND_MODE (gst_audio_cheb_band_mode_get_type ()) -static GType -gst_audio_cheb_band_mode_get_type (void) -{ - static GType gtype = 0; - - if (gtype == 0) { - static const GEnumValue values[] = { - {MODE_BAND_PASS, "Band pass (default)", - "band-pass"}, - {MODE_BAND_REJECT, "Band reject", - "band-reject"}, - {0, NULL, NULL} - }; - - gtype = g_enum_register_static ("GstAudioChebBandMode", values); - } - return gtype; -} - -/* GObject vmethod implementations */ - -static void -gst_audio_cheb_band_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gst_element_class_set_details_simple (element_class, - "Band pass & band reject filter", "Filter/Effect/Audio", - "Chebyshev band pass and band reject filter", - "Sebastian Dröge "); -} - -static void -gst_audio_cheb_band_class_init (GstAudioChebBandClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass; - - gobject_class->set_property = gst_audio_cheb_band_set_property; - gobject_class->get_property = gst_audio_cheb_band_get_property; - gobject_class->finalize = gst_audio_cheb_band_finalize; - - g_object_class_install_property (gobject_class, PROP_MODE, - g_param_spec_enum ("mode", "Mode", - "Low pass or high pass mode", GST_TYPE_AUDIO_CHEBYSHEV_FREQ_BAND_MODE, - MODE_BAND_PASS, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_TYPE, - g_param_spec_int ("type", "Type", "Type of the chebychev filter", 1, 2, 1, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - - /* FIXME: Don't use the complete possible range but restrict the upper boundary - * so automatically generated UIs can use a slider without */ - g_object_class_install_property (gobject_class, PROP_LOWER_FREQUENCY, - g_param_spec_float ("lower-frequency", "Lower frequency", - "Start frequency of the band (Hz)", 0.0, 100000.0, - 0.0, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_UPPER_FREQUENCY, - g_param_spec_float ("upper-frequency", "Upper frequency", - "Stop frequency of the band (Hz)", 0.0, 100000.0, 0.0, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_RIPPLE, - g_param_spec_float ("ripple", "Ripple", "Amount of ripple (dB)", 0.0, - 200.0, 0.25, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - /* FIXME: What to do about this upper boundary? With a frequencies near - * rate/4 32 poles are completely possible, with frequencies very low - * or very high 16 poles already produces only noise */ - g_object_class_install_property (gobject_class, PROP_POLES, - g_param_spec_int ("poles", "Poles", - "Number of poles to use, will be rounded up to the next multiply of four", - 4, 32, 4, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - - filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_cheb_band_setup); -} - -static void -gst_audio_cheb_band_init (GstAudioChebBand * filter, - GstAudioChebBandClass * klass) -{ - filter->lower_frequency = filter->upper_frequency = 0.0; - filter->mode = MODE_BAND_PASS; - filter->type = 1; - filter->poles = 4; - filter->ripple = 0.25; - - filter->lock = g_mutex_new (); -} - -static void -generate_biquad_coefficients (GstAudioChebBand * filter, - gint p, gdouble * a0, gdouble * a1, gdouble * a2, gdouble * a3, - gdouble * a4, gdouble * b1, gdouble * b2, gdouble * b3, gdouble * b4) -{ - gint np = filter->poles / 2; - gdouble ripple = filter->ripple; - - /* pole location in s-plane */ - gdouble rp, ip; - - /* zero location in s-plane */ - gdouble iz = 0.0; - - /* transfer function coefficients for the z-plane */ - gdouble x0, x1, x2, y1, y2; - gint type = filter->type; - - /* Calculate pole location for lowpass at frequency 1 */ - { - gdouble angle = (M_PI / 2.0) * (2.0 * p - 1) / np; - - rp = -sin (angle); - ip = cos (angle); - } - - /* If we allow ripple, move the pole from the unit - * circle to an ellipse and keep cutoff at frequency 1 */ - if (ripple > 0 && type == 1) { - gdouble es, vx; - - es = sqrt (pow (10.0, ripple / 10.0) - 1.0); - - vx = (1.0 / np) * asinh (1.0 / es); - rp = rp * sinh (vx); - ip = ip * cosh (vx); - } else if (type == 2) { - gdouble es, vx; - - es = sqrt (pow (10.0, ripple / 10.0) - 1.0); - vx = (1.0 / np) * asinh (es); - rp = rp * sinh (vx); - ip = ip * cosh (vx); - } - - /* Calculate inverse of the pole location to move from - * type I to type II */ - if (type == 2) { - gdouble mag2 = rp * rp + ip * ip; - - rp /= mag2; - ip /= mag2; - } - - /* Calculate zero location for frequency 1 on the - * unit circle for type 2 */ - if (type == 2) { - gdouble angle = M_PI / (np * 2.0) + ((p - 1) * M_PI) / (np); - gdouble mag2; - - iz = cos (angle); - mag2 = iz * iz; - iz /= mag2; - } - - /* Convert from s-domain to z-domain by - * using the bilinear Z-transform, i.e. - * substitute s by (2/t)*((z-1)/(z+1)) - * with t = 2 * tan(0.5). - */ - if (type == 1) { - gdouble t, m, d; - - t = 2.0 * tan (0.5); - m = rp * rp + ip * ip; - d = 4.0 - 4.0 * rp * t + m * t * t; - - x0 = (t * t) / d; - x1 = 2.0 * x0; - x2 = x0; - y1 = (8.0 - 2.0 * m * t * t) / d; - y2 = (-4.0 - 4.0 * rp * t - m * t * t) / d; - } else { - gdouble t, m, d; - - t = 2.0 * tan (0.5); - m = rp * rp + ip * ip; - d = 4.0 - 4.0 * rp * t + m * t * t; - - x0 = (t * t * iz * iz + 4.0) / d; - x1 = (-8.0 + 2.0 * iz * iz * t * t) / d; - x2 = x0; - y1 = (8.0 - 2.0 * m * t * t) / d; - y2 = (-4.0 - 4.0 * rp * t - m * t * t) / d; - } - - /* Convert from lowpass at frequency 1 to either bandpass - * or band reject. - * - * For bandpass substitute z^(-1) with: - * - * -2 -1 - * -z + alpha * z - beta - * ---------------------------- - * -2 -1 - * beta * z - alpha * z + 1 - * - * alpha = (2*a*b)/(1+b) - * beta = (b-1)/(b+1) - * a = cos((w1 + w0)/2) / cos((w1 - w0)/2) - * b = tan(1/2) * cot((w1 - w0)/2) - * - * For bandreject substitute z^(-1) with: - * - * -2 -1 - * z - alpha * z + beta - * ---------------------------- - * -2 -1 - * beta * z - alpha * z + 1 - * - * alpha = (2*a)/(1+b) - * beta = (1-b)/(1+b) - * a = cos((w1 + w0)/2) / cos((w1 - w0)/2) - * b = tan(1/2) * tan((w1 - w0)/2) - * - */ - { - gdouble a, b, d; - gdouble alpha, beta; - gdouble w0 = - 2.0 * M_PI * (filter->lower_frequency / - GST_AUDIO_FILTER (filter)->format.rate); - gdouble w1 = - 2.0 * M_PI * (filter->upper_frequency / - GST_AUDIO_FILTER (filter)->format.rate); - - if (filter->mode == MODE_BAND_PASS) { - a = cos ((w1 + w0) / 2.0) / cos ((w1 - w0) / 2.0); - b = tan (1.0 / 2.0) / tan ((w1 - w0) / 2.0); - - alpha = (2.0 * a * b) / (1.0 + b); - beta = (b - 1.0) / (b + 1.0); - - d = 1.0 + beta * (y1 - beta * y2); - - *a0 = (x0 + beta * (-x1 + beta * x2)) / d; - *a1 = (alpha * (-2.0 * x0 + x1 + beta * x1 - 2.0 * beta * x2)) / d; - *a2 = - (-x1 - beta * beta * x1 + 2.0 * beta * (x0 + x2) + - alpha * alpha * (x0 - x1 + x2)) / d; - *a3 = (alpha * (x1 + beta * (-2.0 * x0 + x1) - 2.0 * x2)) / d; - *a4 = (beta * (beta * x0 - x1) + x2) / d; - *b1 = (alpha * (2.0 + y1 + beta * y1 - 2.0 * beta * y2)) / d; - *b2 = - (-y1 - beta * beta * y1 - alpha * alpha * (1.0 + y1 - y2) + - 2.0 * beta * (-1.0 + y2)) / d; - *b3 = (alpha * (y1 + beta * (2.0 + y1) - 2.0 * y2)) / d; - *b4 = (-beta * beta - beta * y1 + y2) / d; - } else { - a = cos ((w1 + w0) / 2.0) / cos ((w1 - w0) / 2.0); - b = tan (1.0 / 2.0) * tan ((w1 - w0) / 2.0); - - alpha = (2.0 * a) / (1.0 + b); - beta = (1.0 - b) / (1.0 + b); - - d = -1.0 + beta * (beta * y2 + y1); - - *a0 = (-x0 - beta * x1 - beta * beta * x2) / d; - *a1 = (alpha * (2.0 * x0 + x1 + beta * x1 + 2.0 * beta * x2)) / d; - *a2 = - (-x1 - beta * beta * x1 - 2.0 * beta * (x0 + x2) - - alpha * alpha * (x0 + x1 + x2)) / d; - *a3 = (alpha * (x1 + beta * (2.0 * x0 + x1) + 2.0 * x2)) / d; - *a4 = (-beta * beta * x0 - beta * x1 - x2) / d; - *b1 = (alpha * (-2.0 + y1 + beta * y1 + 2.0 * beta * y2)) / d; - *b2 = - -(y1 + beta * beta * y1 + 2.0 * beta * (-1.0 + y2) + - alpha * alpha * (-1.0 + y1 + y2)) / d; - *b3 = (alpha * (beta * (-2.0 + y1) + y1 + 2.0 * y2)) / d; - *b4 = -(-beta * beta + beta * y1 + y2) / d; - } - } -} - -static void -generate_coefficients (GstAudioChebBand * filter) -{ - if (GST_AUDIO_FILTER (filter)->format.rate == 0) { - gdouble *a = g_new0 (gdouble, 1); - - a[0] = 1.0; - gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER - (filter), a, 1, NULL, 0); - GST_LOG_OBJECT (filter, "rate was not set yet"); - return; - } - - if (filter->upper_frequency <= filter->lower_frequency) { - gdouble *a = g_new0 (gdouble, 1); - - a[0] = (filter->mode == MODE_BAND_PASS) ? 0.0 : 1.0; - gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER - (filter), a, 1, NULL, 0); - - GST_LOG_OBJECT (filter, "frequency band had no or negative dimension"); - return; - } - - if (filter->upper_frequency > GST_AUDIO_FILTER (filter)->format.rate / 2) { - filter->upper_frequency = GST_AUDIO_FILTER (filter)->format.rate / 2; - GST_LOG_OBJECT (filter, "clipped upper frequency to nyquist frequency"); - } - - if (filter->lower_frequency < 0.0) { - filter->lower_frequency = 0.0; - GST_LOG_OBJECT (filter, "clipped lower frequency to 0.0"); - } - - /* Calculate coefficients for the chebyshev filter */ - { - gint np = filter->poles; - gdouble *a, *b; - gint i, p; - - a = g_new0 (gdouble, np + 5); - b = g_new0 (gdouble, np + 5); - - /* Calculate transfer function coefficients */ - a[4] = 1.0; - b[4] = 1.0; - - for (p = 1; p <= np / 4; p++) { - gdouble a0, a1, a2, a3, a4, b1, b2, b3, b4; - gdouble *ta = g_new0 (gdouble, np + 5); - gdouble *tb = g_new0 (gdouble, np + 5); - - generate_biquad_coefficients (filter, p, &a0, &a1, &a2, &a3, &a4, &b1, - &b2, &b3, &b4); - - memcpy (ta, a, sizeof (gdouble) * (np + 5)); - memcpy (tb, b, sizeof (gdouble) * (np + 5)); - - /* add the new coefficients for the new two poles - * to the cascade by multiplication of the transfer - * functions */ - for (i = 4; i < np + 5; i++) { - a[i] = - a0 * ta[i] + a1 * ta[i - 1] + a2 * ta[i - 2] + a3 * ta[i - 3] + - a4 * ta[i - 4]; - b[i] = - tb[i] - b1 * tb[i - 1] - b2 * tb[i - 2] - b3 * tb[i - 3] - - b4 * tb[i - 4]; - } - g_free (ta); - g_free (tb); - } - - /* Move coefficients to the beginning of the array - * and multiply the b coefficients with -1 to move from - * the transfer function's coefficients to the difference - * equation's coefficients */ - b[4] = 0.0; - for (i = 0; i <= np; i++) { - a[i] = a[i + 4]; - b[i] = -b[i + 4]; - } - - /* Normalize to unity gain at frequency 0 and frequency - * 0.5 for bandreject and unity gain at band center frequency - * for bandpass */ - if (filter->mode == MODE_BAND_REJECT) { - /* gain is sqrt(H(0)*H(0.5)) */ - - gdouble gain1 = - gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, - 1.0, 0.0); - gdouble gain2 = - gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, - -1.0, 0.0); - - gain1 = sqrt (gain1 * gain2); - - for (i = 0; i <= np; i++) { - a[i] /= gain1; - } - } else { - /* gain is H(wc), wc = center frequency */ - - gdouble w1 = - 2.0 * M_PI * (filter->lower_frequency / - GST_AUDIO_FILTER (filter)->format.rate); - gdouble w2 = - 2.0 * M_PI * (filter->upper_frequency / - GST_AUDIO_FILTER (filter)->format.rate); - gdouble w0 = (w2 + w1) / 2.0; - gdouble zr = cos (w0), zi = sin (w0); - gdouble gain = - gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, zr, - zi); - - for (i = 0; i <= np; i++) { - a[i] /= gain; - } - } - - gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER - (filter), a, np + 1, b, np + 1); - - GST_LOG_OBJECT (filter, - "Generated IIR coefficients for the Chebyshev filter"); - GST_LOG_OBJECT (filter, - "mode: %s, type: %d, poles: %d, lower-frequency: %.2f Hz, upper-frequency: %.2f Hz, ripple: %.2f dB", - (filter->mode == MODE_BAND_PASS) ? "band-pass" : "band-reject", - filter->type, filter->poles, filter->lower_frequency, - filter->upper_frequency, filter->ripple); - - GST_LOG_OBJECT (filter, "%.2f dB gain @ 0Hz", - 20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, - np + 1, 1.0, 0.0))); - { - gdouble w1 = - 2.0 * M_PI * (filter->lower_frequency / - GST_AUDIO_FILTER (filter)->format.rate); - gdouble w2 = - 2.0 * M_PI * (filter->upper_frequency / - GST_AUDIO_FILTER (filter)->format.rate); - gdouble w0 = (w2 + w1) / 2.0; - gdouble zr, zi; - - zr = cos (w1); - zi = sin (w1); - GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz", - 20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, - b, np + 1, zr, zi)), (int) filter->lower_frequency); - zr = cos (w0); - zi = sin (w0); - GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz", - 20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, - b, np + 1, zr, zi)), - (int) ((filter->lower_frequency + filter->upper_frequency) / 2.0)); - zr = cos (w2); - zi = sin (w2); - GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz", - 20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, - b, np + 1, zr, zi)), (int) filter->upper_frequency); - } - GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz", - 20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, - np + 1, -1.0, 0.0)), - GST_AUDIO_FILTER (filter)->format.rate / 2); - } -} - -static void -gst_audio_cheb_band_finalize (GObject * object) -{ - GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object); - - g_mutex_free (filter->lock); - filter->lock = NULL; - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_audio_cheb_band_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object); - - switch (prop_id) { - case PROP_MODE: - g_mutex_lock (filter->lock); - filter->mode = g_value_get_enum (value); - generate_coefficients (filter); - g_mutex_unlock (filter->lock); - break; - case PROP_TYPE: - g_mutex_lock (filter->lock); - filter->type = g_value_get_int (value); - generate_coefficients (filter); - g_mutex_unlock (filter->lock); - break; - case PROP_LOWER_FREQUENCY: - g_mutex_lock (filter->lock); - filter->lower_frequency = g_value_get_float (value); - generate_coefficients (filter); - g_mutex_unlock (filter->lock); - break; - case PROP_UPPER_FREQUENCY: - g_mutex_lock (filter->lock); - filter->upper_frequency = g_value_get_float (value); - generate_coefficients (filter); - g_mutex_unlock (filter->lock); - break; - case PROP_RIPPLE: - g_mutex_lock (filter->lock); - filter->ripple = g_value_get_float (value); - generate_coefficients (filter); - g_mutex_unlock (filter->lock); - break; - case PROP_POLES: - g_mutex_lock (filter->lock); - filter->poles = GST_ROUND_UP_4 (g_value_get_int (value)); - generate_coefficients (filter); - g_mutex_unlock (filter->lock); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_audio_cheb_band_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object); - - switch (prop_id) { - case PROP_MODE: - g_value_set_enum (value, filter->mode); - break; - case PROP_TYPE: - g_value_set_int (value, filter->type); - break; - case PROP_LOWER_FREQUENCY: - g_value_set_float (value, filter->lower_frequency); - break; - case PROP_UPPER_FREQUENCY: - g_value_set_float (value, filter->upper_frequency); - break; - case PROP_RIPPLE: - g_value_set_float (value, filter->ripple); - break; - case PROP_POLES: - g_value_set_int (value, filter->poles); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* GstAudioFilter vmethod implementations */ - -static gboolean -gst_audio_cheb_band_setup (GstAudioFilter * base, GstRingBufferSpec * format) -{ - GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (base); - - generate_coefficients (filter); - - return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, format); -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiochebband.h --- a/gst_plugins_good/gst/audiofx/audiochebband.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2007-2009 Sebastian Dröge - * - * 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. - */ - -#ifndef __GST_AUDIO_CHEB_BAND_H__ -#define __GST_AUDIO_CHEB_BAND_H__ - -#include -#include -#include -#include -#include - -#include "audiofxbaseiirfilter.h" - -G_BEGIN_DECLS -#define GST_TYPE_AUDIO_CHEB_BAND (gst_audio_cheb_band_get_type()) -#define GST_AUDIO_CHEB_BAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_CHEB_BAND,GstAudioChebBand)) -#define GST_IS_AUDIO_CHEB_BAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_CHEB_BAND)) -#define GST_AUDIO_CHEB_BAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_CHEB_BAND,GstAudioChebBandClass)) -#define GST_IS_AUDIO_CHEB_BAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_CHEB_BAND)) -#define GST_AUDIO_CHEB_BAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_CHEB_BAND,GstAudioChebBandClass)) -typedef struct _GstAudioChebBand GstAudioChebBand; -typedef struct _GstAudioChebBandClass GstAudioChebBandClass; - -struct _GstAudioChebBand -{ - GstAudioFXBaseIIRFilter parent; - - gint mode; - gint type; - gint poles; - gfloat lower_frequency; - gfloat upper_frequency; - gfloat ripple; - - /* < private > */ - GMutex *lock; -}; - -struct _GstAudioChebBandClass -{ - GstAudioFXBaseIIRFilterClass parent; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_audio_cheb_band_get_type (void); - -G_END_DECLS -#endif /* __GST_AUDIO_CHEB_BAND_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiocheblimit.c --- a/gst_plugins_good/gst/audiofx/audiocheblimit.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,568 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2007-2009 Sebastian Dröge - * - * 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. - */ - -/* - * Chebyshev type 1 filter design based on - * "The Scientist and Engineer's Guide to DSP", Chapter 20. - * http://www.dspguide.com/ - * - * For type 2 and Chebyshev filters in general read - * http://en.wikipedia.org/wiki/Chebyshev_filter - * - */ - -/** - * SECTION:element-audiocheblimit - * - * Attenuates all frequencies above the cutoff frequency (low-pass) or all frequencies below the - * cutoff frequency (high-pass). The number of poles and the ripple parameter control the rolloff. - * - * This element has the advantage over the windowed sinc lowpass and highpass filter that it is - * much faster and produces almost as good results. It's only disadvantages are the highly - * non-linear phase and the slower rolloff compared to a windowed sinc filter with a large kernel. - * - * For type 1 the ripple parameter specifies how much ripple in dB is allowed in the passband, i.e. - * some frequencies in the passband will be amplified by that value. A higher ripple value will allow - * a faster rolloff. - * - * For type 2 the ripple parameter specifies the stopband attenuation. In the stopband the gain will - * be at most this value. A lower ripple value will allow a faster rolloff. - * - * As a special case, a Chebyshev type 1 filter with no ripple is a Butterworth filter. - * - * - * Be warned that a too large number of poles can produce noise. The most poles are possible with - * a cutoff frequency at a quarter of the sampling rate. - * - * - * - * Example launch line - * |[ - * gst-launch audiotestsrc freq=1500 ! audioconvert ! audiocheblimit mode=low-pass cutoff=1000 poles=4 ! audioconvert ! alsasink - * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiocheblimit mode=high-pass cutoff=400 ripple=0.2 ! audioconvert ! alsasink - * gst-launch audiotestsrc wave=white-noise ! audioconvert ! audiocheblimit mode=low-pass cutoff=800 type=2 ! audioconvert ! alsasink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include - -#include "math_compat.h" - -#include "audiocheblimit.h" - -#define GST_CAT_DEFAULT gst_audio_cheb_limit_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -enum -{ - PROP_0, - PROP_MODE, - PROP_TYPE, - PROP_CUTOFF, - PROP_RIPPLE, - PROP_POLES -}; - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_audio_cheb_limit_debug, "audiocheblimit", 0, "audiocheblimit element"); - -GST_BOILERPLATE_FULL (GstAudioChebLimit, - gst_audio_cheb_limit, GstAudioFXBaseIIRFilter, - GST_TYPE_AUDIO_FX_BASE_IIR_FILTER, DEBUG_INIT); - -static void gst_audio_cheb_limit_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_audio_cheb_limit_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); -static void gst_audio_cheb_limit_finalize (GObject * object); - -static gboolean gst_audio_cheb_limit_setup (GstAudioFilter * filter, - GstRingBufferSpec * format); - -enum -{ - MODE_LOW_PASS = 0, - MODE_HIGH_PASS -}; - -#define GST_TYPE_AUDIO_CHEBYSHEV_FREQ_LIMIT_MODE (gst_audio_cheb_limit_mode_get_type ()) -static GType -gst_audio_cheb_limit_mode_get_type (void) -{ - static GType gtype = 0; - - if (gtype == 0) { - static const GEnumValue values[] = { - {MODE_LOW_PASS, "Low pass (default)", - "low-pass"}, - {MODE_HIGH_PASS, "High pass", - "high-pass"}, - {0, NULL, NULL} - }; - - gtype = g_enum_register_static ("GstAudioChebLimitMode", values); - } - return gtype; -} - -/* GObject vmethod implementations */ - -static void -gst_audio_cheb_limit_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gst_element_class_set_details_simple (element_class, - "Low pass & high pass filter", - "Filter/Effect/Audio", - "Chebyshev low pass and high pass filter", - "Sebastian Dröge "); -} - -static void -gst_audio_cheb_limit_class_init (GstAudioChebLimitClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass; - - gobject_class->set_property = gst_audio_cheb_limit_set_property; - gobject_class->get_property = gst_audio_cheb_limit_get_property; - gobject_class->finalize = gst_audio_cheb_limit_finalize; - - g_object_class_install_property (gobject_class, PROP_MODE, - g_param_spec_enum ("mode", "Mode", - "Low pass or high pass mode", - GST_TYPE_AUDIO_CHEBYSHEV_FREQ_LIMIT_MODE, MODE_LOW_PASS, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_TYPE, - g_param_spec_int ("type", "Type", "Type of the chebychev filter", 1, 2, 1, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - - /* FIXME: Don't use the complete possible range but restrict the upper boundary - * so automatically generated UIs can use a slider without */ - g_object_class_install_property (gobject_class, PROP_CUTOFF, - g_param_spec_float ("cutoff", "Cutoff", "Cut off frequency (Hz)", 0.0, - 100000.0, 0.0, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_RIPPLE, - g_param_spec_float ("ripple", "Ripple", "Amount of ripple (dB)", 0.0, - 200.0, 0.25, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - - /* FIXME: What to do about this upper boundary? With a cutoff frequency of - * rate/4 32 poles are completely possible, with a cutoff frequency very low - * or very high 16 poles already produces only noise */ - g_object_class_install_property (gobject_class, PROP_POLES, - g_param_spec_int ("poles", "Poles", - "Number of poles to use, will be rounded up to the next even number", - 2, 32, 4, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - - filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_cheb_limit_setup); -} - -static void -gst_audio_cheb_limit_init (GstAudioChebLimit * filter, - GstAudioChebLimitClass * klass) -{ - filter->cutoff = 0.0; - filter->mode = MODE_LOW_PASS; - filter->type = 1; - filter->poles = 4; - filter->ripple = 0.25; - - filter->lock = g_mutex_new (); -} - -static void -generate_biquad_coefficients (GstAudioChebLimit * filter, - gint p, gdouble * a0, gdouble * a1, gdouble * a2, - gdouble * b1, gdouble * b2) -{ - gint np = filter->poles; - gdouble ripple = filter->ripple; - - /* pole location in s-plane */ - gdouble rp, ip; - - /* zero location in s-plane */ - gdouble iz = 0.0; - - /* transfer function coefficients for the z-plane */ - gdouble x0, x1, x2, y1, y2; - gint type = filter->type; - - /* Calculate pole location for lowpass at frequency 1 */ - { - gdouble angle = (M_PI / 2.0) * (2.0 * p - 1) / np; - - rp = -sin (angle); - ip = cos (angle); - } - - /* If we allow ripple, move the pole from the unit - * circle to an ellipse and keep cutoff at frequency 1 */ - if (ripple > 0 && type == 1) { - gdouble es, vx; - - es = sqrt (pow (10.0, ripple / 10.0) - 1.0); - - vx = (1.0 / np) * asinh (1.0 / es); - rp = rp * sinh (vx); - ip = ip * cosh (vx); - } else if (type == 2) { - gdouble es, vx; - - es = sqrt (pow (10.0, ripple / 10.0) - 1.0); - vx = (1.0 / np) * asinh (es); - rp = rp * sinh (vx); - ip = ip * cosh (vx); - } - - /* Calculate inverse of the pole location to convert from - * type I to type II */ - if (type == 2) { - gdouble mag2 = rp * rp + ip * ip; - - rp /= mag2; - ip /= mag2; - } - - /* Calculate zero location for frequency 1 on the - * unit circle for type 2 */ - if (type == 2) { - gdouble angle = M_PI / (np * 2.0) + ((p - 1) * M_PI) / (np); - gdouble mag2; - - iz = cos (angle); - mag2 = iz * iz; - iz /= mag2; - } - - /* Convert from s-domain to z-domain by - * using the bilinear Z-transform, i.e. - * substitute s by (2/t)*((z-1)/(z+1)) - * with t = 2 * tan(0.5). - */ - if (type == 1) { - gdouble t, m, d; - - t = 2.0 * tan (0.5); - m = rp * rp + ip * ip; - d = 4.0 - 4.0 * rp * t + m * t * t; - - x0 = (t * t) / d; - x1 = 2.0 * x0; - x2 = x0; - y1 = (8.0 - 2.0 * m * t * t) / d; - y2 = (-4.0 - 4.0 * rp * t - m * t * t) / d; - } else { - gdouble t, m, d; - - t = 2.0 * tan (0.5); - m = rp * rp + ip * ip; - d = 4.0 - 4.0 * rp * t + m * t * t; - - x0 = (t * t * iz * iz + 4.0) / d; - x1 = (-8.0 + 2.0 * iz * iz * t * t) / d; - x2 = x0; - y1 = (8.0 - 2.0 * m * t * t) / d; - y2 = (-4.0 - 4.0 * rp * t - m * t * t) / d; - } - - /* Convert from lowpass at frequency 1 to either lowpass - * or highpass. - * - * For lowpass substitute z^(-1) with: - * -1 - * z - k - * ------------ - * -1 - * 1 - k * z - * - * k = sin((1-w)/2) / sin((1+w)/2) - * - * For highpass substitute z^(-1) with: - * - * -1 - * -z - k - * ------------ - * -1 - * 1 + k * z - * - * k = -cos((1+w)/2) / cos((1-w)/2) - * - */ - { - gdouble k, d; - gdouble omega = - 2.0 * M_PI * (filter->cutoff / GST_AUDIO_FILTER (filter)->format.rate); - - if (filter->mode == MODE_LOW_PASS) - k = sin ((1.0 - omega) / 2.0) / sin ((1.0 + omega) / 2.0); - else - k = -cos ((omega + 1.0) / 2.0) / cos ((omega - 1.0) / 2.0); - - d = 1.0 + y1 * k - y2 * k * k; - *a0 = (x0 + k * (-x1 + k * x2)) / d; - *a1 = (x1 + k * k * x1 - 2.0 * k * (x0 + x2)) / d; - *a2 = (x0 * k * k - x1 * k + x2) / d; - *b1 = (2.0 * k + y1 + y1 * k * k - 2.0 * y2 * k) / d; - *b2 = (-k * k - y1 * k + y2) / d; - - if (filter->mode == MODE_HIGH_PASS) { - *a1 = -*a1; - *b1 = -*b1; - } - } -} - -static void -generate_coefficients (GstAudioChebLimit * filter) -{ - if (GST_AUDIO_FILTER (filter)->format.rate == 0) { - gdouble *a = g_new0 (gdouble, 1); - - a[0] = 1.0; - gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER - (filter), a, 1, NULL, 0); - - GST_LOG_OBJECT (filter, "rate was not set yet"); - return; - } - - if (filter->cutoff >= GST_AUDIO_FILTER (filter)->format.rate / 2.0) { - gdouble *a = g_new0 (gdouble, 1); - - a[0] = (filter->mode == MODE_LOW_PASS) ? 1.0 : 0.0; - gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER - (filter), a, 1, NULL, 0); - GST_LOG_OBJECT (filter, "cutoff was higher than nyquist frequency"); - return; - } else if (filter->cutoff <= 0.0) { - gdouble *a = g_new0 (gdouble, 1); - - a[0] = (filter->mode == MODE_LOW_PASS) ? 0.0 : 1.0; - gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER - (filter), a, 1, NULL, 0); - GST_LOG_OBJECT (filter, "cutoff is lower than zero"); - return; - } - - /* Calculate coefficients for the chebyshev filter */ - { - gint np = filter->poles; - gdouble *a, *b; - gint i, p; - - a = g_new0 (gdouble, np + 3); - b = g_new0 (gdouble, np + 3); - - /* Calculate transfer function coefficients */ - a[2] = 1.0; - b[2] = 1.0; - - for (p = 1; p <= np / 2; p++) { - gdouble a0, a1, a2, b1, b2; - gdouble *ta = g_new0 (gdouble, np + 3); - gdouble *tb = g_new0 (gdouble, np + 3); - - generate_biquad_coefficients (filter, p, &a0, &a1, &a2, &b1, &b2); - - memcpy (ta, a, sizeof (gdouble) * (np + 3)); - memcpy (tb, b, sizeof (gdouble) * (np + 3)); - - /* add the new coefficients for the new two poles - * to the cascade by multiplication of the transfer - * functions */ - for (i = 2; i < np + 3; i++) { - a[i] = a0 * ta[i] + a1 * ta[i - 1] + a2 * ta[i - 2]; - b[i] = tb[i] - b1 * tb[i - 1] - b2 * tb[i - 2]; - } - g_free (ta); - g_free (tb); - } - - /* Move coefficients to the beginning of the array - * and multiply the b coefficients with -1 to move from - * the transfer function's coefficients to the difference - * equation's coefficients */ - b[2] = 0.0; - for (i = 0; i <= np; i++) { - a[i] = a[i + 2]; - b[i] = -b[i + 2]; - } - - /* Normalize to unity gain at frequency 0 for lowpass - * and frequency 0.5 for highpass */ - { - gdouble gain; - - if (filter->mode == MODE_LOW_PASS) - gain = - gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, - 1.0, 0.0); - else - gain = - gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, - -1.0, 0.0); - - for (i = 0; i <= np; i++) { - a[i] /= gain; - } - } - - gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER - (filter), a, np + 1, b, np + 1); - - GST_LOG_OBJECT (filter, - "Generated IIR coefficients for the Chebyshev filter"); - GST_LOG_OBJECT (filter, - "mode: %s, type: %d, poles: %d, cutoff: %.2f Hz, ripple: %.2f dB", - (filter->mode == MODE_LOW_PASS) ? "low-pass" : "high-pass", - filter->type, filter->poles, filter->cutoff, filter->ripple); - GST_LOG_OBJECT (filter, "%.2f dB gain @ 0 Hz", - 20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, - np + 1, 1.0, 0.0))); - -#ifndef GST_DISABLE_GST_DEBUG - { - gdouble wc = - 2.0 * M_PI * (filter->cutoff / - GST_AUDIO_FILTER (filter)->format.rate); - gdouble zr = cos (wc), zi = sin (wc); - - GST_LOG_OBJECT (filter, "%.2f dB gain @ %d Hz", - 20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, - b, np + 1, zr, zi)), (int) filter->cutoff); - } -#endif - - GST_LOG_OBJECT (filter, "%.2f dB gain @ %d Hz", - 20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, - np + 1, -1.0, 0.0)), - GST_AUDIO_FILTER (filter)->format.rate / 2); - } -} - -static void -gst_audio_cheb_limit_finalize (GObject * object) -{ - GstAudioChebLimit *filter = GST_AUDIO_CHEB_LIMIT (object); - - g_mutex_free (filter->lock); - filter->lock = NULL; - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_audio_cheb_limit_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAudioChebLimit *filter = GST_AUDIO_CHEB_LIMIT (object); - - switch (prop_id) { - case PROP_MODE: - g_mutex_lock (filter->lock); - filter->mode = g_value_get_enum (value); - generate_coefficients (filter); - g_mutex_unlock (filter->lock); - break; - case PROP_TYPE: - g_mutex_lock (filter->lock); - filter->type = g_value_get_int (value); - generate_coefficients (filter); - g_mutex_unlock (filter->lock); - break; - case PROP_CUTOFF: - g_mutex_lock (filter->lock); - filter->cutoff = g_value_get_float (value); - generate_coefficients (filter); - g_mutex_unlock (filter->lock); - break; - case PROP_RIPPLE: - g_mutex_lock (filter->lock); - filter->ripple = g_value_get_float (value); - generate_coefficients (filter); - g_mutex_unlock (filter->lock); - break; - case PROP_POLES: - g_mutex_lock (filter->lock); - filter->poles = GST_ROUND_UP_2 (g_value_get_int (value)); - generate_coefficients (filter); - g_mutex_unlock (filter->lock); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_audio_cheb_limit_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAudioChebLimit *filter = GST_AUDIO_CHEB_LIMIT (object); - - switch (prop_id) { - case PROP_MODE: - g_value_set_enum (value, filter->mode); - break; - case PROP_TYPE: - g_value_set_int (value, filter->type); - break; - case PROP_CUTOFF: - g_value_set_float (value, filter->cutoff); - break; - case PROP_RIPPLE: - g_value_set_float (value, filter->ripple); - break; - case PROP_POLES: - g_value_set_int (value, filter->poles); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* GstAudioFilter vmethod implementations */ - -static gboolean -gst_audio_cheb_limit_setup (GstAudioFilter * base, GstRingBufferSpec * format) -{ - GstAudioChebLimit *filter = GST_AUDIO_CHEB_LIMIT (base); - - generate_coefficients (filter); - - return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, format); -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiocheblimit.h --- a/gst_plugins_good/gst/audiofx/audiocheblimit.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2007-2009 Sebastian Dröge - * - * 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. - */ - -#ifndef __GST_AUDIO_CHEB_LIMIT_H__ -#define __GST_AUDIO_CHEB_LIMIT_H__ - -#include -#include -#include -#include -#include - -#include "audiofxbaseiirfilter.h" - -G_BEGIN_DECLS - -#define GST_TYPE_AUDIO_CHEB_LIMIT (gst_audio_cheb_limit_get_type()) -#define GST_AUDIO_CHEB_LIMIT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_CHEB_LIMIT,GstAudioChebLimit)) -#define GST_IS_AUDIO_CHEB_LIMIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_CHEB_LIMIT)) -#define GST_AUDIO_CHEB_LIMIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_CHEB_LIMIT,GstAudioChebLimitClass)) -#define GST_IS_AUDIO_CHEB_LIMIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_CHEB_LIMIT)) -#define GST_AUDIO_CHEB_LIMIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_CHEB_LIMIT,GstAudioChebLimitClass)) - -typedef struct _GstAudioChebLimit GstAudioChebLimit; -typedef struct _GstAudioChebLimitClass GstAudioChebLimitClass; - -struct _GstAudioChebLimit -{ - GstAudioFXBaseIIRFilter parent; - - gint mode; - gint type; - gint poles; - gfloat cutoff; - gfloat ripple; - - /* < private > */ - GMutex *lock; -}; - -struct _GstAudioChebLimitClass -{ - GstAudioFXBaseIIRFilterClass parent; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_audio_cheb_limit_get_type (void); - -G_END_DECLS - -#endif /* __GST_AUDIO_CHEB_LIMIT_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiodynamic.c --- a/gst_plugins_good/gst/audiofx/audiodynamic.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,711 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -/** - * SECTION:element-audiodynamic - * - * This element can act as a compressor or expander. A compressor changes the - * amplitude of all samples above a specific threshold with a specific ratio, - * a expander does the same for all samples below a specific threshold. If - * soft-knee mode is selected the ratio is applied smoothly. - * - * - * Example launch line - * |[ - * gst-launch audiotestsrc wave=saw ! audiodynamic characteristics=soft-knee mode=compressor threshold=0.5 rate=0.5 ! alsasink - * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiodynamic characteristics=hard-knee mode=expander threshold=0.2 rate=4.0 ! alsasink - * gst-launch audiotestsrc wave=saw ! audioconvert ! audiodynamic ! audioconvert ! alsasink - * ]| - * - */ - -/* TODO: Implement attack and release parameters */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "audiodynamic.h" - -#define GST_CAT_DEFAULT gst_audio_dynamic_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -static const GstElementDetails element_details = -GST_ELEMENT_DETAILS ("Dynamic range controller", - "Filter/Effect/Audio", - "Compressor and Expander", - "Sebastian Dröge "); - -/* Filter signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - PROP_0, - PROP_CHARACTERISTICS, - PROP_MODE, - PROP_THRESHOLD, - PROP_RATIO -}; - -#define ALLOWED_CAPS \ - "audio/x-raw-int," \ - " depth=(int)16," \ - " width=(int)16," \ - " endianness=(int)BYTE_ORDER," \ - " signed=(bool)TRUE," \ - " rate=(int)[1,MAX]," \ - " channels=(int)[1,MAX]; " \ - "audio/x-raw-float," \ - " width=(int)32," \ - " endianness=(int)BYTE_ORDER," \ - " rate=(int)[1,MAX]," \ - " channels=(int)[1,MAX]" - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_audio_dynamic_debug, "audiodynamic", 0, "audiodynamic element"); - -GST_BOILERPLATE_FULL (GstAudioDynamic, gst_audio_dynamic, GstAudioFilter, - GST_TYPE_AUDIO_FILTER, DEBUG_INIT); - -static void gst_audio_dynamic_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_audio_dynamic_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static gboolean gst_audio_dynamic_setup (GstAudioFilter * filter, - GstRingBufferSpec * format); -static GstFlowReturn gst_audio_dynamic_transform_ip (GstBaseTransform * base, - GstBuffer * buf); - -static void -gst_audio_dynamic_transform_hard_knee_compressor_int (GstAudioDynamic * filter, - gint16 * data, guint num_samples); -static void -gst_audio_dynamic_transform_hard_knee_compressor_float (GstAudioDynamic * - filter, gfloat * data, guint num_samples); -static void -gst_audio_dynamic_transform_soft_knee_compressor_int (GstAudioDynamic * filter, - gint16 * data, guint num_samples); -static void -gst_audio_dynamic_transform_soft_knee_compressor_float (GstAudioDynamic * - filter, gfloat * data, guint num_samples); -static void gst_audio_dynamic_transform_hard_knee_expander_int (GstAudioDynamic - * filter, gint16 * data, guint num_samples); -static void -gst_audio_dynamic_transform_hard_knee_expander_float (GstAudioDynamic * filter, - gfloat * data, guint num_samples); -static void gst_audio_dynamic_transform_soft_knee_expander_int (GstAudioDynamic - * filter, gint16 * data, guint num_samples); -static void -gst_audio_dynamic_transform_soft_knee_expander_float (GstAudioDynamic * filter, - gfloat * data, guint num_samples); - -static GstAudioDynamicProcessFunc process_functions[] = { - (GstAudioDynamicProcessFunc) - gst_audio_dynamic_transform_hard_knee_compressor_int, - (GstAudioDynamicProcessFunc) - gst_audio_dynamic_transform_hard_knee_compressor_float, - (GstAudioDynamicProcessFunc) - gst_audio_dynamic_transform_soft_knee_compressor_int, - (GstAudioDynamicProcessFunc) - gst_audio_dynamic_transform_soft_knee_compressor_float, - (GstAudioDynamicProcessFunc) - gst_audio_dynamic_transform_hard_knee_expander_int, - (GstAudioDynamicProcessFunc) - gst_audio_dynamic_transform_hard_knee_expander_float, - (GstAudioDynamicProcessFunc) - gst_audio_dynamic_transform_soft_knee_expander_int, - (GstAudioDynamicProcessFunc) - gst_audio_dynamic_transform_soft_knee_expander_float -}; - -enum -{ - CHARACTERISTICS_HARD_KNEE = 0, - CHARACTERISTICS_SOFT_KNEE -}; - -#define GST_TYPE_AUDIO_DYNAMIC_CHARACTERISTICS (gst_audio_dynamic_characteristics_get_type ()) -static GType -gst_audio_dynamic_characteristics_get_type (void) -{ - static GType gtype = 0; - - if (gtype == 0) { - static const GEnumValue values[] = { - {CHARACTERISTICS_HARD_KNEE, "Hard Knee (default)", - "hard-knee"}, - {CHARACTERISTICS_SOFT_KNEE, "Soft Knee (smooth)", - "soft-knee"}, - {0, NULL, NULL} - }; - - gtype = g_enum_register_static ("GstAudioDynamicCharacteristics", values); - } - return gtype; -} - -enum -{ - MODE_COMPRESSOR = 0, - MODE_EXPANDER -}; - -#define GST_TYPE_AUDIO_DYNAMIC_MODE (gst_audio_dynamic_mode_get_type ()) -static GType -gst_audio_dynamic_mode_get_type (void) -{ - static GType gtype = 0; - - if (gtype == 0) { - static const GEnumValue values[] = { - {MODE_COMPRESSOR, "Compressor (default)", - "compressor"}, - {MODE_EXPANDER, "Expander", "expander"}, - {0, NULL, NULL} - }; - - gtype = g_enum_register_static ("GstAudioDynamicMode", values); - } - return gtype; -} - -static gboolean -gst_audio_dynamic_set_process_function (GstAudioDynamic * filter) -{ - gint func_index; - - func_index = (filter->mode == MODE_COMPRESSOR) ? 0 : 4; - func_index += (filter->characteristics == CHARACTERISTICS_HARD_KNEE) ? 0 : 2; - func_index += - (GST_AUDIO_FILTER (filter)->format.type == GST_BUFTYPE_FLOAT) ? 1 : 0; - - if (func_index >= 0 && func_index < 8) { - filter->process = process_functions[func_index]; - return TRUE; - } - - return FALSE; -} - -/* GObject vmethod implementations */ - -static void -gst_audio_dynamic_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstCaps *caps; - - gst_element_class_set_details (element_class, &element_details); - - caps = gst_caps_from_string (ALLOWED_CAPS); - gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass), - caps); - gst_caps_unref (caps); -} - -static void -gst_audio_dynamic_class_init (GstAudioDynamicClass * klass) -{ - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - gobject_class->set_property = gst_audio_dynamic_set_property; - gobject_class->get_property = gst_audio_dynamic_get_property; - - g_object_class_install_property (gobject_class, PROP_CHARACTERISTICS, - g_param_spec_enum ("characteristics", "Characteristics", - "Selects whether the ratio should be applied smooth (soft-knee) " - "or hard (hard-knee).", - GST_TYPE_AUDIO_DYNAMIC_CHARACTERISTICS, CHARACTERISTICS_HARD_KNEE, - G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_MODE, - g_param_spec_enum ("mode", "Mode", - "Selects whether the filter should work on loud samples (compressor) or" - "quiet samples (expander).", - GST_TYPE_AUDIO_DYNAMIC_MODE, MODE_COMPRESSOR, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_THRESHOLD, - g_param_spec_float ("threshold", "Threshold", - "Threshold until the filter is activated", 0.0, 1.0, - 0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - - g_object_class_install_property (gobject_class, PROP_RATIO, - g_param_spec_float ("ratio", "Ratio", - "Ratio that should be applied", 0.0, G_MAXFLOAT, - 1.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - - GST_AUDIO_FILTER_CLASS (klass)->setup = - GST_DEBUG_FUNCPTR (gst_audio_dynamic_setup); - GST_BASE_TRANSFORM_CLASS (klass)->transform_ip = - GST_DEBUG_FUNCPTR (gst_audio_dynamic_transform_ip); -} - -static void -gst_audio_dynamic_init (GstAudioDynamic * filter, GstAudioDynamicClass * klass) -{ - filter->ratio = 1.0; - filter->threshold = 0.0; - filter->characteristics = CHARACTERISTICS_HARD_KNEE; - filter->mode = MODE_COMPRESSOR; - gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE); - gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE); -} - -static void -gst_audio_dynamic_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAudioDynamic *filter = GST_AUDIO_DYNAMIC (object); - - switch (prop_id) { - case PROP_CHARACTERISTICS: - filter->characteristics = g_value_get_enum (value); - gst_audio_dynamic_set_process_function (filter); - break; - case PROP_MODE: - filter->mode = g_value_get_enum (value); - gst_audio_dynamic_set_process_function (filter); - break; - case PROP_THRESHOLD: - filter->threshold = g_value_get_float (value); - break; - case PROP_RATIO: - filter->ratio = g_value_get_float (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_audio_dynamic_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAudioDynamic *filter = GST_AUDIO_DYNAMIC (object); - - switch (prop_id) { - case PROP_CHARACTERISTICS: - g_value_set_enum (value, filter->characteristics); - break; - case PROP_MODE: - g_value_set_enum (value, filter->mode); - break; - case PROP_THRESHOLD: - g_value_set_float (value, filter->threshold); - break; - case PROP_RATIO: - g_value_set_float (value, filter->ratio); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* GstAudioFilter vmethod implementations */ - -static gboolean -gst_audio_dynamic_setup (GstAudioFilter * base, GstRingBufferSpec * format) -{ - GstAudioDynamic *filter = GST_AUDIO_DYNAMIC (base); - gboolean ret = TRUE; - - ret = gst_audio_dynamic_set_process_function (filter); - - return ret; -} - -static void -gst_audio_dynamic_transform_hard_knee_compressor_int (GstAudioDynamic * filter, - gint16 * data, guint num_samples) -{ - glong val; - glong thr_p = filter->threshold * G_MAXINT16; - glong thr_n = filter->threshold * G_MININT16; - - /* Nothing to do for us if ratio is 1.0 or if the threshold - * equals 1.0. */ - if (filter->threshold == 1.0 || filter->ratio == 1.0) - return; - - for (; num_samples; num_samples--) { - val = *data; - - if (val > thr_p) { - val = thr_p + (val - thr_p) * filter->ratio; - } else if (val < thr_n) { - val = thr_n + (val - thr_n) * filter->ratio; - } - *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16); - } -} - -static void -gst_audio_dynamic_transform_hard_knee_compressor_float (GstAudioDynamic * - filter, gfloat * data, guint num_samples) -{ - gdouble val, threshold = filter->threshold; - - /* Nothing to do for us if ratio == 1.0. - * As float values can be above 1.0 we have to do something - * if threshold is greater than 1.0. */ - if (filter->ratio == 1.0) - return; - - for (; num_samples; num_samples--) { - val = *data; - - if (val > threshold) { - val = threshold + (val - threshold) * filter->ratio; - } else if (val < -threshold) { - val = -threshold + (val + threshold) * filter->ratio; - } - *data++ = (gfloat) val; - } -} - -static void -gst_audio_dynamic_transform_soft_knee_compressor_int (GstAudioDynamic * filter, - gint16 * data, guint num_samples) -{ - glong val; - glong thr_p = filter->threshold * G_MAXINT16; - glong thr_n = filter->threshold * G_MININT16; - gdouble a_p, b_p, c_p; - gdouble a_n, b_n, c_n; - - /* Nothing to do for us if ratio is 1.0 or if the threshold - * equals 1.0. */ - if (filter->threshold == 1.0 || filter->ratio == 1.0) - return; - - /* We build a 2nd degree polynomial here for - * values greater than threshold or small than - * -threshold with: - * f(t) = t, f'(t) = 1, f'(m) = r - * => - * a = (1-r)/(2*(t-m)) - * b = (r*t - m)/(t-m) - * c = t * (1 - b - a*t) - * f(x) = ax^2 + bx + c - */ - - /* shouldn't happen because this would only be the case - * for threshold == 1.0 which we catch above */ - g_assert (thr_p - G_MAXINT16 != 0); - g_assert (thr_n - G_MININT != 0); - - a_p = (1 - filter->ratio) / (2 * (thr_p - G_MAXINT16)); - b_p = (filter->ratio * thr_p - G_MAXINT16) / (thr_p - G_MAXINT16); - c_p = thr_p * (1 - b_p - a_p * thr_p); - a_n = (1 - filter->ratio) / (2 * (thr_n - G_MININT16)); - b_n = (filter->ratio * thr_n - G_MININT16) / (thr_n - G_MININT16); - c_n = thr_n * (1 - b_n - a_n * thr_n); - - for (; num_samples; num_samples--) { - val = *data; - - if (val > thr_p) { - val = a_p * val * val + b_p * val + c_p; - } else if (val < thr_n) { - val = a_n * val * val + b_n * val + c_n; - } - *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16); - } -} - -static void -gst_audio_dynamic_transform_soft_knee_compressor_float (GstAudioDynamic * - filter, gfloat * data, guint num_samples) -{ - gdouble val; - gdouble threshold = filter->threshold; - gdouble a_p, b_p, c_p; - gdouble a_n, b_n, c_n; - - /* Nothing to do for us if ratio == 1.0. - * As float values can be above 1.0 we have to do something - * if threshold is greater than 1.0. */ - if (filter->ratio == 1.0) - return; - - /* We build a 2nd degree polynomial here for - * values greater than threshold or small than - * -threshold with: - * f(t) = t, f'(t) = 1, f'(m) = r - * => - * a = (1-r)/(2*(t-m)) - * b = (r*t - m)/(t-m) - * c = t * (1 - b - a*t) - * f(x) = ax^2 + bx + c - */ - - /* FIXME: If treshold is the same as the maximum - * we need to raise it a bit to prevent - * division by zero. */ - if (threshold == 1.0) - threshold = 1.0 + 0.00001; - - a_p = (1.0 - filter->ratio) / (2.0 * (threshold - 1.0)); - b_p = (filter->ratio * threshold - 1.0) / (threshold - 1.0); - c_p = threshold * (1.0 - b_p - a_p * threshold); - a_n = (1.0 - filter->ratio) / (2.0 * (-threshold + 1.0)); - b_n = (-filter->ratio * threshold + 1.0) / (-threshold + 1.0); - c_n = -threshold * (1.0 - b_n + a_n * threshold); - - for (; num_samples; num_samples--) { - val = *data; - - if (val > 1.0) { - val = 1.0 + (val - 1.0) * filter->ratio; - } else if (val > threshold) { - val = a_p * val * val + b_p * val + c_p; - } else if (val < -1.0) { - val = -1.0 + (val + 1.0) * filter->ratio; - } else if (val < -threshold) { - val = a_n * val * val + b_n * val + c_n; - } - *data++ = (gfloat) val; - } -} - -static void -gst_audio_dynamic_transform_hard_knee_expander_int (GstAudioDynamic * filter, - gint16 * data, guint num_samples) -{ - glong val; - glong thr_p = filter->threshold * G_MAXINT16; - glong thr_n = filter->threshold * G_MININT16; - gdouble zero_p, zero_n; - - /* Nothing to do for us here if threshold equals 0.0 - * or ratio equals 1.0 */ - if (filter->threshold == 0.0 || filter->ratio == 1.0) - return; - - /* zero crossing of our function */ - if (filter->ratio != 0.0) { - zero_p = thr_p - thr_p / filter->ratio; - zero_n = thr_n - thr_n / filter->ratio; - } else { - zero_p = zero_n = 0.0; - } - - if (zero_p < 0.0) - zero_p = 0.0; - if (zero_n > 0.0) - zero_n = 0.0; - - for (; num_samples; num_samples--) { - val = *data; - - if (val < thr_p && val > zero_p) { - val = filter->ratio * val + thr_p * (1 - filter->ratio); - } else if ((val <= zero_p && val > 0) || (val >= zero_n && val < 0)) { - val = 0; - } else if (val > thr_n && val < zero_n) { - val = filter->ratio * val + thr_n * (1 - filter->ratio); - } - *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16); - } -} - -static void -gst_audio_dynamic_transform_hard_knee_expander_float (GstAudioDynamic * filter, - gfloat * data, guint num_samples) -{ - gdouble val, threshold = filter->threshold, zero; - - /* Nothing to do for us here if threshold equals 0.0 - * or ratio equals 1.0 */ - if (filter->threshold == 0.0 || filter->ratio == 1.0) - return; - - /* zero crossing of our function */ - if (filter->ratio != 0.0) - zero = threshold - threshold / filter->ratio; - else - zero = 0.0; - - if (zero < 0.0) - zero = 0.0; - - for (; num_samples; num_samples--) { - val = *data; - - if (val < threshold && val > zero) { - val = filter->ratio * val + threshold * (1.0 - filter->ratio); - } else if ((val <= zero && val > 0.0) || (val >= -zero && val < 0.0)) { - val = 0.0; - } else if (val > -threshold && val < -zero) { - val = filter->ratio * val - threshold * (1.0 - filter->ratio); - } - *data++ = (gfloat) val; - } -} - -static void -gst_audio_dynamic_transform_soft_knee_expander_int (GstAudioDynamic * filter, - gint16 * data, guint num_samples) -{ - glong val; - glong thr_p = filter->threshold * G_MAXINT16; - glong thr_n = filter->threshold * G_MININT16; - gdouble zero_p, zero_n; - gdouble a_p, b_p, c_p; - gdouble a_n, b_n, c_n; - - /* Nothing to do for us here if threshold equals 0.0 - * or ratio equals 1.0 */ - if (filter->threshold == 0.0 || filter->ratio == 1.0) - return; - - /* zero crossing of our function */ - zero_p = (thr_p * (filter->ratio - 1.0)) / (1.0 + filter->ratio); - zero_n = (thr_n * (filter->ratio - 1.0)) / (1.0 + filter->ratio); - - if (zero_p < 0.0) - zero_p = 0.0; - if (zero_n > 0.0) - zero_n = 0.0; - - /* shouldn't happen as this would only happen - * with threshold == 0.0 */ - g_assert (thr_p != 0); - g_assert (thr_n != 0); - - /* We build a 2n degree polynomial here for values between - * 0 and threshold or 0 and -threshold with: - * f(t) = t, f'(t) = 1, f(z) = 0, f'(z) = r - * z between 0 and t - * => - * a = (1 - r^2) / (4 * t) - * b = (1 + r^2) / 2 - * c = t * (1.0 - b - a*t) - * f(x) = ax^2 + bx + c */ - a_p = (1.0 - filter->ratio * filter->ratio) / (4.0 * thr_p); - b_p = (1.0 + filter->ratio * filter->ratio) / 2.0; - c_p = thr_p * (1.0 - b_p - a_p * thr_p); - a_n = (1.0 - filter->ratio * filter->ratio) / (4.0 * thr_n); - b_n = (1.0 + filter->ratio * filter->ratio) / 2.0; - c_n = thr_n * (1.0 - b_n - a_n * thr_n); - - for (; num_samples; num_samples--) { - val = *data; - - if (val < thr_p && val > zero_p) { - val = a_p * val * val + b_p * val + c_p; - } else if ((val <= zero_p && val > 0) || (val >= zero_n && val < 0)) { - val = 0; - } else if (val > thr_n && val < zero_n) { - val = a_n * val * val + b_n * val + c_n; - } - *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16); - } -} - -static void -gst_audio_dynamic_transform_soft_knee_expander_float (GstAudioDynamic * filter, - gfloat * data, guint num_samples) -{ - gdouble val; - gdouble threshold = filter->threshold; - gdouble zero; - gdouble a_p, b_p, c_p; - gdouble a_n, b_n, c_n; - - /* Nothing to do for us here if threshold equals 0.0 - * or ratio equals 1.0 */ - if (filter->threshold == 0.0 || filter->ratio == 1.0) - return; - - /* zero crossing of our function */ - zero = (threshold * (filter->ratio - 1.0)) / (1.0 + filter->ratio); - - if (zero < 0.0) - zero = 0.0; - - /* shouldn't happen as this only happens with - * threshold == 0.0 */ - g_assert (threshold != 0.0); - - /* We build a 2n degree polynomial here for values between - * 0 and threshold or 0 and -threshold with: - * f(t) = t, f'(t) = 1, f(z) = 0, f'(z) = r - * z between 0 and t - * => - * a = (1 - r^2) / (4 * t) - * b = (1 + r^2) / 2 - * c = t * (1.0 - b - a*t) - * f(x) = ax^2 + bx + c */ - a_p = (1.0 - filter->ratio * filter->ratio) / (4.0 * threshold); - b_p = (1.0 + filter->ratio * filter->ratio) / 2.0; - c_p = threshold * (1.0 - b_p - a_p * threshold); - a_n = (1.0 - filter->ratio * filter->ratio) / (-4.0 * threshold); - b_n = (1.0 + filter->ratio * filter->ratio) / 2.0; - c_n = -threshold * (1.0 - b_n + a_n * threshold); - - for (; num_samples; num_samples--) { - val = *data; - - if (val < threshold && val > zero) { - val = a_p * val * val + b_p * val + c_p; - } else if ((val <= zero && val > 0.0) || (val >= -zero && val < 0.0)) { - val = 0.0; - } else if (val > -threshold && val < -zero) { - val = a_n * val * val + b_n * val + c_n; - } - *data++ = (gfloat) val; - } -} - -/* GstBaseTransform vmethod implementations */ -static GstFlowReturn -gst_audio_dynamic_transform_ip (GstBaseTransform * base, GstBuffer * buf) -{ - GstAudioDynamic *filter = GST_AUDIO_DYNAMIC (base); - guint num_samples = - GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8); - - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) - gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (buf)); - - if (gst_base_transform_is_passthrough (base) || - G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP))) - return GST_FLOW_OK; - - filter->process (filter, GST_BUFFER_DATA (buf), num_samples); - - return GST_FLOW_OK; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiodynamic.h --- a/gst_plugins_good/gst/audiofx/audiodynamic.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2007 Sebastian Dröge - * - * 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. - */ - -#ifndef __GST_AUDIO_DYNAMIC_H__ -#define __GST_AUDIO_DYNAMIC_H__ - -#include -#include -#include -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_AUDIO_DYNAMIC (gst_audio_dynamic_get_type()) -#define GST_AUDIO_DYNAMIC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_DYNAMIC,GstAudioDynamic)) -#define GST_IS_AUDIO_DYNAMIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_DYNAMIC)) -#define GST_AUDIO_DYNAMIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_DYNAMIC,GstAudioDynamicClass)) -#define GST_IS_AUDIO_DYNAMIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_DYNAMIC)) -#define GST_AUDIO_DYNAMIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_DYNAMIC,GstAudioDynamicClass)) -typedef struct _GstAudioDynamic GstAudioDynamic; -typedef struct _GstAudioDynamicClass GstAudioDynamicClass; - -typedef void (*GstAudioDynamicProcessFunc) (GstAudioDynamic *, guint8 *, guint); - -struct _GstAudioDynamic -{ - GstAudioFilter audiofilter; - - gfloat degree; - - /* < private > */ - GstAudioDynamicProcessFunc process; - gint characteristics; - gint mode; - gfloat threshold; - gfloat ratio; -}; - -struct _GstAudioDynamicClass -{ - GstAudioFilterClass parent; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_audio_dynamic_get_type (void); - -G_END_DECLS - -#endif /* __GST_AUDIO_DYNAMIC_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audioecho.c --- a/gst_plugins_good/gst/audiofx/audioecho.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,391 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2009 Sebastian Dröge - * - * 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. - */ - -/** - * SECTION:element-audioecho - * @Since: 0.10.14 - * - * audioecho adds an echo or (simple) reverb effect to an audio stream. The echo - * delay, intensity and the percentage of feedback can be configured. - * - * For getting an echo effect you have to set the delay to a larger value, - * for example 200ms and more. Everything below will result in a simple - * reverb effect, which results in a slightly metallic sound. - * - * Use the max-delay property to set the maximum amount of delay that - * will be used. This can only be set before going to the PAUSED or PLAYING - * state and will be set to the current delay by default. - * - * - * Example launch line - * |[ - * gst-launch filesrc location="melo1.ogg" ! audioconvert ! audioecho delay=500000000 intensity=0.6 feedback=0.4 ! audioconvert ! autoaudiosink - * gst-launch filesrc location="melo1.ogg" ! decodebin ! audioconvert ! audioecho delay=50000000 intensity=0.6 feedback=0.4 ! audioconvert ! autoaudiosink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "audioecho.h" - -#define GST_CAT_DEFAULT gst_audio_echo_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -enum -{ - PROP_0, - PROP_DELAY, - PROP_MAX_DELAY, - PROP_INTENSITY, - PROP_FEEDBACK -}; - -#define ALLOWED_CAPS \ - "audio/x-raw-float," \ - " width=(int) { 32, 64 }, " \ - " endianness=(int)BYTE_ORDER," \ - " rate=(int)[1,MAX]," \ - " channels=(int)[1,MAX]" - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_audio_echo_debug, "audioecho", 0, "audioecho element"); - -GST_BOILERPLATE_FULL (GstAudioEcho, gst_audio_echo, GstAudioFilter, - GST_TYPE_AUDIO_FILTER, DEBUG_INIT); - -static void gst_audio_echo_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_audio_echo_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_audio_echo_finalize (GObject * object); - -static gboolean gst_audio_echo_setup (GstAudioFilter * self, - GstRingBufferSpec * format); -static gboolean gst_audio_echo_stop (GstBaseTransform * base); -static GstFlowReturn gst_audio_echo_transform_ip (GstBaseTransform * base, - GstBuffer * buf); - -static void gst_audio_echo_transform_float (GstAudioEcho * self, - gfloat * data, guint num_samples); -static void gst_audio_echo_transform_double (GstAudioEcho * self, - gdouble * data, guint num_samples); - -/* GObject vmethod implementations */ - -static void -gst_audio_echo_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstCaps *caps; - - gst_element_class_set_details_simple (element_class, "Audio echo", - "Filter/Effect/Audio", - "Adds an echo or reverb effect to an audio stream", - "Sebastian Dröge "); - - caps = gst_caps_from_string (ALLOWED_CAPS); - gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass), - caps); - gst_caps_unref (caps); -} - -static void -gst_audio_echo_class_init (GstAudioEchoClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstBaseTransformClass *basetransform_class = (GstBaseTransformClass *) klass; - GstAudioFilterClass *audioself_class = (GstAudioFilterClass *) klass; - - gobject_class->set_property = gst_audio_echo_set_property; - gobject_class->get_property = gst_audio_echo_get_property; - gobject_class->finalize = gst_audio_echo_finalize; - - g_object_class_install_property (gobject_class, PROP_DELAY, - g_param_spec_uint64 ("delay", "Delay", - "Delay of the echo in nanoseconds", 1, G_MAXUINT64, - 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS - | GST_PARAM_CONTROLLABLE)); - - g_object_class_install_property (gobject_class, PROP_MAX_DELAY, - g_param_spec_uint64 ("max-delay", "Maximum Delay", - "Maximum delay of the echo in nanoseconds" - " (can't be changed in PLAYING or PAUSED state)", - 1, G_MAXUINT64, 1, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE)); - - g_object_class_install_property (gobject_class, PROP_INTENSITY, - g_param_spec_float ("intensity", "Intensity", - "Intensity of the echo", 0.0, 1.0, - 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS - | GST_PARAM_CONTROLLABLE)); - - g_object_class_install_property (gobject_class, PROP_FEEDBACK, - g_param_spec_float ("feedback", "Feedback", - "Amount of feedback", 0.0, 1.0, - 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS - | GST_PARAM_CONTROLLABLE)); - - audioself_class->setup = GST_DEBUG_FUNCPTR (gst_audio_echo_setup); - basetransform_class->transform_ip = - GST_DEBUG_FUNCPTR (gst_audio_echo_transform_ip); - basetransform_class->stop = GST_DEBUG_FUNCPTR (gst_audio_echo_stop); -} - -static void -gst_audio_echo_init (GstAudioEcho * self, GstAudioEchoClass * klass) -{ - self->delay = 1; - self->max_delay = 1; - self->intensity = 0.0; - self->feedback = 0.0; - - gst_base_transform_set_in_place (GST_BASE_TRANSFORM (self), TRUE); -} - -static void -gst_audio_echo_finalize (GObject * object) -{ - GstAudioEcho *self = GST_AUDIO_ECHO (object); - - g_free (self->buffer); - self->buffer = NULL; - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_audio_echo_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAudioEcho *self = GST_AUDIO_ECHO (object); - - switch (prop_id) { - case PROP_DELAY:{ - guint64 max_delay, delay; - - GST_BASE_TRANSFORM_LOCK (self); - delay = g_value_get_uint64 (value); - max_delay = self->max_delay; - - if (delay > max_delay && GST_STATE (self) > GST_STATE_READY) { - GST_WARNING_OBJECT (self, "New delay (%" GST_TIME_FORMAT ") " - "is larger than maximum delay (%" GST_TIME_FORMAT ")", - GST_TIME_ARGS (delay), GST_TIME_ARGS (max_delay)); - self->delay = max_delay; - } else { - self->delay = delay; - self->max_delay = MAX (delay, max_delay); - } - GST_BASE_TRANSFORM_UNLOCK (self); - } - break; - case PROP_MAX_DELAY:{ - guint64 max_delay, delay; - - GST_BASE_TRANSFORM_LOCK (self); - max_delay = g_value_get_uint64 (value); - delay = self->delay; - - if (GST_STATE (self) > GST_STATE_READY) { - GST_ERROR_OBJECT (self, "Can't change maximum delay in" - " PLAYING or PAUSED state"); - } else { - self->delay = delay; - self->max_delay = max_delay; - } - GST_BASE_TRANSFORM_UNLOCK (self); - } - break; - case PROP_INTENSITY:{ - GST_BASE_TRANSFORM_LOCK (self); - self->intensity = g_value_get_float (value); - GST_BASE_TRANSFORM_UNLOCK (self); - } - break; - case PROP_FEEDBACK:{ - GST_BASE_TRANSFORM_LOCK (self); - self->feedback = g_value_get_float (value); - GST_BASE_TRANSFORM_UNLOCK (self); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_audio_echo_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAudioEcho *self = GST_AUDIO_ECHO (object); - - switch (prop_id) { - case PROP_DELAY: - GST_BASE_TRANSFORM_LOCK (self); - g_value_set_uint64 (value, self->delay); - GST_BASE_TRANSFORM_UNLOCK (self); - break; - case PROP_MAX_DELAY: - GST_BASE_TRANSFORM_LOCK (self); - g_value_set_uint64 (value, self->max_delay); - GST_BASE_TRANSFORM_UNLOCK (self); - break; - case PROP_INTENSITY: - GST_BASE_TRANSFORM_LOCK (self); - g_value_set_float (value, self->intensity); - GST_BASE_TRANSFORM_UNLOCK (self); - break; - case PROP_FEEDBACK: - GST_BASE_TRANSFORM_LOCK (self); - g_value_set_float (value, self->feedback); - GST_BASE_TRANSFORM_UNLOCK (self); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* GstAudioFilter vmethod implementations */ - -static gboolean -gst_audio_echo_setup (GstAudioFilter * base, GstRingBufferSpec * format) -{ - GstAudioEcho *self = GST_AUDIO_ECHO (base); - gboolean ret = TRUE; - - if (format->type == GST_BUFTYPE_FLOAT && format->width == 32) - self->process = (GstAudioEchoProcessFunc) - gst_audio_echo_transform_float; - else if (format->type == GST_BUFTYPE_FLOAT && format->width == 64) - self->process = (GstAudioEchoProcessFunc) - gst_audio_echo_transform_double; - else - ret = FALSE; - - g_free (self->buffer); - self->buffer = NULL; - self->buffer_pos = 0; - self->buffer_size = 0; - self->buffer_size_frames = 0; - - return ret; -} - -static gboolean -gst_audio_echo_stop (GstBaseTransform * base) -{ - GstAudioEcho *self = GST_AUDIO_ECHO (base); - - g_free (self->buffer); - self->buffer = NULL; - self->buffer_pos = 0; - self->buffer_size = 0; - self->buffer_size_frames = 0; - - return TRUE; -} - -#define TRANSFORM_FUNC(name, type) \ -static void \ -gst_audio_echo_transform_##name (GstAudioEcho * self, \ - type * data, guint num_samples) \ -{ \ - type *buffer = (type *) self->buffer; \ - guint channels = GST_AUDIO_FILTER (self)->format.channels; \ - guint rate = GST_AUDIO_FILTER (self)->format.rate; \ - guint i, j; \ - guint echo_index = self->buffer_size_frames - self->delay_frames; \ - gdouble echo_off = ((((gdouble) self->delay) * rate) / GST_SECOND) - self->delay_frames; \ - \ - if (echo_off < 0.0) \ - echo_off = 0.0; \ - \ - num_samples /= channels; \ - \ - for (i = 0; i < num_samples; i++) { \ - guint echo0_index = ((echo_index + self->buffer_pos) % self->buffer_size_frames) * channels; \ - guint echo1_index = ((echo_index + self->buffer_pos +1) % self->buffer_size_frames) * channels; \ - guint rbout_index = (self->buffer_pos % self->buffer_size_frames) * channels; \ - for (j = 0; j < channels; j++) { \ - gdouble in = data[i*channels + j]; \ - gdouble echo0 = buffer[echo0_index + j]; \ - gdouble echo1 = buffer[echo1_index + j]; \ - gdouble echo = echo0 + (echo1-echo0)*echo_off; \ - type out = in + self->intensity * echo; \ - \ - data[i*channels + j] = out; \ - \ - buffer[rbout_index + j] = in + self->feedback * echo; \ - } \ - self->buffer_pos = (self->buffer_pos + 1) % self->buffer_size_frames; \ - } \ -} - -TRANSFORM_FUNC (float, gfloat); -TRANSFORM_FUNC (double, gdouble); - -/* GstBaseTransform vmethod implementations */ -static GstFlowReturn -gst_audio_echo_transform_ip (GstBaseTransform * base, GstBuffer * buf) -{ - GstAudioEcho *self = GST_AUDIO_ECHO (base); - guint num_samples = - GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (self)->format.width / 8); - - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) - gst_object_sync_values (G_OBJECT (self), GST_BUFFER_TIMESTAMP (buf)); - - if (self->buffer == NULL) { - guint width, rate, channels; - - width = GST_AUDIO_FILTER (self)->format.width / 8; - rate = GST_AUDIO_FILTER (self)->format.rate; - channels = GST_AUDIO_FILTER (self)->format.channels; - - self->delay_frames = - MAX (gst_util_uint64_scale (self->delay, rate, GST_SECOND), 1); - self->buffer_size_frames = - MAX (gst_util_uint64_scale (self->max_delay, rate, GST_SECOND), 1); - - self->buffer_size = self->buffer_size_frames * width * channels; - self->buffer = g_try_malloc0 (self->buffer_size); - self->buffer_pos = 0; - - if (self->buffer == NULL) { - GST_ERROR_OBJECT (self, "Failed to allocate %u bytes", self->buffer_size); - return GST_FLOW_ERROR; - } - } - - self->process (self, GST_BUFFER_DATA (buf), num_samples); - - return GST_FLOW_OK; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audioecho.h --- a/gst_plugins_good/gst/audiofx/audioecho.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2009 Sebastian Dröge - * - * 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. - */ - -#ifndef __GST_AUDIO_ECHO_H__ -#define __GST_AUDIO_ECHO_H__ - -#include -#include -#include -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_AUDIO_ECHO (gst_audio_echo_get_type()) -#define GST_AUDIO_ECHO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_ECHO,GstAudioEcho)) -#define GST_IS_AUDIO_ECHO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_ECHO)) -#define GST_AUDIO_ECHO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_ECHO,GstAudioEchoClass)) -#define GST_IS_AUDIO_ECHO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_ECHO)) -#define GST_AUDIO_ECHO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_ECHO,GstAudioEchoClass)) -typedef struct _GstAudioEcho GstAudioEcho; -typedef struct _GstAudioEchoClass GstAudioEchoClass; - -typedef void (*GstAudioEchoProcessFunc) (GstAudioEcho *, guint8 *, guint); - -struct _GstAudioEcho -{ - GstAudioFilter audiofilter; - - guint64 delay; - guint64 max_delay; - gfloat intensity; - gfloat feedback; - - /* < private > */ - GstAudioEchoProcessFunc process; - guint delay_frames; - guint8 *buffer; - guint buffer_pos; - guint buffer_size; - guint buffer_size_frames; -}; - -struct _GstAudioEchoClass -{ - GstAudioFilterClass parent; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_audio_echo_get_type (void); - -G_END_DECLS - -#endif /* __GST_AUDIO_ECHO_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiofirfilter.c --- a/gst_plugins_good/gst/audiofx/audiofirfilter.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,269 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2009 Sebastian Dröge - * - * 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. - * - */ - -/** - * SECTION:element-audiofirfilter - * - * audiofirfilter implements a generic audio FIR filter. Before usage the - * "kernel" property has to be set to the filter kernel that should be - * used and the "latency" property has to be set to the latency (in samples) - * that is introduced by the filter kernel. Setting a latency of n samples - * will lead to the first n samples being dropped from the output and - * n samples added to the end. - * - * The filter kernel describes the impulse response of the filter. To - * calculate the frequency response of the filter you have to calculate - * the Fourier Transform of the impulse response. - * - * To change the filter kernel whenever the sampling rate changes the - * "rate-changed" signal can be used. This should be done for most - * FIR filters as they're depending on the sampling rate. - * - * - * Example application - * |[ - * - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "audiofirfilter.h" - -#define GST_CAT_DEFAULT gst_audio_fir_filter_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -enum -{ - SIGNAL_RATE_CHANGED, - LAST_SIGNAL -}; - -enum -{ - PROP_0, - PROP_KERNEL, - PROP_LATENCY -}; - -static guint gst_audio_fir_filter_signals[LAST_SIGNAL] = { 0, }; - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_audio_fir_filter_debug, "audiofirfilter", 0, \ - "Generic audio FIR filter plugin"); - -GST_BOILERPLATE_FULL (GstAudioFIRFilter, gst_audio_fir_filter, GstAudioFilter, - GST_TYPE_AUDIO_FX_BASE_FIR_FILTER, DEBUG_INIT); - -static void gst_audio_fir_filter_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_audio_fir_filter_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_audio_fir_filter_finalize (GObject * object); - -static gboolean gst_audio_fir_filter_setup (GstAudioFilter * base, - GstRingBufferSpec * format); - -/* Element class */ -static void -gst_audio_fir_filter_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details_simple (element_class, - "Audio FIR filter", "Filter/Effect/Audio", - "Generic audio FIR filter with custom filter kernel", - "Sebastian Dröge "); -} - -static void -gst_audio_fir_filter_class_init (GstAudioFIRFilterClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass; - - gobject_class->set_property = gst_audio_fir_filter_set_property; - gobject_class->get_property = gst_audio_fir_filter_get_property; - gobject_class->finalize = gst_audio_fir_filter_finalize; - - g_object_class_install_property (gobject_class, PROP_KERNEL, - g_param_spec_value_array ("kernel", "Filter Kernel", - "Filter kernel for the FIR filter", - g_param_spec_double ("Element", "Filter Kernel Element", - "Element of the filter kernel", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS), - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_LATENCY, - g_param_spec_uint64 ("latency", "Latecy", - "Filter latency in samples", - 0, G_MAXUINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fir_filter_setup); - - /** - * GstAudioFIRFilter::rate-changed: - * @filter: the filter on which the signal is emitted - * @rate: the new sampling rate - * - * Will be emitted when the sampling rate changes. The callbacks - * will be called from the streaming thread and processing will - * stop until the event is handled. - */ - gst_audio_fir_filter_signals[SIGNAL_RATE_CHANGED] = - g_signal_new ("rate-changed", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstAudioFIRFilterClass, rate_changed), - NULL, NULL, gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); -} - -static void -gst_audio_fir_filter_update_kernel (GstAudioFIRFilter * self, GValueArray * va) -{ - gdouble *kernel; - guint i; - - gst_audio_fx_base_fir_filter_push_residue (GST_AUDIO_FX_BASE_FIR_FILTER - (self)); - - if (va) { - if (self->kernel) - g_value_array_free (self->kernel); - - self->kernel = va; - } - - kernel = g_new (gdouble, self->kernel->n_values); - - for (i = 0; i < self->kernel->n_values; i++) { - GValue *v = g_value_array_get_nth (self->kernel, i); - kernel[i] = g_value_get_double (v); - } - - gst_audio_fx_base_fir_filter_set_kernel (GST_AUDIO_FX_BASE_FIR_FILTER (self), - kernel, self->kernel->n_values, self->latency); -} - -static void -gst_audio_fir_filter_init (GstAudioFIRFilter * self, - GstAudioFIRFilterClass * g_class) -{ - GValue v = { 0, }; - GValueArray *va; - - self->latency = 0; - va = g_value_array_new (1); - - g_value_init (&v, G_TYPE_DOUBLE); - g_value_set_double (&v, 1.0); - g_value_array_append (va, &v); - g_value_unset (&v); - gst_audio_fir_filter_update_kernel (self, va); - - self->lock = g_mutex_new (); -} - -/* GstAudioFilter vmethod implementations */ - -/* get notified of caps and plug in the correct process function */ -static gboolean -gst_audio_fir_filter_setup (GstAudioFilter * base, GstRingBufferSpec * format) -{ - GstAudioFIRFilter *self = GST_AUDIO_FIR_FILTER (base); - - if (self->rate != format->rate) { - g_signal_emit (G_OBJECT (self), - gst_audio_fir_filter_signals[SIGNAL_RATE_CHANGED], 0, format->rate); - self->rate = format->rate; - } - - return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, format); -} - -static void -gst_audio_fir_filter_finalize (GObject * object) -{ - GstAudioFIRFilter *self = GST_AUDIO_FIR_FILTER (object); - - g_mutex_free (self->lock); - self->lock = NULL; - - if (self->kernel) - g_value_array_free (self->kernel); - self->kernel = NULL; - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_audio_fir_filter_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAudioFIRFilter *self = GST_AUDIO_FIR_FILTER (object); - - g_return_if_fail (GST_IS_AUDIO_FIR_FILTER (self)); - - switch (prop_id) { - case PROP_KERNEL: - g_mutex_lock (self->lock); - gst_audio_fx_base_fir_filter_push_residue (GST_AUDIO_FX_BASE_FIR_FILTER - (self)); - - gst_audio_fir_filter_update_kernel (self, g_value_dup_boxed (value)); - g_mutex_unlock (self->lock); - break; - case PROP_LATENCY: - g_mutex_lock (self->lock); - self->latency = g_value_get_uint64 (value); - gst_audio_fir_filter_update_kernel (self, NULL); - g_mutex_unlock (self->lock); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_audio_fir_filter_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAudioFIRFilter *self = GST_AUDIO_FIR_FILTER (object); - - switch (prop_id) { - case PROP_KERNEL: - g_value_set_boxed (value, self->kernel); - break; - case PROP_LATENCY: - g_value_set_uint64 (value, self->latency); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiofirfilter.h --- a/gst_plugins_good/gst/audiofx/audiofirfilter.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2009 Sebastian Dröge - * - * 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. - * - */ - -#ifndef __GST_AUDIO_FIR_FILTER_H__ -#define __GST_AUDIO_FIR_FILTER_H__ - -#include -#include -#include - -#include "audiofxbasefirfilter.h" - -G_BEGIN_DECLS - -#define GST_TYPE_AUDIO_FIR_FILTER \ - (gst_audio_fir_filter_get_type()) -#define GST_AUDIO_FIR_FILTER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_FIR_FILTER,GstAudioFIRFilter)) -#define GST_AUDIO_FIR_FILTER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_FIR_FILTER,GstAudioFIRFilterClass)) -#define GST_IS_AUDIO_FIR_FILTER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_FIR_FILTER)) -#define GST_IS_AUDIO_FIR_FILTER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_FIR_FILTER)) - -typedef struct _GstAudioFIRFilter GstAudioFIRFilter; -typedef struct _GstAudioFIRFilterClass GstAudioFIRFilterClass; - -/** - * GstAudioFIRFilter: - * - * Opaque data structure. - */ -struct _GstAudioFIRFilter { - GstAudioFXBaseFIRFilter parent; - - GValueArray *kernel; - guint64 latency; - - /* < private > */ - GMutex *lock; - gint rate; -}; - -struct _GstAudioFIRFilterClass { - GstAudioFXBaseFIRFilterClass parent; - - void (*rate_changed) (GstElement * element, gint rate); -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_audio_fir_filter_get_type (void); - -G_END_DECLS - -#endif /* __GST_AUDIO_FIR_FILTER_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiofx.c --- a/gst_plugins_good/gst/audiofx/audiofx.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2006 Stefan Kost - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#include "audiopanorama.h" -#include "audioinvert.h" -#include "audiokaraoke.h" -#include "audioamplify.h" -#include "audiodynamic.h" -#include "audiocheblimit.h" -#include "audiochebband.h" -#include "audioiirfilter.h" -#include "audiowsincband.h" -#include "audiowsinclimit.h" -#include "audiofirfilter.h" -#include "audioecho.h" - -/* entry point to initialize the plug-in - * initialize the plug-in itself - * register the element factories and pad templates - * register the features - */ -static gboolean -plugin_init (GstPlugin * plugin) -{ - /* initialize gst controller library */ - gst_controller_init (NULL, NULL); - - return (gst_element_register (plugin, "audiopanorama", GST_RANK_NONE, - GST_TYPE_AUDIO_PANORAMA) && - gst_element_register (plugin, "audioinvert", GST_RANK_NONE, - GST_TYPE_AUDIO_INVERT) && - gst_element_register (plugin, "audiokaraoke", GST_RANK_NONE, - GST_TYPE_AUDIO_KARAOKE) && - gst_element_register (plugin, "audioamplify", GST_RANK_NONE, - GST_TYPE_AUDIO_AMPLIFY) && - gst_element_register (plugin, "audiodynamic", GST_RANK_NONE, - GST_TYPE_AUDIO_DYNAMIC) && - gst_element_register (plugin, "audiocheblimit", GST_RANK_NONE, - GST_TYPE_AUDIO_CHEB_LIMIT) && - gst_element_register (plugin, "audiochebband", GST_RANK_NONE, - GST_TYPE_AUDIO_CHEB_BAND) && - gst_element_register (plugin, "audioiirfilter", GST_RANK_NONE, - GST_TYPE_AUDIO_IIR_FILTER) && - gst_element_register (plugin, "audiowsinclimit", GST_RANK_NONE, - GST_TYPE_AUDIO_WSINC_LIMIT) && - gst_element_register (plugin, "audiowsincband", GST_RANK_NONE, - GST_TYPE_AUDIO_WSINC_BAND) && - gst_element_register (plugin, "audiofirfilter", GST_RANK_NONE, - GST_TYPE_AUDIO_FIR_FILTER) && - gst_element_register (plugin, "audioecho", GST_RANK_NONE, - GST_TYPE_AUDIO_ECHO)); -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "audiofx", - "Audio effects plugin", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) - - -EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC() -{ - return &gst_plugin_desc; -} - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiofxbasefirfilter.c --- a/gst_plugins_good/gst/audiofx/audiofxbasefirfilter.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,527 +0,0 @@ -/* -*- c-basic-offset: 2 -*- - * - * GStreamer - * Copyright (C) 1999-2001 Erik Walthinsen - * 2006 Dreamlab Technologies Ltd. - * 2007-2009 Sebastian Dröge - * - * 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. - * - * - * TODO: - Implement the convolution in place, probably only makes sense - * when using FFT convolution as currently the convolution itself - * is probably the bottleneck - * - Maybe allow cascading the filter to get a better stopband attenuation. - * Can be done by convolving a filter kernel with itself - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "audiofxbasefirfilter.h" - -#define GST_CAT_DEFAULT gst_audio_fx_base_fir_filter_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -#define ALLOWED_CAPS \ - "audio/x-raw-float, " \ - " width = (int) { 32, 64 }, " \ - " endianness = (int) BYTE_ORDER, " \ - " rate = (int) [ 1, MAX ], " \ - " channels = (int) [ 1, MAX ]" - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_audio_fx_base_fir_filter_debug, "audiofxbasefirfilter", 0, \ - "FIR filter base class"); - -GST_BOILERPLATE_FULL (GstAudioFXBaseFIRFilter, gst_audio_fx_base_fir_filter, - GstAudioFilter, GST_TYPE_AUDIO_FILTER, DEBUG_INIT); - -static GstFlowReturn gst_audio_fx_base_fir_filter_transform (GstBaseTransform * - base, GstBuffer * inbuf, GstBuffer * outbuf); -static gboolean gst_audio_fx_base_fir_filter_start (GstBaseTransform * base); -static gboolean gst_audio_fx_base_fir_filter_stop (GstBaseTransform * base); -static gboolean gst_audio_fx_base_fir_filter_event (GstBaseTransform * base, - GstEvent * event); -static gboolean gst_audio_fx_base_fir_filter_setup (GstAudioFilter * base, - GstRingBufferSpec * format); - -static gboolean gst_audio_fx_base_fir_filter_query (GstPad * pad, - GstQuery * query); -static const GstQueryType *gst_audio_fx_base_fir_filter_query_type (GstPad * - pad); - -/* Element class */ - -static void -gst_audio_fx_base_fir_filter_dispose (GObject * object) -{ - GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (object); - - if (self->residue) { - g_free (self->residue); - self->residue = NULL; - } - - if (self->kernel) { - g_free (self->kernel); - self->kernel = NULL; - } - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -gst_audio_fx_base_fir_filter_base_init (gpointer g_class) -{ - GstCaps *caps; - - caps = gst_caps_from_string (ALLOWED_CAPS); - gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (g_class), - caps); - gst_caps_unref (caps); -} - -static void -gst_audio_fx_base_fir_filter_class_init (GstAudioFXBaseFIRFilterClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass; - GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass; - - gobject_class->dispose = gst_audio_fx_base_fir_filter_dispose; - - trans_class->transform = - GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_transform); - trans_class->start = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_start); - trans_class->stop = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_stop); - trans_class->event = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_event); - filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fx_base_fir_filter_setup); -} - -static void -gst_audio_fx_base_fir_filter_init (GstAudioFXBaseFIRFilter * self, - GstAudioFXBaseFIRFilterClass * g_class) -{ - self->kernel = NULL; - self->residue = NULL; - - self->next_ts = GST_CLOCK_TIME_NONE; - self->next_off = GST_BUFFER_OFFSET_NONE; - - gst_pad_set_query_function (GST_BASE_TRANSFORM (self)->srcpad, - gst_audio_fx_base_fir_filter_query); - gst_pad_set_query_type_function (GST_BASE_TRANSFORM (self)->srcpad, - gst_audio_fx_base_fir_filter_query_type); -} - -#define DEFINE_PROCESS_FUNC(width,ctype) \ -static void \ -process_##width (GstAudioFXBaseFIRFilter * self, g##ctype * src, g##ctype * dst, guint input_samples) \ -{ \ - gint kernel_length = self->kernel_length; \ - gint i, j, k, l; \ - gint channels = GST_AUDIO_FILTER (self)->format.channels; \ - gint res_start; \ - \ - /* convolution */ \ - for (i = 0; i < input_samples; i++) { \ - dst[i] = 0.0; \ - k = i % channels; \ - l = i / channels; \ - for (j = 0; j < kernel_length; j++) \ - if (l < j) \ - dst[i] += \ - self->residue[(kernel_length + l - j) * channels + \ - k] * self->kernel[j]; \ - else \ - dst[i] += src[(l - j) * channels + k] * self->kernel[j]; \ - } \ - \ - /* copy the tail of the current input buffer to the residue, while \ - * keeping parts of the residue if the input buffer is smaller than \ - * the kernel length */ \ - if (input_samples < kernel_length * channels) \ - res_start = kernel_length * channels - input_samples; \ - else \ - res_start = 0; \ - \ - for (i = 0; i < res_start; i++) \ - self->residue[i] = self->residue[i + input_samples]; \ - for (i = res_start; i < kernel_length * channels; i++) \ - self->residue[i] = src[input_samples - kernel_length * channels + i]; \ - \ - self->residue_length += kernel_length * channels - res_start; \ - if (self->residue_length > kernel_length * channels) \ - self->residue_length = kernel_length * channels; \ -} - -DEFINE_PROCESS_FUNC (32, float); -DEFINE_PROCESS_FUNC (64, double); - -#undef DEFINE_PROCESS_FUNC - -void -gst_audio_fx_base_fir_filter_push_residue (GstAudioFXBaseFIRFilter * self) -{ - GstBuffer *outbuf; - GstFlowReturn res; - gint rate = GST_AUDIO_FILTER (self)->format.rate; - gint channels = GST_AUDIO_FILTER (self)->format.channels; - gint outsize, outsamples; - gint diffsize, diffsamples; - guint8 *in, *out; - - if (channels == 0 || rate == 0) { - self->residue_length = 0; - return; - } - - /* Calculate the number of samples and their memory size that - * should be pushed from the residue */ - outsamples = MIN (self->latency, self->residue_length / channels); - outsize = outsamples * channels * (GST_AUDIO_FILTER (self)->format.width / 8); - if (outsize == 0) { - self->residue_length = 0; - return; - } - - /* Process the difference between latency and residue_length samples - * to start at the actual data instead of starting at the zeros before - * when we only got one buffer smaller than latency */ - diffsamples = self->latency - self->residue_length / channels; - diffsize = - diffsamples * channels * (GST_AUDIO_FILTER (self)->format.width / 8); - if (diffsize > 0) { - in = g_new0 (guint8, diffsize); - out = g_new0 (guint8, diffsize); - self->process (self, in, out, diffsamples * channels); - g_free (in); - g_free (out); - } - - res = gst_pad_alloc_buffer (GST_BASE_TRANSFORM (self)->srcpad, - GST_BUFFER_OFFSET_NONE, outsize, - GST_PAD_CAPS (GST_BASE_TRANSFORM (self)->srcpad), &outbuf); - - if (G_UNLIKELY (res != GST_FLOW_OK)) { - GST_WARNING_OBJECT (self, "failed allocating buffer of %d bytes", outsize); - self->residue_length = 0; - return; - } - - /* Convolve the residue with zeros to get the actual remaining data */ - in = g_new0 (guint8, outsize); - self->process (self, in, GST_BUFFER_DATA (outbuf), outsamples * channels); - g_free (in); - - /* Set timestamp, offset, etc from the values we - * saved when processing the regular buffers */ - if (GST_CLOCK_TIME_IS_VALID (self->next_ts)) - GST_BUFFER_TIMESTAMP (outbuf) = self->next_ts; - else - GST_BUFFER_TIMESTAMP (outbuf) = 0; - GST_BUFFER_DURATION (outbuf) = - gst_util_uint64_scale (outsamples, GST_SECOND, rate); - self->next_ts += gst_util_uint64_scale (outsamples, GST_SECOND, rate); - - if (self->next_off != GST_BUFFER_OFFSET_NONE) { - GST_BUFFER_OFFSET (outbuf) = self->next_off; - GST_BUFFER_OFFSET_END (outbuf) = self->next_off + outsamples; - self->next_off = GST_BUFFER_OFFSET_END (outbuf); - } - - GST_DEBUG_OBJECT (self, "Pushing residue buffer of size %d with timestamp: %" - GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %lld," - " offset_end: %lld, nsamples: %d", GST_BUFFER_SIZE (outbuf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf), - GST_BUFFER_OFFSET_END (outbuf), outsamples); - - res = gst_pad_push (GST_BASE_TRANSFORM (self)->srcpad, outbuf); - - if (G_UNLIKELY (res != GST_FLOW_OK)) { - GST_WARNING_OBJECT (self, "failed to push residue"); - } - - self->residue_length = 0; -} - -/* GstAudioFilter vmethod implementations */ - -/* get notified of caps and plug in the correct process function */ -static gboolean -gst_audio_fx_base_fir_filter_setup (GstAudioFilter * base, - GstRingBufferSpec * format) -{ - GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base); - gboolean ret = TRUE; - - if (self->residue) { - gst_audio_fx_base_fir_filter_push_residue (self); - g_free (self->residue); - self->residue = NULL; - self->residue_length = 0; - self->next_ts = GST_CLOCK_TIME_NONE; - self->next_off = GST_BUFFER_OFFSET_NONE; - } - - if (format->width == 32) - self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_32; - else if (format->width == 64) - self->process = (GstAudioFXBaseFIRFilterProcessFunc) process_64; - else - ret = FALSE; - - return TRUE; -} - -/* GstBaseTransform vmethod implementations */ - -static GstFlowReturn -gst_audio_fx_base_fir_filter_transform (GstBaseTransform * base, - GstBuffer * inbuf, GstBuffer * outbuf) -{ - GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base); - GstClockTime timestamp; - gint channels = GST_AUDIO_FILTER (self)->format.channels; - gint rate = GST_AUDIO_FILTER (self)->format.rate; - gint input_samples = - GST_BUFFER_SIZE (outbuf) / (GST_AUDIO_FILTER (self)->format.width / 8); - gint output_samples = input_samples; - gint diff = 0; - - timestamp = GST_BUFFER_TIMESTAMP (outbuf); - if (!GST_CLOCK_TIME_IS_VALID (timestamp)) { - GST_ERROR_OBJECT (self, "Invalid timestamp"); - return GST_FLOW_ERROR; - } - - gst_object_sync_values (G_OBJECT (self), timestamp); - - g_return_val_if_fail (self->kernel != NULL, GST_FLOW_ERROR); - g_return_val_if_fail (channels != 0, GST_FLOW_ERROR); - - if (!self->residue) - self->residue = g_new0 (gdouble, self->kernel_length * channels); - - /* Reset the residue if already existing on discont buffers */ - if (GST_BUFFER_IS_DISCONT (inbuf) || (GST_CLOCK_TIME_IS_VALID (self->next_ts) - && timestamp - gst_util_uint64_scale (MIN (self->latency, - self->residue_length / channels), GST_SECOND, - rate) - self->next_ts > 5 * GST_MSECOND)) { - GST_DEBUG_OBJECT (self, "Discontinuity detected - flushing"); - if (GST_CLOCK_TIME_IS_VALID (self->next_ts)) - gst_audio_fx_base_fir_filter_push_residue (self); - self->residue_length = 0; - self->next_ts = timestamp; - self->next_off = GST_BUFFER_OFFSET (inbuf); - } else if (!GST_CLOCK_TIME_IS_VALID (self->next_ts)) { - self->next_ts = timestamp; - self->next_off = GST_BUFFER_OFFSET (inbuf); - } - - /* Calculate the number of samples we can push out now without outputting - * latency zeros in the beginning */ - diff = self->latency * channels - self->residue_length; - if (diff > 0) - output_samples -= diff; - - self->process (self, GST_BUFFER_DATA (inbuf), GST_BUFFER_DATA (outbuf), - input_samples); - - if (output_samples <= 0) { - return GST_BASE_TRANSFORM_FLOW_DROPPED; - } - - GST_BUFFER_TIMESTAMP (outbuf) = self->next_ts; - GST_BUFFER_DURATION (outbuf) = - gst_util_uint64_scale (output_samples / channels, GST_SECOND, rate); - GST_BUFFER_OFFSET (outbuf) = self->next_off; - if (GST_BUFFER_OFFSET_IS_VALID (outbuf)) - GST_BUFFER_OFFSET_END (outbuf) = self->next_off + output_samples / channels; - else - GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_NONE; - - if (output_samples < input_samples) { - GST_BUFFER_DATA (outbuf) += - diff * (GST_AUDIO_FILTER (self)->format.width / 8); - GST_BUFFER_SIZE (outbuf) -= - diff * (GST_AUDIO_FILTER (self)->format.width / 8); - } - - self->next_ts += GST_BUFFER_DURATION (outbuf); - self->next_off = GST_BUFFER_OFFSET_END (outbuf); - - GST_DEBUG_OBJECT (self, "Pushing buffer of size %d with timestamp: %" - GST_TIME_FORMAT ", duration: %" GST_TIME_FORMAT ", offset: %lld," - " offset_end: %lld, nsamples: %d", GST_BUFFER_SIZE (outbuf), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf), - GST_BUFFER_OFFSET_END (outbuf), output_samples / channels); - - return GST_FLOW_OK; -} - -static gboolean -gst_audio_fx_base_fir_filter_start (GstBaseTransform * base) -{ - GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base); - - self->residue_length = 0; - self->next_ts = GST_CLOCK_TIME_NONE; - self->next_off = GST_BUFFER_OFFSET_NONE; - - return TRUE; -} - -static gboolean -gst_audio_fx_base_fir_filter_stop (GstBaseTransform * base) -{ - GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base); - - g_free (self->residue); - self->residue = NULL; - - return TRUE; -} - -static gboolean -gst_audio_fx_base_fir_filter_query (GstPad * pad, GstQuery * query) -{ - GstAudioFXBaseFIRFilter *self = - GST_AUDIO_FX_BASE_FIR_FILTER (gst_pad_get_parent (pad)); - gboolean res = TRUE; - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_LATENCY: - { - GstClockTime min, max; - gboolean live; - guint64 latency; - GstPad *peer; - gint rate = GST_AUDIO_FILTER (self)->format.rate; - - if (rate == 0) { - res = FALSE; - } else if ((peer = gst_pad_get_peer (GST_BASE_TRANSFORM (self)->sinkpad))) { - if ((res = gst_pad_query (peer, query))) { - gst_query_parse_latency (query, &live, &min, &max); - - GST_DEBUG_OBJECT (self, "Peer latency: min %" - GST_TIME_FORMAT " max %" GST_TIME_FORMAT, - GST_TIME_ARGS (min), GST_TIME_ARGS (max)); - - /* add our own latency */ - latency = gst_util_uint64_scale (self->latency, GST_SECOND, rate); - - GST_DEBUG_OBJECT (self, "Our latency: %" - GST_TIME_FORMAT, GST_TIME_ARGS (latency)); - - min += latency; - if (max != GST_CLOCK_TIME_NONE) - max += latency; - - GST_DEBUG_OBJECT (self, "Calculated total latency : min %" - GST_TIME_FORMAT " max %" GST_TIME_FORMAT, - GST_TIME_ARGS (min), GST_TIME_ARGS (max)); - - gst_query_set_latency (query, live, min, max); - } - gst_object_unref (peer); - } - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } - gst_object_unref (self); - return res; -} - -static const GstQueryType * -gst_audio_fx_base_fir_filter_query_type (GstPad * pad) -{ - static const GstQueryType types[] = { - GST_QUERY_LATENCY, - 0 - }; - - return types; -} - -static gboolean -gst_audio_fx_base_fir_filter_event (GstBaseTransform * base, GstEvent * event) -{ - GstAudioFXBaseFIRFilter *self = GST_AUDIO_FX_BASE_FIR_FILTER (base); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - gst_audio_fx_base_fir_filter_push_residue (self); - self->next_ts = GST_CLOCK_TIME_NONE; - self->next_off = GST_BUFFER_OFFSET_NONE; - break; - default: - break; - } - - return GST_BASE_TRANSFORM_CLASS (parent_class)->event (base, event); -} - -void -gst_audio_fx_base_fir_filter_set_kernel (GstAudioFXBaseFIRFilter * self, - gdouble * kernel, guint kernel_length, guint64 latency) -{ - g_return_if_fail (kernel != NULL); - g_return_if_fail (self != NULL); - - GST_BASE_TRANSFORM_LOCK (self); - if (self->residue) { - gst_audio_fx_base_fir_filter_push_residue (self); - self->next_ts = GST_CLOCK_TIME_NONE; - self->next_off = GST_BUFFER_OFFSET_NONE; - self->residue_length = 0; - } - - g_free (self->kernel); - g_free (self->residue); - - self->kernel = kernel; - self->kernel_length = kernel_length; - - if (GST_AUDIO_FILTER (self)->format.channels) { - self->residue = - g_new0 (gdouble, - kernel_length * GST_AUDIO_FILTER (self)->format.channels); - self->residue_length = 0; - } - - if (self->latency != latency) { - self->latency = latency; - gst_element_post_message (GST_ELEMENT (self), - gst_message_new_latency (GST_OBJECT (self))); - } - - GST_BASE_TRANSFORM_UNLOCK (self); -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiofxbasefirfilter.h --- a/gst_plugins_good/gst/audiofx/audiofxbasefirfilter.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* -*- c-basic-offset: 2 -*- - * - * GStreamer - * Copyright (C) 1999-2001 Erik Walthinsen - * 2006 Dreamlab Technologies Ltd. - * 2009 Sebastian Dröge - * - * 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. - * - */ - -#ifndef __GST_AUDIO_FX_BASE_FIR_FILTER_H__ -#define __GST_AUDIO_FX_BASE_FIR_FILTER_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_AUDIO_FX_BASE_FIR_FILTER \ - (gst_audio_fx_base_fir_filter_get_type()) -#define GST_AUDIO_FX_BASE_FIR_FILTER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_FX_BASE_FIR_FILTER,GstAudioFXBaseFIRFilter)) -#define GST_AUDIO_FX_BASE_FIR_FILTER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_FX_BASE_FIR_FILTER,GstAudioFXBaseFIRFilterClass)) -#define GST_IS_AUDIO_FX_BASE_FIR_FILTER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_FX_BASE_FIR_FILTER)) -#define GST_IS_AUDIO_FX_BASE_FIR_FILTER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_FX_BASE_FIR_FILTER)) - -typedef struct _GstAudioFXBaseFIRFilter GstAudioFXBaseFIRFilter; -typedef struct _GstAudioFXBaseFIRFilterClass GstAudioFXBaseFIRFilterClass; - -typedef void (*GstAudioFXBaseFIRFilterProcessFunc) (GstAudioFXBaseFIRFilter *, guint8 *, guint8 *, guint); - -/** - * GstAudioFXBaseFIRFilter: - * - * Opaque data structure. - */ -struct _GstAudioFXBaseFIRFilter { - GstAudioFilter element; - - /* < private > */ - GstAudioFXBaseFIRFilterProcessFunc process; - - gdouble *kernel; /* filter kernel */ - guint kernel_length; /* length of the filter kernel */ - gdouble *residue; /* buffer for left-over samples from previous buffer */ - guint residue_length; - - guint64 latency; - - GstClockTime next_ts; - guint64 next_off; -}; - -struct _GstAudioFXBaseFIRFilterClass { - GstAudioFilterClass parent_class; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_audio_fx_base_fir_filter_get_type (void); -void gst_audio_fx_base_fir_filter_set_kernel (GstAudioFXBaseFIRFilter *filter, gdouble *kernel, guint kernel_length, guint64 latency); -void gst_audio_fx_base_fir_filter_push_residue (GstAudioFXBaseFIRFilter *filter); - -G_END_DECLS - -#endif /* __GST_AUDIO_FX_BASE_FIR_FILTER_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiofxbaseiirfilter.c --- a/gst_plugins_good/gst/audiofx/audiofxbaseiirfilter.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,396 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2007-2009 Sebastian Dröge - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include - -#include "audiofxbaseiirfilter.h" - -#define GST_CAT_DEFAULT gst_audio_fx_base_iir_filter_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -#define ALLOWED_CAPS \ - "audio/x-raw-float," \ - " width = (int) { 32, 64 }, " \ - " endianness = (int) BYTE_ORDER," \ - " rate = (int) [ 1, MAX ]," \ - " channels = (int) [ 1, MAX ]" - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_audio_fx_base_iir_filter_debug, "audiofxbaseiirfilter", 0, "Audio IIR Filter Base Class"); - -GST_BOILERPLATE_FULL (GstAudioFXBaseIIRFilter, - gst_audio_fx_base_iir_filter, GstAudioFilter, GST_TYPE_AUDIO_FILTER, - DEBUG_INIT); - -static gboolean gst_audio_fx_base_iir_filter_setup (GstAudioFilter * filter, - GstRingBufferSpec * format); -static GstFlowReturn -gst_audio_fx_base_iir_filter_transform_ip (GstBaseTransform * base, - GstBuffer * buf); -static gboolean gst_audio_fx_base_iir_filter_stop (GstBaseTransform * base); - -static void process_64 (GstAudioFXBaseIIRFilter * filter, - gdouble * data, guint num_samples); -static void process_32 (GstAudioFXBaseIIRFilter * filter, - gfloat * data, guint num_samples); - -/* GObject vmethod implementations */ - -static void -gst_audio_fx_base_iir_filter_base_init (gpointer klass) -{ - GstCaps *caps; - - caps = gst_caps_from_string (ALLOWED_CAPS); - gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass), - caps); - gst_caps_unref (caps); -} - -static void -gst_audio_fx_base_iir_filter_dispose (GObject * object) -{ - GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (object); - - if (filter->a) { - g_free (filter->a); - filter->a = NULL; - } - - if (filter->b) { - g_free (filter->b); - filter->b = NULL; - } - - if (filter->channels) { - GstAudioFXBaseIIRFilterChannelCtx *ctx; - guint i; - - for (i = 0; i < filter->nchannels; i++) { - ctx = &filter->channels[i]; - g_free (ctx->x); - g_free (ctx->y); - } - - g_free (filter->channels); - filter->channels = NULL; - } - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -gst_audio_fx_base_iir_filter_class_init (GstAudioFXBaseIIRFilterClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass; - GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass; - - gobject_class->dispose = gst_audio_fx_base_iir_filter_dispose; - - filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_setup); - - trans_class->transform_ip = - GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_transform_ip); - trans_class->stop = GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_stop); -} - -static void -gst_audio_fx_base_iir_filter_init (GstAudioFXBaseIIRFilter * filter, - GstAudioFXBaseIIRFilterClass * klass) -{ - gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE); - - filter->a = NULL; - filter->na = 0; - filter->b = NULL; - filter->nb = 0; - filter->channels = NULL; - filter->nchannels = 0; -} - -/* Evaluate the transfer function that corresponds to the IIR - * coefficients at zr + zi*I and return the magnitude */ -gdouble -gst_audio_fx_base_iir_filter_calculate_gain (gdouble * a, guint na, gdouble * b, - guint nb, gdouble zr, gdouble zi) -{ - gdouble sum_ar, sum_ai; - gdouble sum_br, sum_bi; - gdouble gain_r, gain_i; - - gdouble sum_r_old; - gdouble sum_i_old; - - gint i; - - sum_ar = 0.0; - sum_ai = 0.0; - for (i = na - 1; i >= 0; i--) { - sum_r_old = sum_ar; - sum_i_old = sum_ai; - - sum_ar = (sum_r_old * zr - sum_i_old * zi) + a[i]; - sum_ai = (sum_r_old * zi + sum_i_old * zr) + 0.0; - } - - sum_br = 0.0; - sum_bi = 0.0; - for (i = nb - 1; i >= 0; i--) { - sum_r_old = sum_br; - sum_i_old = sum_bi; - - sum_br = (sum_r_old * zr - sum_i_old * zi) - b[i]; - sum_bi = (sum_r_old * zi + sum_i_old * zr) - 0.0; - } - sum_br += 1.0; - sum_bi += 0.0; - - gain_r = - (sum_ar * sum_br + sum_ai * sum_bi) / (sum_br * sum_br + sum_bi * sum_bi); - gain_i = - (sum_ai * sum_br - sum_ar * sum_bi) / (sum_br * sum_br + sum_bi * sum_bi); - - return (sqrt (gain_r * gain_r + gain_i * gain_i)); -} - -void -gst_audio_fx_base_iir_filter_set_coefficients (GstAudioFXBaseIIRFilter * filter, - gdouble * a, guint na, gdouble * b, guint nb) -{ - guint i; - - g_return_if_fail (GST_IS_AUDIO_FX_BASE_IIR_FILTER (filter)); - - GST_BASE_TRANSFORM_LOCK (filter); - - g_free (filter->a); - g_free (filter->b); - - filter->a = filter->b = NULL; - - if (filter->channels) { - GstAudioFXBaseIIRFilterChannelCtx *ctx; - gboolean free = (na != filter->na || nb != filter->nb); - - for (i = 0; i < filter->nchannels; i++) { - ctx = &filter->channels[i]; - - if (free) - g_free (ctx->x); - else - memset (ctx->x, 0, filter->na * sizeof (gdouble)); - - if (free) - g_free (ctx->y); - else - memset (ctx->y, 0, filter->nb * sizeof (gdouble)); - } - - g_free (filter->channels); - filter->channels = NULL; - } - - filter->na = na; - filter->nb = nb; - - filter->a = a; - filter->b = b; - - if (filter->nchannels && !filter->channels) { - GstAudioFXBaseIIRFilterChannelCtx *ctx; - - filter->channels = - g_new0 (GstAudioFXBaseIIRFilterChannelCtx, filter->nchannels); - for (i = 0; i < filter->nchannels; i++) { - ctx = &filter->channels[i]; - - ctx->x = g_new0 (gdouble, filter->na); - ctx->y = g_new0 (gdouble, filter->nb); - } - } - - GST_BASE_TRANSFORM_UNLOCK (filter); -} - -/* GstAudioFilter vmethod implementations */ - -static gboolean -gst_audio_fx_base_iir_filter_setup (GstAudioFilter * base, - GstRingBufferSpec * format) -{ - GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base); - gboolean ret = TRUE; - - if (format->width == 32) - filter->process = (GstAudioFXBaseIIRFilterProcessFunc) - process_32; - else if (format->width == 64) - filter->process = (GstAudioFXBaseIIRFilterProcessFunc) - process_64; - else - ret = FALSE; - - if (format->channels != filter->nchannels) { - guint i; - GstAudioFXBaseIIRFilterChannelCtx *ctx; - - if (filter->channels) { - - for (i = 0; i < filter->nchannels; i++) { - ctx = &filter->channels[i]; - - g_free (ctx->x); - g_free (ctx->y); - } - - g_free (filter->channels); - filter->channels = NULL; - } - - filter->nchannels = format->channels; - - filter->channels = - g_new0 (GstAudioFXBaseIIRFilterChannelCtx, filter->nchannels); - for (i = 0; i < filter->nchannels; i++) { - ctx = &filter->channels[i]; - - ctx->x = g_new0 (gdouble, filter->na); - ctx->y = g_new0 (gdouble, filter->nb); - } - } - - return ret; -} - -static inline gdouble -process (GstAudioFXBaseIIRFilter * filter, - GstAudioFXBaseIIRFilterChannelCtx * ctx, gdouble x0) -{ - gdouble val = filter->a[0] * x0; - gint i, j; - - for (i = 1, j = ctx->x_pos; i < filter->na; i++) { - val += filter->a[i] * ctx->x[j]; - j--; - if (j < 0) - j = filter->na - 1; - } - - for (i = 1, j = ctx->y_pos; i < filter->nb; i++) { - val += filter->b[i] * ctx->y[j]; - j--; - if (j < 0) - j = filter->nb - 1; - } - - if (ctx->x) { - ctx->x_pos++; - if (ctx->x_pos >= filter->na) - ctx->x_pos = 0; - ctx->x[ctx->x_pos] = x0; - } - if (ctx->y) { - ctx->y_pos++; - if (ctx->y_pos >= filter->nb) - ctx->y_pos = 0; - - ctx->y[ctx->y_pos] = val; - } - - return val; -} - -#define DEFINE_PROCESS_FUNC(width,ctype) \ -static void \ -process_##width (GstAudioFXBaseIIRFilter * filter, \ - g##ctype * data, guint num_samples) \ -{ \ - gint i, j, channels = GST_AUDIO_FILTER (filter)->format.channels; \ - gdouble val; \ - \ - for (i = 0; i < num_samples / channels; i++) { \ - for (j = 0; j < channels; j++) { \ - val = process (filter, &filter->channels[j], *data); \ - *data++ = val; \ - } \ - } \ -} - -DEFINE_PROCESS_FUNC (32, float); -DEFINE_PROCESS_FUNC (64, double); - -#undef DEFINE_PROCESS_FUNC - -/* GstBaseTransform vmethod implementations */ -static GstFlowReturn -gst_audio_fx_base_iir_filter_transform_ip (GstBaseTransform * base, - GstBuffer * buf) -{ - GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base); - guint num_samples = - GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8); - - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) - gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (buf)); - - if (gst_base_transform_is_passthrough (base)) - return GST_FLOW_OK; - - g_return_val_if_fail (filter->a != NULL, GST_FLOW_ERROR); - - filter->process (filter, GST_BUFFER_DATA (buf), num_samples); - - return GST_FLOW_OK; -} - - -static gboolean -gst_audio_fx_base_iir_filter_stop (GstBaseTransform * base) -{ - GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base); - guint channels = GST_AUDIO_FILTER (filter)->format.channels; - GstAudioFXBaseIIRFilterChannelCtx *ctx; - guint i; - - /* Reset the history of input and output values if - * already existing */ - if (channels && filter->channels) { - for (i = 0; i < channels; i++) { - ctx = &filter->channels[i]; - g_free (ctx->x); - g_free (ctx->y); - } - g_free (filter->channels); - } - filter->channels = NULL; - - return TRUE; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiofxbaseiirfilter.h --- a/gst_plugins_good/gst/audiofx/audiofxbaseiirfilter.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2007-2009 Sebastian Dröge - * - * 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. - */ - -#ifndef __GST_AUDIO_FX_BASE_IIR_FILTER_H__ -#define __GST_AUDIO_FX_BASE_IIR_FILTER_H__ - -#include -#include -#include -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_AUDIO_FX_BASE_IIR_FILTER (gst_audio_fx_base_iir_filter_get_type()) -#define GST_AUDIO_FX_BASE_IIR_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_FX_BASE_IIR_FILTER,GstAudioFXBaseIIRFilter)) -#define GST_IS_AUDIO_FX_BASE_IIR_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_FX_BASE_IIR_FILTER)) -#define GST_AUDIO_FX_BASE_IIR_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_FX_BASE_IIR_FILTER,GstAudioFXBaseIIRFilterClass)) -#define GST_IS_AUDIO_FX_BASE_IIR_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_FX_BASE_IIR_FILTER)) -#define GST_AUDIO_FX_BASE_IIR_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_FX_BASE_IIR_FILTER,GstAudioFXBaseIIRFilterClass)) -typedef struct _GstAudioFXBaseIIRFilter GstAudioFXBaseIIRFilter; -typedef struct _GstAudioFXBaseIIRFilterClass GstAudioFXBaseIIRFilterClass; - -typedef void (*GstAudioFXBaseIIRFilterProcessFunc) (GstAudioFXBaseIIRFilter *, guint8 *, guint); - -typedef struct -{ - gdouble *x; - gint x_pos; - gdouble *y; - gint y_pos; -} GstAudioFXBaseIIRFilterChannelCtx; - -struct _GstAudioFXBaseIIRFilter -{ - GstAudioFilter audiofilter; - - /* < private > */ - GstAudioFXBaseIIRFilterProcessFunc process; - - gboolean have_coeffs; - gdouble *a; - guint na; - gdouble *b; - guint nb; - GstAudioFXBaseIIRFilterChannelCtx *channels; - guint nchannels; -}; - -struct _GstAudioFXBaseIIRFilterClass -{ - GstAudioFilterClass parent; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_audio_fx_base_iir_filter_get_type (void); -void gst_audio_fx_base_iir_filter_set_coefficients (GstAudioFXBaseIIRFilter *filter, gdouble *a, guint na, gdouble *b, guint nb); -gdouble gst_audio_fx_base_iir_filter_calculate_gain (gdouble *a, guint na, gdouble *b, guint nb, gdouble zr, gdouble zi); - -G_END_DECLS - -#endif /* __GST_AUDIO_FX_BASE_IIR_FILTER_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audioiirfilter.c --- a/gst_plugins_good/gst/audiofx/audioiirfilter.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,287 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2009 Sebastian Dröge - * - * 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. - * - */ - -/** - * SECTION:element-audioiirfilter - * - * audioiirfilter implements a generic audio IIR filter. Before usage the - * "a" and "b" properties have to be set to the filter coefficients that - * should be used. - * - * The filter coefficients describe the numerator and denominator of the - * transfer function. - * - * To change the filter coefficients whenever the sampling rate changes the - * "rate-changed" signal can be used. This should be done for most - * IIR filters as they're depending on the sampling rate. - * - * - * Example application - * |[ - * - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "audioiirfilter.h" - -#define GST_CAT_DEFAULT gst_audio_iir_filter_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -enum -{ - SIGNAL_RATE_CHANGED, - LAST_SIGNAL -}; - -enum -{ - PROP_0, - PROP_A, - PROP_B -}; - -static guint gst_audio_iir_filter_signals[LAST_SIGNAL] = { 0, }; - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_audio_iir_filter_debug, "audioiirfilter", 0, \ - "Generic audio IIR filter plugin"); - -GST_BOILERPLATE_FULL (GstAudioIIRFilter, gst_audio_iir_filter, GstAudioFilter, - GST_TYPE_AUDIO_FX_BASE_IIR_FILTER, DEBUG_INIT); - -static void gst_audio_iir_filter_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_audio_iir_filter_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_audio_iir_filter_finalize (GObject * object); - -static gboolean gst_audio_iir_filter_setup (GstAudioFilter * base, - GstRingBufferSpec * format); - -/* Element class */ -static void -gst_audio_iir_filter_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details_simple (element_class, - "Audio IIR filter", "Filter/Effect/Audio", - "Generic audio IIR filter with custom filter kernel", - "Sebastian Dröge "); -} - -static void -gst_audio_iir_filter_class_init (GstAudioIIRFilterClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass; - - gobject_class->set_property = gst_audio_iir_filter_set_property; - gobject_class->get_property = gst_audio_iir_filter_get_property; - gobject_class->finalize = gst_audio_iir_filter_finalize; - - g_object_class_install_property (gobject_class, PROP_A, - g_param_spec_value_array ("a", "A", - "Filter coefficients (numerator of transfer function)", - g_param_spec_double ("Coefficient", "Filter Coefficient", - "Filter coefficient", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS), - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_B, - g_param_spec_value_array ("b", "B", - "Filter coefficients (denominator of transfer function)", - g_param_spec_double ("Coefficient", "Filter Coefficient", - "Filter coefficient", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS), - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - - filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_iir_filter_setup); - - /** - * GstAudioIIRFilter::rate-changed: - * @filter: the filter on which the signal is emitted - * @rate: the new sampling rate - * - * Will be emitted when the sampling rate changes. The callbacks - * will be called from the streaming thread and processing will - * stop until the event is handled. - */ - gst_audio_iir_filter_signals[SIGNAL_RATE_CHANGED] = - g_signal_new ("rate-changed", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstAudioIIRFilterClass, rate_changed), - NULL, NULL, gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); -} - -static void -gst_audio_iir_filter_update_coefficients (GstAudioIIRFilter * self, - GValueArray * va, GValueArray * vb) -{ - gdouble *a = NULL, *b = NULL; - guint i; - - if (va) { - if (self->a) - g_value_array_free (self->a); - - self->a = va; - } - if (vb) { - if (self->b) - g_value_array_free (self->b); - - self->b = vb; - } - - if (self->a && self->a->n_values > 0) - a = g_new (gdouble, self->a->n_values); - if (self->b && self->b->n_values > 0) - b = g_new (gdouble, self->b->n_values); - - if (self->a) { - for (i = 0; i < self->a->n_values; i++) { - GValue *v = g_value_array_get_nth (self->a, i); - a[i] = g_value_get_double (v); - } - } - - if (self->b) { - for (i = 0; i < self->b->n_values; i++) { - GValue *v = g_value_array_get_nth (self->b, i); - b[i] = g_value_get_double (v); - } - } - - gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER - (self), a, (self->a) ? self->a->n_values : 0, b, - (self->b) ? self->b->n_values : 0); -} - -static void -gst_audio_iir_filter_init (GstAudioIIRFilter * self, - GstAudioIIRFilterClass * g_class) -{ - GValue v = { 0, }; - GValueArray *a, *b; - - a = g_value_array_new (1); - - g_value_init (&v, G_TYPE_DOUBLE); - g_value_set_double (&v, 1.0); - g_value_array_append (a, &v); - g_value_unset (&v); - - b = NULL; - gst_audio_iir_filter_update_coefficients (self, a, b); - - self->lock = g_mutex_new (); -} - -/* GstAudioFilter vmethod implementations */ - -/* get notified of caps and plug in the correct process function */ -static gboolean -gst_audio_iir_filter_setup (GstAudioFilter * base, GstRingBufferSpec * format) -{ - GstAudioIIRFilter *self = GST_AUDIO_IIR_FILTER (base); - - if (self->rate != format->rate) { - g_signal_emit (G_OBJECT (self), - gst_audio_iir_filter_signals[SIGNAL_RATE_CHANGED], 0, format->rate); - self->rate = format->rate; - } - - return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, format); -} - -static void -gst_audio_iir_filter_finalize (GObject * object) -{ - GstAudioIIRFilter *self = GST_AUDIO_IIR_FILTER (object); - - g_mutex_free (self->lock); - self->lock = NULL; - - if (self->a) - g_value_array_free (self->a); - self->a = NULL; - if (self->b) - g_value_array_free (self->b); - self->b = NULL; - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_audio_iir_filter_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAudioIIRFilter *self = GST_AUDIO_IIR_FILTER (object); - - g_return_if_fail (GST_IS_AUDIO_IIR_FILTER (self)); - - switch (prop_id) { - case PROP_A: - g_mutex_lock (self->lock); - gst_audio_iir_filter_update_coefficients (self, g_value_dup_boxed (value), - NULL); - g_mutex_unlock (self->lock); - break; - case PROP_B: - g_mutex_lock (self->lock); - gst_audio_iir_filter_update_coefficients (self, NULL, - g_value_dup_boxed (value)); - g_mutex_unlock (self->lock); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_audio_iir_filter_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAudioIIRFilter *self = GST_AUDIO_IIR_FILTER (object); - - switch (prop_id) { - case PROP_A: - g_value_set_boxed (value, self->a); - break; - case PROP_B: - g_value_set_boxed (value, self->b); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audioiirfilter.h --- a/gst_plugins_good/gst/audiofx/audioiirfilter.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2009 Sebastian Dröge - * - * 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. - * - */ - -#ifndef __GST_AUDIO_IIR_FILTER_H__ -#define __GST_AUDIO_IIR_FILTER_H__ - -#include -#include -#include - -#include "audiofxbaseiirfilter.h" - -G_BEGIN_DECLS - -#define GST_TYPE_AUDIO_IIR_FILTER \ - (gst_audio_iir_filter_get_type()) -#define GST_AUDIO_IIR_FILTER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_IIR_FILTER,GstAudioIIRFilter)) -#define GST_AUDIO_IIR_FILTER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_IIR_FILTER,GstAudioIIRFilterClass)) -#define GST_IS_AUDIO_IIR_FILTER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_IIR_FILTER)) -#define GST_IS_AUDIO_IIR_FILTER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_IIR_FILTER)) - -typedef struct _GstAudioIIRFilter GstAudioIIRFilter; -typedef struct _GstAudioIIRFilterClass GstAudioIIRFilterClass; - -/** - * GstAudioIIRFilter: - * - * Opaque data structure. - */ -struct _GstAudioIIRFilter { - GstAudioFXBaseIIRFilter parent; - - GValueArray *a, *b; - - /* < private > */ - GMutex *lock; - gint rate; -}; - -struct _GstAudioIIRFilterClass { - GstAudioFXBaseIIRFilterClass parent; - - void (*rate_changed) (GstElement * element, gint rate); -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_audio_iir_filter_get_type (void); - -G_END_DECLS - -#endif /* __GST_AUDIO_IIR_FILTER_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audioinvert.c --- a/gst_plugins_good/gst/audiofx/audioinvert.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,252 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2007 Sebastian Dröge - * Copyright (C) 2006 Stefan Kost - * - * 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. - */ - -/** - * SECTION:element-audioinvert - * - * Swaps upper and lower half of audio samples. Mixing an inverted sample on top of - * the original with a slight delay can produce effects that sound like resonance. - * Creating a stereo sample from a mono source, with one channel inverted produces wide-stereo sounds. - * - * - * Example launch line - * |[ - * gst-launch audiotestsrc wave=saw ! audioinvert invert=0.4 ! alsasink - * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audioinvert invert=0.4 ! alsasink - * gst-launch audiotestsrc wave=saw ! audioconvert ! audioinvert invert=0.4 ! audioconvert ! alsasink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "audioinvert.h" - -#define GST_CAT_DEFAULT gst_audio_invert_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -static const GstElementDetails element_details = -GST_ELEMENT_DETAILS ("Audio inversion", - "Filter/Effect/Audio", - "Swaps upper and lower half of audio samples", - "Sebastian Dröge "); - -/* Filter signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - PROP_0, - PROP_DEGREE -}; - -#define ALLOWED_CAPS \ - "audio/x-raw-int," \ - " depth=(int)16," \ - " width=(int)16," \ - " endianness=(int)BYTE_ORDER," \ - " signed=(bool)TRUE," \ - " rate=(int)[1,MAX]," \ - " channels=(int)[1,MAX]; " \ - "audio/x-raw-float," \ - " width=(int)32," \ - " endianness=(int)BYTE_ORDER," \ - " rate=(int)[1,MAX]," \ - " channels=(int)[1,MAX]" - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_audio_invert_debug, "audioinvert", 0, "audioinvert element"); - -GST_BOILERPLATE_FULL (GstAudioInvert, gst_audio_invert, GstAudioFilter, - GST_TYPE_AUDIO_FILTER, DEBUG_INIT); - -static void gst_audio_invert_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_audio_invert_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static gboolean gst_audio_invert_setup (GstAudioFilter * filter, - GstRingBufferSpec * format); -static GstFlowReturn gst_audio_invert_transform_ip (GstBaseTransform * base, - GstBuffer * buf); - -static void gst_audio_invert_transform_int (GstAudioInvert * filter, - gint16 * data, guint num_samples); -static void gst_audio_invert_transform_float (GstAudioInvert * filter, - gfloat * data, guint num_samples); - -/* GObject vmethod implementations */ - -static void -gst_audio_invert_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstCaps *caps; - - gst_element_class_set_details (element_class, &element_details); - - caps = gst_caps_from_string (ALLOWED_CAPS); - gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass), - caps); - gst_caps_unref (caps); -} - -static void -gst_audio_invert_class_init (GstAudioInvertClass * klass) -{ - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - gobject_class->set_property = gst_audio_invert_set_property; - gobject_class->get_property = gst_audio_invert_get_property; - - g_object_class_install_property (gobject_class, PROP_DEGREE, - g_param_spec_float ("degree", "Degree", - "Degree of inversion", 0.0, 1.0, - 0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - - GST_AUDIO_FILTER_CLASS (klass)->setup = - GST_DEBUG_FUNCPTR (gst_audio_invert_setup); - GST_BASE_TRANSFORM_CLASS (klass)->transform_ip = - GST_DEBUG_FUNCPTR (gst_audio_invert_transform_ip); -} - -static void -gst_audio_invert_init (GstAudioInvert * filter, GstAudioInvertClass * klass) -{ - filter->degree = 0.0; - gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE); - gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE); -} - -static void -gst_audio_invert_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAudioInvert *filter = GST_AUDIO_INVERT (object); - - switch (prop_id) { - case PROP_DEGREE: - filter->degree = g_value_get_float (value); - gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), - filter->degree == 0.0); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_audio_invert_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAudioInvert *filter = GST_AUDIO_INVERT (object); - - switch (prop_id) { - case PROP_DEGREE: - g_value_set_float (value, filter->degree); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* GstAudioFilter vmethod implementations */ - -static gboolean -gst_audio_invert_setup (GstAudioFilter * base, GstRingBufferSpec * format) -{ - GstAudioInvert *filter = GST_AUDIO_INVERT (base); - gboolean ret = TRUE; - - if (format->type == GST_BUFTYPE_FLOAT && format->width == 32) - filter->process = (GstAudioInvertProcessFunc) - gst_audio_invert_transform_float; - else if (format->type == GST_BUFTYPE_LINEAR && format->width == 16) - filter->process = (GstAudioInvertProcessFunc) - gst_audio_invert_transform_int; - else - ret = FALSE; - - return ret; -} - -static void -gst_audio_invert_transform_int (GstAudioInvert * filter, - gint16 * data, guint num_samples) -{ - gint i; - gfloat dry = 1.0 - filter->degree; - glong val; - - for (i = 0; i < num_samples; i++) { - val = (*data) * dry + (-1 - (*data)) * filter->degree; - *data++ = (gint16) CLAMP (val, G_MININT16, G_MAXINT16); - } -} - -static void -gst_audio_invert_transform_float (GstAudioInvert * filter, - gfloat * data, guint num_samples) -{ - gint i; - gfloat dry = 1.0 - filter->degree; - glong val; - - for (i = 0; i < num_samples; i++) { - val = (*data) * dry - (*data) * filter->degree; - *data++ = val; - } -} - -/* GstBaseTransform vmethod implementations */ -static GstFlowReturn -gst_audio_invert_transform_ip (GstBaseTransform * base, GstBuffer * buf) -{ - GstAudioInvert *filter = GST_AUDIO_INVERT (base); - guint num_samples = - GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8); - - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) - gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (buf)); - - if (gst_base_transform_is_passthrough (base) || - G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP))) - return GST_FLOW_OK; - - filter->process (filter, GST_BUFFER_DATA (buf), num_samples); - - return GST_FLOW_OK; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audioinvert.h --- a/gst_plugins_good/gst/audiofx/audioinvert.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2007 Sebastian Dröge - * Copyright (C) 2006 Stefan Kost - * - * 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. - */ - -#ifndef __GST_AUDIO_INVERT_H__ -#define __GST_AUDIO_INVERT_H__ - -#include -#include -#include -#include -#include - -G_BEGIN_DECLS -#define GST_TYPE_AUDIO_INVERT (gst_audio_invert_get_type()) -#define GST_AUDIO_INVERT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_INVERT,GstAudioInvert)) -#define GST_IS_AUDIO_INVERT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_INVERT)) -#define GST_AUDIO_INVERT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_INVERT,GstAudioInvertClass)) -#define GST_IS_AUDIO_INVERT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_INVERT)) -#define GST_AUDIO_INVERT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_INVERT,GstAudioInvertClass)) -typedef struct _GstAudioInvert GstAudioInvert; -typedef struct _GstAudioInvertClass GstAudioInvertClass; - -typedef void (*GstAudioInvertProcessFunc) (GstAudioInvert *, guint8 *, guint); - -struct _GstAudioInvert -{ - GstAudioFilter audiofilter; - - gfloat degree; - - /* < private > */ - GstAudioInvertProcessFunc process; -}; - -struct _GstAudioInvertClass -{ - GstAudioFilterClass parent; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_audio_invert_get_type (void); - -G_END_DECLS -#endif /* __GST_AUDIO_INVERT_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiokaraoke.c --- a/gst_plugins_good/gst/audiofx/audiokaraoke.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,357 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Wim Taymans - * - * 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. - */ - -/** - * SECTION:element-audiokaraoke - * - * Remove the voice from audio by filtering the center channel. - * This plugin is useful for karaoke applications. - * - * - * Example launch line - * |[ - * gst-launch filesrc location=song.ogg ! oggdemux ! vorbisdec ! audiokaraoke ! audioconvert ! alsasink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include -#include -#include -#include -#include - -#include "audiokaraoke.h" - -#define GST_CAT_DEFAULT gst_audio_karaoke_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -static const GstElementDetails element_details = -GST_ELEMENT_DETAILS ("AudioKaraoke", - "Filter/Effect/Audio", - "Removes voice from sound", - "Wim Taymans "); - -/* Filter signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -#define DEFAULT_LEVEL 1.0 -#define DEFAULT_MONO_LEVEL 1.0 -#define DEFAULT_FILTER_BAND 220.0 -#define DEFAULT_FILTER_WIDTH 100.0 - -enum -{ - PROP_0, - PROP_LEVEL, - PROP_MONO_LEVEL, - PROP_FILTER_BAND, - PROP_FILTER_WIDTH, - PROP_LAST -}; - -#define ALLOWED_CAPS \ - "audio/x-raw-int," \ - " depth=(int)16," \ - " width=(int)16," \ - " endianness=(int)BYTE_ORDER," \ - " signed=(bool)TRUE," \ - " rate=(int)[1,MAX]," \ - " channels=(int)[1,MAX]; " \ - "audio/x-raw-float," \ - " width=(int)32," \ - " endianness=(int)BYTE_ORDER," \ - " rate=(int)[1,MAX]," \ - " channels=(int)[1,MAX]" - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_audio_karaoke_debug, "audiokaraoke", 0, "audiokaraoke element"); - -GST_BOILERPLATE_FULL (GstAudioKaraoke, gst_audio_karaoke, GstAudioFilter, - GST_TYPE_AUDIO_FILTER, DEBUG_INIT); - -static void gst_audio_karaoke_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_audio_karaoke_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static gboolean gst_audio_karaoke_setup (GstAudioFilter * filter, - GstRingBufferSpec * format); -static GstFlowReturn gst_audio_karaoke_transform_ip (GstBaseTransform * base, - GstBuffer * buf); - -static void gst_audio_karaoke_transform_int (GstAudioKaraoke * filter, - gint16 * data, guint num_samples); -static void gst_audio_karaoke_transform_float (GstAudioKaraoke * filter, - gfloat * data, guint num_samples); - -/* GObject vmethod implementations */ - -static void -gst_audio_karaoke_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstCaps *caps; - - gst_element_class_set_details (element_class, &element_details); - - caps = gst_caps_from_string (ALLOWED_CAPS); - gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass), - caps); - gst_caps_unref (caps); -} - -static void -gst_audio_karaoke_class_init (GstAudioKaraokeClass * klass) -{ - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - gobject_class->set_property = gst_audio_karaoke_set_property; - gobject_class->get_property = gst_audio_karaoke_get_property; - - g_object_class_install_property (gobject_class, PROP_LEVEL, - g_param_spec_float ("level", "Level", - "Level of the effect (1.0 = full)", 0.0, 1.0, DEFAULT_LEVEL, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - - g_object_class_install_property (gobject_class, PROP_MONO_LEVEL, - g_param_spec_float ("mono-level", "Mono Level", - "Level of the mono channel (1.0 = full)", 0.0, 1.0, DEFAULT_LEVEL, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - - g_object_class_install_property (gobject_class, PROP_FILTER_BAND, - g_param_spec_float ("filter-band", "Filter Band", - "The Frequency band of the filter", 0.0, 441.0, DEFAULT_FILTER_BAND, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - - g_object_class_install_property (gobject_class, PROP_FILTER_WIDTH, - g_param_spec_float ("filter-width", "Filter Width", - "The Frequency width of the filter", 0.0, 100.0, DEFAULT_FILTER_WIDTH, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - - GST_AUDIO_FILTER_CLASS (klass)->setup = - GST_DEBUG_FUNCPTR (gst_audio_karaoke_setup); - GST_BASE_TRANSFORM_CLASS (klass)->transform_ip = - GST_DEBUG_FUNCPTR (gst_audio_karaoke_transform_ip); -} - -static void -gst_audio_karaoke_init (GstAudioKaraoke * filter, GstAudioKaraokeClass * klass) -{ - gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE); - gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE); - - filter->level = DEFAULT_LEVEL; - filter->mono_level = DEFAULT_MONO_LEVEL; - filter->filter_band = DEFAULT_FILTER_BAND; - filter->filter_width = DEFAULT_FILTER_WIDTH; -} - -static void -update_filter (GstAudioKaraoke * filter, gint rate) -{ - gfloat A, B, C; - - if (rate == 0) - return; - - C = exp (-2 * M_PI * filter->filter_width / rate); - B = -4 * C / (1 + C) * cos (2 * M_PI * filter->filter_band / rate); - A = sqrt (1 - B * B / (4 * C)) * (1 - C); - - filter->A = A; - filter->B = B; - filter->C = C; - filter->y1 = 0.0; - filter->y2 = 0.0; -} - -static void -gst_audio_karaoke_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAudioKaraoke *filter; - - filter = GST_AUDIO_KARAOKE (object); - - switch (prop_id) { - case PROP_LEVEL: - filter->level = g_value_get_float (value); - break; - case PROP_MONO_LEVEL: - filter->mono_level = g_value_get_float (value); - break; - case PROP_FILTER_BAND: - filter->filter_band = g_value_get_float (value); - update_filter (filter, filter->rate); - break; - case PROP_FILTER_WIDTH: - filter->filter_width = g_value_get_float (value); - update_filter (filter, filter->rate); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_audio_karaoke_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAudioKaraoke *filter; - - filter = GST_AUDIO_KARAOKE (object); - - switch (prop_id) { - case PROP_LEVEL: - g_value_set_float (value, filter->level); - break; - case PROP_MONO_LEVEL: - g_value_set_float (value, filter->mono_level); - break; - case PROP_FILTER_BAND: - g_value_set_float (value, filter->filter_band); - break; - case PROP_FILTER_WIDTH: - g_value_set_float (value, filter->filter_width); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* GstAudioFilter vmethod implementations */ - -static gboolean -gst_audio_karaoke_setup (GstAudioFilter * base, GstRingBufferSpec * format) -{ - GstAudioKaraoke *filter = GST_AUDIO_KARAOKE (base); - gboolean ret = TRUE; - - filter->channels = format->channels; - filter->rate = format->rate; - - if (format->type == GST_BUFTYPE_FLOAT && format->width == 32) - filter->process = (GstAudioKaraokeProcessFunc) - gst_audio_karaoke_transform_float; - else if (format->type == GST_BUFTYPE_LINEAR && format->width == 16) - filter->process = (GstAudioKaraokeProcessFunc) - gst_audio_karaoke_transform_int; - else - ret = FALSE; - - update_filter (filter, format->rate); - - return ret; -} - -static void -gst_audio_karaoke_transform_int (GstAudioKaraoke * filter, - gint16 * data, guint num_samples) -{ - gint i, l, r, o, x; - gint channels; - gdouble y; - gint level; - - channels = filter->channels; - level = filter->level * 256; - - for (i = 0; i < num_samples; i += channels) { - /* get left and right inputs */ - l = data[i]; - r = data[i + 1]; - /* do filtering */ - x = (l + r) / 2; - y = (filter->A * x - filter->B * filter->y1) - filter->C * filter->y2; - filter->y2 = filter->y1; - filter->y1 = y; - /* filter mono signal */ - o = (int) (y * filter->mono_level); - o = CLAMP (o, G_MININT16, G_MAXINT16); - o = (o * level) >> 8; - /* now cut the center */ - x = l - ((r * level) >> 8) + o; - r = r - ((l * level) >> 8) + o; - data[i] = CLAMP (x, G_MININT16, G_MAXINT16); - data[i + 1] = CLAMP (r, G_MININT16, G_MAXINT16); - } -} - -static void -gst_audio_karaoke_transform_float (GstAudioKaraoke * filter, - gfloat * data, guint num_samples) -{ - gint i; - gint channels; - gdouble l, r, o; - gdouble y; - - channels = filter->channels; - - for (i = 0; i < num_samples; i += channels) { - /* get left and right inputs */ - l = data[i]; - r = data[i + 1]; - /* do filtering */ - y = (filter->A * ((l + r) / 2.0) - filter->B * filter->y1) - - filter->C * filter->y2; - filter->y2 = filter->y1; - filter->y1 = y; - /* filter mono signal */ - o = y * filter->mono_level * filter->level; - /* now cut the center */ - data[i] = l - (r * filter->level) + o; - data[i + 1] = r - (l * filter->level) + o; - } -} - -/* GstBaseTransform vmethod implementations */ -static GstFlowReturn -gst_audio_karaoke_transform_ip (GstBaseTransform * base, GstBuffer * buf) -{ - GstAudioKaraoke *filter = GST_AUDIO_KARAOKE (base); - guint num_samples = - GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8); - - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) - gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (buf)); - - if (gst_base_transform_is_passthrough (base) || - G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP))) - return GST_FLOW_OK; - - filter->process (filter, GST_BUFFER_DATA (buf), num_samples); - - return GST_FLOW_OK; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiokaraoke.h --- a/gst_plugins_good/gst/audiofx/audiokaraoke.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Wim Taymans - * - * 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. - */ - -#ifndef __GST_AUDIO_KARAOKE_H__ -#define __GST_AUDIO_KARAOKE_H__ - -#include -#include -#include -#include -#include - -G_BEGIN_DECLS -#define GST_TYPE_AUDIO_KARAOKE (gst_audio_karaoke_get_type()) -#define GST_AUDIO_KARAOKE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_KARAOKE,GstAudioKaraoke)) -#define GST_IS_AUDIO_KARAOKE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_KARAOKE)) -#define GST_AUDIO_KARAOKE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_KARAOKE,GstAudioKaraokeClass)) -#define GST_IS_AUDIO_KARAOKE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_KARAOKE)) -#define GST_AUDIO_KARAOKE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_KARAOKE,GstAudioKaraokeClass)) -typedef struct _GstAudioKaraoke GstAudioKaraoke; -typedef struct _GstAudioKaraokeClass GstAudioKaraokeClass; - -typedef void (*GstAudioKaraokeProcessFunc) (GstAudioKaraoke *, guint8 *, guint); - -struct _GstAudioKaraoke -{ - GstAudioFilter audiofilter; - - gint channels; - gint rate; - - /* properties */ - gfloat level; - gfloat mono_level; - gfloat filter_band; - gfloat filter_width; - - /* filter coef */ - gfloat A, B, C; - gfloat y1, y2; - - /* < private > */ - GstAudioKaraokeProcessFunc process; -}; - -struct _GstAudioKaraokeClass -{ - GstAudioFilterClass parent; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_audio_karaoke_get_type (void); - -G_END_DECLS -#endif /* __GST_AUDIO_KARAOKE_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiopanorama.c --- a/gst_plugins_good/gst/audiofx/audiopanorama.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,648 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2006 Stefan Kost - * Copyright (C) 2006 Sebastian Dröge - * - * 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. - */ - -/** - * SECTION:element-audiopanorama - * - * Stereo panorama effect with controllable pan position. One can choose between the default psychoacoustic panning method, - * which keeps the same perceived loudness, and a simple panning method that just controls the volume on one channel. - * - * - * Example launch line - * |[ - * gst-launch audiotestsrc wave=saw ! audiopanorama panorama=-1.00 ! alsasink - * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiopanorama panorama=-1.00 ! alsasink - * gst-launch audiotestsrc wave=saw ! audioconvert ! audiopanorama panorama=-1.00 ! audioconvert ! alsasink - * gst-launch audiotestsrc wave=saw ! audioconvert ! audiopanorama method=simple panorama=-0.50 ! audioconvert ! alsasink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#include "audiopanorama.h" - -#define GST_CAT_DEFAULT gst_audio_panorama_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -static const GstElementDetails element_details = -GST_ELEMENT_DETAILS ("Stereo positioning", - "Filter/Effect/Audio", - "Positions audio streams in the stereo panorama", - "Stefan Kost "); - -/* Filter signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - PROP_0, - PROP_PANORAMA, - PROP_METHOD -}; - -enum -{ - METHOD_PSYCHOACOUSTIC = 0, - METHOD_SIMPLE, - NUM_METHODS -}; - -#define GST_TYPE_AUDIO_PANORAMA_METHOD (gst_audio_panorama_method_get_type ()) -static GType -gst_audio_panorama_method_get_type (void) -{ - static GType gtype = 0; - - if (gtype == 0) { - static const GEnumValue values[] = { - {METHOD_PSYCHOACOUSTIC, "Psychoacoustic Panning (default)", - "psychoacoustic"}, - {METHOD_SIMPLE, "Simple Panning", "simple"}, - {0, NULL, NULL} - }; - - gtype = g_enum_register_static ("GstAudioPanoramaMethod", values); - } - return gtype; -} - -static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-float, " - "rate = (int) [ 1, MAX ], " - "channels = (int) [ 1, 2 ], " - "endianness = (int) BYTE_ORDER, " "width = (int) 32; " - "audio/x-raw-int, " - "rate = (int) [ 1, MAX ], " - "channels = (int) [ 1, 2 ], " - "endianness = (int) BYTE_ORDER, " - "width = (int) 16, " "depth = (int) 16, " "signed = (boolean) true") - ); - -static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-float, " - "rate = (int) [ 1, MAX ], " - "channels = (int) 2, " - "endianness = (int) BYTE_ORDER, " "width = (int) 32; " - "audio/x-raw-int, " - "rate = (int) [ 1, MAX ], " - "channels = (int) 2, " - "endianness = (int) BYTE_ORDER, " - "width = (int) 16, " "depth = (int) 16, " "signed = (boolean) true") - ); - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_audio_panorama_debug, "audiopanorama", 0, "audiopanorama element"); - -GST_BOILERPLATE_FULL (GstAudioPanorama, gst_audio_panorama, GstBaseTransform, - GST_TYPE_BASE_TRANSFORM, DEBUG_INIT); - -static void gst_audio_panorama_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_audio_panorama_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -static gboolean gst_audio_panorama_get_unit_size (GstBaseTransform * base, - GstCaps * caps, guint * size); -static GstCaps *gst_audio_panorama_transform_caps (GstBaseTransform * base, - GstPadDirection direction, GstCaps * caps); -static gboolean gst_audio_panorama_set_caps (GstBaseTransform * base, - GstCaps * incaps, GstCaps * outcaps); - -static void gst_audio_panorama_transform_m2s_int (GstAudioPanorama * filter, - gint16 * idata, gint16 * odata, guint num_samples); -static void gst_audio_panorama_transform_s2s_int (GstAudioPanorama * filter, - gint16 * idata, gint16 * odata, guint num_samples); -static void gst_audio_panorama_transform_m2s_float (GstAudioPanorama * filter, - gfloat * idata, gfloat * odata, guint num_samples); -static void gst_audio_panorama_transform_s2s_float (GstAudioPanorama * filter, - gfloat * idata, gfloat * odata, guint num_samples); - -static void gst_audio_panorama_transform_m2s_int_simple (GstAudioPanorama * - filter, gint16 * idata, gint16 * odata, guint num_samples); -static void gst_audio_panorama_transform_s2s_int_simple (GstAudioPanorama * - filter, gint16 * idata, gint16 * odata, guint num_samples); -static void gst_audio_panorama_transform_m2s_float_simple (GstAudioPanorama * - filter, gfloat * idata, gfloat * odata, guint num_samples); -static void gst_audio_panorama_transform_s2s_float_simple (GstAudioPanorama * - filter, gfloat * idata, gfloat * odata, guint num_samples); - -static GstFlowReturn gst_audio_panorama_transform (GstBaseTransform * base, - GstBuffer * inbuf, GstBuffer * outbuf); - - -/* Table with processing functions: [channels][format][method] */ -static GstAudioPanoramaProcessFunc panorama_process_functions[2][2][2] = { - { - {(GstAudioPanoramaProcessFunc) gst_audio_panorama_transform_m2s_int, - (GstAudioPanoramaProcessFunc) - gst_audio_panorama_transform_m2s_int_simple}, - {(GstAudioPanoramaProcessFunc) gst_audio_panorama_transform_m2s_float, - (GstAudioPanoramaProcessFunc) - gst_audio_panorama_transform_m2s_float_simple} - }, - { - {(GstAudioPanoramaProcessFunc) gst_audio_panorama_transform_s2s_int, - (GstAudioPanoramaProcessFunc) - gst_audio_panorama_transform_s2s_int_simple}, - {(GstAudioPanoramaProcessFunc) gst_audio_panorama_transform_s2s_float, - (GstAudioPanoramaProcessFunc) - gst_audio_panorama_transform_s2s_float_simple} - } -}; - -/* GObject vmethod implementations */ - -static void -gst_audio_panorama_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_template)); - gst_element_class_set_details (element_class, &element_details); -} - -static void -gst_audio_panorama_class_init (GstAudioPanoramaClass * klass) -{ - GObjectClass *gobject_class; - - gobject_class = (GObjectClass *) klass; - gobject_class->set_property = gst_audio_panorama_set_property; - gobject_class->get_property = gst_audio_panorama_get_property; - - g_object_class_install_property (gobject_class, PROP_PANORAMA, - g_param_spec_float ("panorama", "Panorama", - "Position in stereo panorama (-1.0 left -> 1.0 right)", -1.0, 1.0, - 0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - /** - * GstAudioPanorama:method - * - * Panning method: psychoacoustic mode keeps the same perceived loudness, - * while simple mode just controls the volume of one channel. It's merely - * a matter of taste which method should be chosen. - * - * Since: 0.10.6 - **/ - g_object_class_install_property (gobject_class, PROP_METHOD, - g_param_spec_enum ("method", "Panning method", - "Psychoacoustic mode keeps same perceived loudness, " - "simple mode just controls volume of one channel.", - GST_TYPE_AUDIO_PANORAMA_METHOD, METHOD_PSYCHOACOUSTIC, - G_PARAM_READWRITE)); - - GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size = - GST_DEBUG_FUNCPTR (gst_audio_panorama_get_unit_size); - GST_BASE_TRANSFORM_CLASS (klass)->transform_caps = - GST_DEBUG_FUNCPTR (gst_audio_panorama_transform_caps); - GST_BASE_TRANSFORM_CLASS (klass)->set_caps = - GST_DEBUG_FUNCPTR (gst_audio_panorama_set_caps); - GST_BASE_TRANSFORM_CLASS (klass)->transform = - GST_DEBUG_FUNCPTR (gst_audio_panorama_transform); -} - -static void -gst_audio_panorama_init (GstAudioPanorama * filter, - GstAudioPanoramaClass * klass) -{ - - filter->panorama = 0; - filter->method = METHOD_PSYCHOACOUSTIC; - filter->width = 0; - filter->channels = 0; - filter->format_float = FALSE; - filter->process = NULL; - - gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE); -} - -static gboolean -gst_audio_panorama_set_process_function (GstAudioPanorama * filter) -{ - gint channel_index, format_index, method_index; - - /* set processing function */ - channel_index = filter->channels - 1; - if (channel_index > 1 || channel_index < 0) { - filter->process = NULL; - return FALSE; - } - - format_index = (filter->format_float) ? 1 : 0; - - method_index = filter->method; - if (method_index >= NUM_METHODS || method_index < 0) - method_index = METHOD_PSYCHOACOUSTIC; - - filter->process = - panorama_process_functions[channel_index][format_index][method_index]; - return TRUE; -} - -static void -gst_audio_panorama_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAudioPanorama *filter = GST_AUDIO_PANORAMA (object); - - switch (prop_id) { - case PROP_PANORAMA: - filter->panorama = g_value_get_float (value); - break; - case PROP_METHOD: - filter->method = g_value_get_enum (value); - gst_audio_panorama_set_process_function (filter); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_audio_panorama_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAudioPanorama *filter = GST_AUDIO_PANORAMA (object); - - switch (prop_id) { - case PROP_PANORAMA: - g_value_set_float (value, filter->panorama); - break; - case PROP_METHOD: - g_value_set_enum (value, filter->method); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* GstBaseTransform vmethod implementations */ - -static gboolean -gst_audio_panorama_get_unit_size (GstBaseTransform * base, GstCaps * caps, - guint * size) -{ - gint width, channels; - GstStructure *structure; - gboolean ret; - - g_assert (size); - - /* this works for both float and int */ - structure = gst_caps_get_structure (caps, 0); - ret = gst_structure_get_int (structure, "width", &width); - ret &= gst_structure_get_int (structure, "channels", &channels); - - *size = width * channels / 8; - - return ret; -} - -static GstCaps * -gst_audio_panorama_transform_caps (GstBaseTransform * base, - GstPadDirection direction, GstCaps * caps) -{ - GstCaps *res; - GstStructure *structure; - - /* transform caps gives one single caps so we can just replace - * the channel property with our range. */ - res = gst_caps_copy (caps); - structure = gst_caps_get_structure (res, 0); - if (direction == GST_PAD_SRC) { - GST_INFO ("allow 1-2 channels"); - gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); - } else { - GST_INFO ("allow 2 channels"); - gst_structure_set (structure, "channels", G_TYPE_INT, 2, NULL); - } - - return res; -} - -static gboolean -gst_audio_panorama_set_caps (GstBaseTransform * base, GstCaps * incaps, - GstCaps * outcaps) -{ - GstAudioPanorama *filter = GST_AUDIO_PANORAMA (base); - const GstStructure *structure; - gboolean ret; - gint width; - const gchar *fmt; - - /*GST_INFO ("incaps are %" GST_PTR_FORMAT, incaps); */ - - structure = gst_caps_get_structure (incaps, 0); - ret = gst_structure_get_int (structure, "channels", &filter->channels); - if (!ret) - goto no_channels; - - ret = gst_structure_get_int (structure, "width", &width); - if (!ret) - goto no_width; - filter->width = width / 8; - - fmt = gst_structure_get_name (structure); - if (!strcmp (fmt, "audio/x-raw-int")) - filter->format_float = FALSE; - else - filter->format_float = TRUE; - - GST_DEBUG ("try to process %s input with %d channels", fmt, filter->channels); - - ret = gst_audio_panorama_set_process_function (filter); - - if (!ret) - GST_WARNING ("can't process input with %d channels", filter->channels); - - return ret; - -no_channels: - GST_DEBUG ("no channels in caps"); - return ret; -no_width: - GST_DEBUG ("no width in caps"); - return ret; -} - -/* psychoacoustic processing functions */ -static void -gst_audio_panorama_transform_m2s_int (GstAudioPanorama * filter, gint16 * idata, - gint16 * odata, guint num_samples) -{ - guint i; - gdouble val; - glong lval, rval; - gdouble rpan, lpan; - - /* pan: -1.0 0.0 1.0 - * lpan: 1.0 0.5 0.0 - * rpan: 0.0 0.5 1.0 - * - * FIXME: we should use -3db (1/sqtr(2)) for 50:50 - */ - rpan = (gdouble) (filter->panorama + 1.0) / 2.0; - lpan = 1.0 - rpan; - - for (i = 0; i < num_samples; i++) { - val = (gdouble) * idata++; - - lval = (glong) (val * lpan); - rval = (glong) (val * rpan); - - *odata++ = (gint16) CLAMP (lval, G_MININT16, G_MAXINT16); - *odata++ = (gint16) CLAMP (rval, G_MININT16, G_MAXINT16); - } -} - -static void -gst_audio_panorama_transform_s2s_int (GstAudioPanorama * filter, gint16 * idata, - gint16 * odata, guint num_samples) -{ - guint i; - glong lval, rval; - gdouble lival, rival; - gdouble lrpan, llpan, rrpan, rlpan; - - /* pan: -1.0 0.0 1.0 - * llpan: 1.0 1.0 0.0 - * lrpan: 1.0 0.0 0.0 - * rrpan: 0.0 1.0 1.0 - * rlpan: 0.0 0.0 1.0 - */ - if (filter->panorama > 0) { - rlpan = (gdouble) filter->panorama; - llpan = 1.0 - rlpan; - lrpan = 0.0; - rrpan = 1.0; - } else { - rrpan = (gdouble) (1.0 + filter->panorama); - lrpan = 1.0 - rrpan; - rlpan = 0.0; - llpan = 1.0; - } - - for (i = 0; i < num_samples; i++) { - lival = (gdouble) * idata++; - rival = (gdouble) * idata++; - - lval = lival * llpan + rival * lrpan; - rval = lival * rlpan + rival * rrpan; - - *odata++ = (gint16) CLAMP (lval, G_MININT16, G_MAXINT16); - *odata++ = (gint16) CLAMP (rval, G_MININT16, G_MAXINT16); - } -} - -static void -gst_audio_panorama_transform_m2s_float (GstAudioPanorama * filter, - gfloat * idata, gfloat * odata, guint num_samples) -{ - guint i; - gfloat val; - gdouble rpan, lpan; - - /* pan: -1.0 0.0 1.0 - * lpan: 1.0 0.5 0.0 - * rpan: 0.0 0.5 1.0 - * - * FIXME: we should use -3db (1/sqtr(2)) for 50:50 - */ - rpan = (gdouble) (filter->panorama + 1.0) / 2.0; - lpan = 1.0 - rpan; - - for (i = 0; i < num_samples; i++) { - val = *idata++; - - *odata++ = val * lpan; - *odata++ = val * rpan; - } -} - -static void -gst_audio_panorama_transform_s2s_float (GstAudioPanorama * filter, - gfloat * idata, gfloat * odata, guint num_samples) -{ - guint i; - gfloat lival, rival; - gdouble lrpan, llpan, rrpan, rlpan; - - /* pan: -1.0 0.0 1.0 - * llpan: 1.0 1.0 0.0 - * lrpan: 1.0 0.0 0.0 - * rrpan: 0.0 1.0 1.0 - * rlpan: 0.0 0.0 1.0 - */ - if (filter->panorama > 0) { - rlpan = (gdouble) filter->panorama; - llpan = 1.0 - rlpan; - lrpan = 0.0; - rrpan = 1.0; - } else { - rrpan = (gdouble) (1.0 + filter->panorama); - lrpan = 1.0 - rrpan; - rlpan = 0.0; - llpan = 1.0; - } - - for (i = 0; i < num_samples; i++) { - lival = *idata++; - rival = *idata++; - - *odata++ = lival * llpan + rival * lrpan; - *odata++ = lival * rlpan + rival * rrpan; - } -} - -/* simple processing functions */ -static void -gst_audio_panorama_transform_m2s_int_simple (GstAudioPanorama * filter, - gint16 * idata, gint16 * odata, guint num_samples) -{ - guint i; - gdouble val; - glong lval, rval; - - for (i = 0; i < num_samples; i++) { - val = (gdouble) * idata++; - - if (filter->panorama > 0.0) { - lval = (glong) (val * (1.0 - filter->panorama)); - rval = (glong) val; - } else { - lval = (glong) val; - rval = (glong) (val * (1.0 + filter->panorama)); - } - - *odata++ = (gint16) CLAMP (lval, G_MININT16, G_MAXINT16); - *odata++ = (gint16) CLAMP (rval, G_MININT16, G_MAXINT16); - } -} - -static void -gst_audio_panorama_transform_s2s_int_simple (GstAudioPanorama * filter, - gint16 * idata, gint16 * odata, guint num_samples) -{ - guint i; - glong lval, rval; - gdouble lival, rival; - - for (i = 0; i < num_samples; i++) { - lival = (gdouble) * idata++; - rival = (gdouble) * idata++; - - if (filter->panorama > 0.0) { - lval = (glong) (lival * (1.0 - filter->panorama)); - rval = (glong) rival; - } else { - lval = (glong) lival; - rval = (glong) (rival * (1.0 + filter->panorama)); - } - - *odata++ = (gint16) CLAMP (lval, G_MININT16, G_MAXINT16); - *odata++ = (gint16) CLAMP (rval, G_MININT16, G_MAXINT16); - } -} - -static void -gst_audio_panorama_transform_m2s_float_simple (GstAudioPanorama * filter, - gfloat * idata, gfloat * odata, guint num_samples) -{ - guint i; - gfloat val; - - - for (i = 0; i < num_samples; i++) { - val = *idata++; - - if (filter->panorama > 0.0) { - *odata++ = val * (1.0 - filter->panorama); - *odata++ = val; - } else { - *odata++ = val; - *odata++ = val * (1.0 + filter->panorama); - } - } -} - -static void -gst_audio_panorama_transform_s2s_float_simple (GstAudioPanorama * filter, - gfloat * idata, gfloat * odata, guint num_samples) -{ - guint i; - gfloat lival, rival; - - for (i = 0; i < num_samples; i++) { - lival = *idata++; - rival = *idata++; - - if (filter->panorama > 0.0) { - *odata++ = lival * (1.0 - filter->panorama); - *odata++ = rival; - } else { - *odata++ = lival; - *odata++ = rival * (1.0 + filter->panorama); - } - } -} - -/* this function does the actual processing - */ -static GstFlowReturn -gst_audio_panorama_transform (GstBaseTransform * base, GstBuffer * inbuf, - GstBuffer * outbuf) -{ - GstAudioPanorama *filter = GST_AUDIO_PANORAMA (base); - guint num_samples = GST_BUFFER_SIZE (outbuf) / (2 * filter->width); - - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (outbuf))) - gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (outbuf)); - - if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP))) { - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP); - memset (GST_BUFFER_DATA (outbuf), 0, GST_BUFFER_SIZE (outbuf)); - return GST_FLOW_OK; - } - - filter->process (filter, GST_BUFFER_DATA (inbuf), - GST_BUFFER_DATA (outbuf), num_samples); - - return GST_FLOW_OK; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiopanorama.h --- a/gst_plugins_good/gst/audiofx/audiopanorama.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2006 Stefan Kost - * - * 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. - */ - -#ifndef __GST_AUDIO_PANORAMA_H__ -#define __GST_AUDIO_PANORAMA_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_AUDIO_PANORAMA (gst_audio_panorama_get_type()) -#define GST_AUDIO_PANORAMA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_PANORAMA,GstAudioPanorama)) -#define GST_IS_AUDIO_PANORAMA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_PANORAMA)) -#define GST_AUDIO_PANORAMA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_PANORAMA,GstAudioPanoramaClass)) -#define GST_IS_AUDIO_PANORAMA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_PANORAMA)) -#define GST_AUDIO_PANORAMA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_PANORAMA,GstAudioPanoramaClass)) - -typedef struct _GstAudioPanorama GstAudioPanorama; -typedef struct _GstAudioPanoramaClass GstAudioPanoramaClass; - -typedef void (*GstAudioPanoramaProcessFunc)(GstAudioPanorama*, guint8*, guint8*, guint); - -struct _GstAudioPanorama { - GstBaseTransform element; - - gfloat panorama; - - /* < private > */ - GstAudioPanoramaProcessFunc process; - gint channels; - gboolean format_float; - gint width; - gint method; -}; - -struct _GstAudioPanoramaClass { - GstBaseTransformClass parent_class; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_audio_panorama_get_type (void); - -G_END_DECLS - -#endif /* __GST_AUDIO_PANORAMA_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiowsincband.c --- a/gst_plugins_good/gst/audiofx/audiowsincband.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,440 +0,0 @@ -/* -*- c-basic-offset: 2 -*- - * - * GStreamer - * Copyright (C) 1999-2001 Erik Walthinsen - * 2006 Dreamlab Technologies Ltd. - * 2007-2009 Sebastian Dröge - * - * 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. - * - * - * this windowed sinc filter is taken from the freely downloadable DSP book, - * "The Scientist and Engineer's Guide to Digital Signal Processing", - * chapter 16 - * available at http://www.dspguide.com/ - * - */ - -/** - * SECTION:element-audiowsincband - * - * Attenuates all frequencies outside (bandpass) or inside (bandreject) of a frequency - * band. The length parameter controls the rolloff, the window parameter - * controls rolloff and stopband attenuation. The Hamming window provides a faster rolloff but a bit - * worse stopband attenuation, the other way around for the Blackman window. - * - * This element has the advantage over the Chebyshev bandpass and bandreject filter that it has - * a much better rolloff when using a larger kernel size and almost linear phase. The only - * disadvantage is the much slower execution time with larger kernels. - * - * - * Example launch line - * |[ - * gst-launch audiotestsrc freq=1500 ! audioconvert ! audiosincband mode=band-pass lower-frequency=3000 upper-frequency=10000 length=501 window=blackman ! audioconvert ! alsasink - * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiowsincband mode=band-reject lower-frequency=59 upper-frequency=61 length=10001 window=hamming ! audioconvert ! alsasink - * gst-launch audiotestsrc wave=white-noise ! audioconvert ! audiowsincband mode=band-pass lower-frequency=1000 upper-frequency=2000 length=31 ! audioconvert ! alsasink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "audiowsincband.h" - -#define GST_CAT_DEFAULT gst_gst_audio_wsincband_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -enum -{ - PROP_0, - PROP_LENGTH, - PROP_LOWER_FREQUENCY, - PROP_UPPER_FREQUENCY, - PROP_MODE, - PROP_WINDOW -}; - -enum -{ - MODE_BAND_PASS = 0, - MODE_BAND_REJECT -}; - -#define GST_TYPE_AUDIO_WSINC_BAND_MODE (gst_gst_audio_wsincband_mode_get_type ()) -static GType -gst_gst_audio_wsincband_mode_get_type (void) -{ - static GType gtype = 0; - - if (gtype == 0) { - static const GEnumValue values[] = { - {MODE_BAND_PASS, "Band pass (default)", - "band-pass"}, - {MODE_BAND_REJECT, "Band reject", - "band-reject"}, - {0, NULL, NULL} - }; - - gtype = g_enum_register_static ("GstAudioWSincBandMode", values); - } - return gtype; -} - -enum -{ - WINDOW_HAMMING = 0, - WINDOW_BLACKMAN -}; - -#define GST_TYPE_AUDIO_WSINC_BAND_WINDOW (gst_gst_audio_wsincband_window_get_type ()) -static GType -gst_gst_audio_wsincband_window_get_type (void) -{ - static GType gtype = 0; - - if (gtype == 0) { - static const GEnumValue values[] = { - {WINDOW_HAMMING, "Hamming window (default)", - "hamming"}, - {WINDOW_BLACKMAN, "Blackman window", - "blackman"}, - {0, NULL, NULL} - }; - - gtype = g_enum_register_static ("GstAudioWSincBandWindow", values); - } - return gtype; -} - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_gst_audio_wsincband_debug, "audiowsincband", 0, \ - "Band-pass and Band-reject Windowed sinc filter plugin"); - -GST_BOILERPLATE_FULL (GstAudioWSincBand, gst_audio_wsincband, GstAudioFilter, - GST_TYPE_AUDIO_FX_BASE_FIR_FILTER, DEBUG_INIT); - -static void gst_audio_wsincband_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_audio_wsincband_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_audio_wsincband_finalize (GObject * object); - -static gboolean gst_audio_wsincband_setup (GstAudioFilter * base, - GstRingBufferSpec * format); - -/* Element class */ -static void -gst_audio_wsincband_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details_simple (element_class, - "Band pass & band reject filter", "Filter/Effect/Audio", - "Band pass and band reject windowed sinc filter", - "Thomas Vander Stichele , " - "Steven W. Smith, " - "Dreamlab Technologies Ltd. , " - "Sebastian Dröge "); -} - -static void -gst_audio_wsincband_class_init (GstAudioWSincBandClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass; - - gobject_class->set_property = gst_audio_wsincband_set_property; - gobject_class->get_property = gst_audio_wsincband_get_property; - gobject_class->finalize = gst_audio_wsincband_finalize; - - /* FIXME: Don't use the complete possible range but restrict the upper boundary - * so automatically generated UIs can use a slider */ - g_object_class_install_property (gobject_class, PROP_LOWER_FREQUENCY, - g_param_spec_float ("lower-frequency", "Lower Frequency", - "Cut-off lower frequency (Hz)", 0.0, 100000.0, 0, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_UPPER_FREQUENCY, - g_param_spec_float ("upper-frequency", "Upper Frequency", - "Cut-off upper frequency (Hz)", 0.0, 100000.0, 0, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_LENGTH, - g_param_spec_int ("length", "Length", - "Filter kernel length, will be rounded to the next odd number", 3, - 50000, 101, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_MODE, - g_param_spec_enum ("mode", "Mode", - "Band pass or band reject mode", GST_TYPE_AUDIO_WSINC_BAND_MODE, - MODE_BAND_PASS, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_WINDOW, - g_param_spec_enum ("window", "Window", - "Window function to use", GST_TYPE_AUDIO_WSINC_BAND_WINDOW, - WINDOW_HAMMING, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - - filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_wsincband_setup); -} - -static void -gst_audio_wsincband_init (GstAudioWSincBand * self, - GstAudioWSincBandClass * g_class) -{ - self->kernel_length = 101; - self->lower_frequency = 0.0; - self->upper_frequency = 0.0; - self->mode = MODE_BAND_PASS; - self->window = WINDOW_HAMMING; - - self->lock = g_mutex_new (); -} - -static void -gst_audio_wsincband_build_kernel (GstAudioWSincBand * self) -{ - gint i = 0; - gdouble sum = 0.0; - gint len = 0; - gdouble *kernel_lp, *kernel_hp; - gdouble w; - gdouble *kernel; - - len = self->kernel_length; - - if (GST_AUDIO_FILTER (self)->format.rate == 0) { - GST_DEBUG ("rate not set yet"); - return; - } - - if (GST_AUDIO_FILTER (self)->format.channels == 0) { - GST_DEBUG ("channels not set yet"); - return; - } - - /* Clamp frequencies */ - self->lower_frequency = - CLAMP (self->lower_frequency, 0.0, - GST_AUDIO_FILTER (self)->format.rate / 2); - self->upper_frequency = - CLAMP (self->upper_frequency, 0.0, - GST_AUDIO_FILTER (self)->format.rate / 2); - if (self->lower_frequency > self->upper_frequency) { - gint tmp = self->lower_frequency; - - self->lower_frequency = self->upper_frequency; - self->upper_frequency = tmp; - } - - GST_DEBUG ("gst_audio_wsincband: initializing filter kernel of length %d " - "with lower frequency %.2lf Hz " - ", upper frequency %.2lf Hz for mode %s", - len, self->lower_frequency, self->upper_frequency, - (self->mode == MODE_BAND_PASS) ? "band-pass" : "band-reject"); - - /* fill the lp kernel */ - w = 2 * M_PI * (self->lower_frequency / GST_AUDIO_FILTER (self)->format.rate); - kernel_lp = g_new (gdouble, len); - for (i = 0; i < len; ++i) { - if (i == len / 2) - kernel_lp[i] = w; - else - kernel_lp[i] = sin (w * (i - len / 2)) - / (i - len / 2); - /* Windowing */ - if (self->window == WINDOW_HAMMING) - kernel_lp[i] *= (0.54 - 0.46 * cos (2 * M_PI * i / len)); - else - kernel_lp[i] *= - (0.42 - 0.5 * cos (2 * M_PI * i / len) + - 0.08 * cos (4 * M_PI * i / len)); - } - - /* normalize for unity gain at DC */ - sum = 0.0; - for (i = 0; i < len; ++i) - sum += kernel_lp[i]; - for (i = 0; i < len; ++i) - kernel_lp[i] /= sum; - - /* fill the hp kernel */ - w = 2 * M_PI * (self->upper_frequency / GST_AUDIO_FILTER (self)->format.rate); - kernel_hp = g_new (gdouble, len); - for (i = 0; i < len; ++i) { - if (i == len / 2) - kernel_hp[i] = w; - else - kernel_hp[i] = sin (w * (i - len / 2)) - / (i - len / 2); - /* Windowing */ - if (self->window == WINDOW_HAMMING) - kernel_hp[i] *= (0.54 - 0.46 * cos (2 * M_PI * i / len)); - else - kernel_hp[i] *= - (0.42 - 0.5 * cos (2 * M_PI * i / len) + - 0.08 * cos (4 * M_PI * i / len)); - } - - /* normalize for unity gain at DC */ - sum = 0.0; - for (i = 0; i < len; ++i) - sum += kernel_hp[i]; - for (i = 0; i < len; ++i) - kernel_hp[i] /= sum; - - /* do spectral inversion to go from lowpass to highpass */ - for (i = 0; i < len; ++i) - kernel_hp[i] = -kernel_hp[i]; - kernel_hp[len / 2] += 1; - - /* combine the two kernels */ - kernel = g_new (gdouble, len); - - for (i = 0; i < len; ++i) - kernel[i] = kernel_lp[i] + kernel_hp[i]; - - /* free the helper kernels */ - g_free (kernel_lp); - g_free (kernel_hp); - - /* do spectral inversion to go from bandreject to bandpass - * if specified */ - if (self->mode == MODE_BAND_PASS) { - for (i = 0; i < len; ++i) - kernel[i] = -kernel[i]; - kernel[len / 2] += 1; - } - - gst_audio_fx_base_fir_filter_set_kernel (GST_AUDIO_FX_BASE_FIR_FILTER (self), - kernel, self->kernel_length, (len - 1) / 2); -} - -/* GstAudioFilter vmethod implementations */ - -/* get notified of caps and plug in the correct process function */ -static gboolean -gst_audio_wsincband_setup (GstAudioFilter * base, GstRingBufferSpec * format) -{ - GstAudioWSincBand *self = GST_AUDIO_WSINC_BAND (base); - - gst_audio_wsincband_build_kernel (self); - - return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, format); -} - -static void -gst_audio_wsincband_finalize (GObject * object) -{ - GstAudioWSincBand *self = GST_AUDIO_WSINC_BAND (object); - - g_mutex_free (self->lock); - self->lock = NULL; - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_audio_wsincband_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAudioWSincBand *self = GST_AUDIO_WSINC_BAND (object); - - g_return_if_fail (GST_IS_AUDIO_WSINC_BAND (self)); - - switch (prop_id) { - case PROP_LENGTH:{ - gint val; - - g_mutex_lock (self->lock); - val = g_value_get_int (value); - if (val % 2 == 0) - val++; - - if (val != self->kernel_length) { - gst_audio_fx_base_fir_filter_push_residue (GST_AUDIO_FX_BASE_FIR_FILTER - (self)); - self->kernel_length = val; - gst_audio_wsincband_build_kernel (self); - } - g_mutex_unlock (self->lock); - break; - } - case PROP_LOWER_FREQUENCY: - g_mutex_lock (self->lock); - self->lower_frequency = g_value_get_float (value); - gst_audio_wsincband_build_kernel (self); - g_mutex_unlock (self->lock); - break; - case PROP_UPPER_FREQUENCY: - g_mutex_lock (self->lock); - self->upper_frequency = g_value_get_float (value); - gst_audio_wsincband_build_kernel (self); - g_mutex_unlock (self->lock); - break; - case PROP_MODE: - g_mutex_lock (self->lock); - self->mode = g_value_get_enum (value); - gst_audio_wsincband_build_kernel (self); - g_mutex_unlock (self->lock); - break; - case PROP_WINDOW: - g_mutex_lock (self->lock); - self->window = g_value_get_enum (value); - gst_audio_wsincband_build_kernel (self); - g_mutex_unlock (self->lock); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_audio_wsincband_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAudioWSincBand *self = GST_AUDIO_WSINC_BAND (object); - - switch (prop_id) { - case PROP_LENGTH: - g_value_set_int (value, self->kernel_length); - break; - case PROP_LOWER_FREQUENCY: - g_value_set_float (value, self->lower_frequency); - break; - case PROP_UPPER_FREQUENCY: - g_value_set_float (value, self->upper_frequency); - break; - case PROP_MODE: - g_value_set_enum (value, self->mode); - break; - case PROP_WINDOW: - g_value_set_enum (value, self->window); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiowsincband.h --- a/gst_plugins_good/gst/audiofx/audiowsincband.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* -*- c-basic-offset: 2 -*- - * - * GStreamer - * Copyright (C) 1999-2001 Erik Walthinsen - * 2006 Dreamlab Technologies Ltd. - * 2007-2009 Sebastian Dröge - * - * 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. - * - * - * this windowed sinc filter is taken from the freely downloadable DSP book, - * "The Scientist and Engineer's Guide to Digital Signal Processing", - * chapter 16 - * available at http://www.dspguide.com/ - * - */ - -#ifndef __GST_AUDIO_WSINC_BAND_H__ -#define __GST_AUDIO_WSINC_BAND_H__ - -#include -#include -#include - -#include "audiofxbasefirfilter.h" - -G_BEGIN_DECLS - -#define GST_TYPE_AUDIO_WSINC_BAND \ - (gst_audio_wsincband_get_type()) -#define GST_AUDIO_WSINC_BAND(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_WSINC_BAND,GstAudioWSincBand)) -#define GST_AUDIO_WSINC_BAND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_WSINC_BAND,GstAudioWSincBandClass)) -#define GST_IS_AUDIO_WSINC_BAND(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_WSINC_BAND)) -#define GST_IS_AUDIO_WSINC_BAND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_WSINC_BAND)) - -typedef struct _GstAudioWSincBand GstAudioWSincBand; -typedef struct _GstAudioWSincBandClass GstAudioWSincBandClass; - -/** - * GstAudioWSincBand: - * - * Opaque data structure. - */ -struct _GstAudioWSincBand { - GstAudioFXBaseFIRFilter parent; - - gint mode; - gint window; - gfloat lower_frequency, upper_frequency; - gint kernel_length; /* length of the filter kernel */ - - /* < private > */ - GMutex *lock; -}; - -struct _GstAudioWSincBandClass { - GstAudioFilterClass parent; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_audio_wsincband_get_type (void); - -G_END_DECLS - -#endif /* __GST_AUDIO_WSINC_BAND_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiowsinclimit.c --- a/gst_plugins_good/gst/audiofx/audiowsinclimit.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,373 +0,0 @@ -/* -*- c-basic-offset: 2 -*- - * - * GStreamer - * Copyright (C) 1999-2001 Erik Walthinsen - * 2006 Dreamlab Technologies Ltd. - * 2007-2009 Sebastian Dröge - * - * 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. - * - * - * this windowed sinc filter is taken from the freely downloadable DSP book, - * "The Scientist and Engineer's Guide to Digital Signal Processing", - * chapter 16 - * available at http://www.dspguide.com/ - * - */ - -/** - * SECTION:element-audiowsinclimit - * - * Attenuates all frequencies above the cutoff frequency (low-pass) or all frequencies below the - * cutoff frequency (high-pass). The length parameter controls the rolloff, the window parameter - * controls rolloff and stopband attenuation. The Hamming window provides a faster rolloff but a bit - * worse stopband attenuation, the other way around for the Blackman window. - * - * This element has the advantage over the Chebyshev lowpass and highpass filter that it has - * a much better rolloff when using a larger kernel size and almost linear phase. The only - * disadvantage is the much slower execution time with larger kernels. - * - * - * Example launch line - * |[ - * gst-launch audiotestsrc freq=1500 ! audioconvert ! audiowsinclimit mode=low-pass frequency=1000 length=501 ! audioconvert ! alsasink - * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiowsinclimit mode=high-pass frequency=15000 length=501 ! audioconvert ! alsasink - * gst-launch audiotestsrc wave=white-noise ! audioconvert ! audiowsinclimit mode=low-pass frequency=1000 length=10001 window=blackman ! audioconvert ! alsasink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include - -#include "audiowsinclimit.h" - -#define GST_CAT_DEFAULT gst_audio_wsinclimit_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -enum -{ - PROP_0, - PROP_LENGTH, - PROP_FREQUENCY, - PROP_MODE, - PROP_WINDOW -}; - -enum -{ - MODE_LOW_PASS = 0, - MODE_HIGH_PASS -}; - -#define GST_TYPE_AUDIO_WSINC_LIMIT_MODE (gst_audio_wsinclimit_mode_get_type ()) -static GType -gst_audio_wsinclimit_mode_get_type (void) -{ - static GType gtype = 0; - - if (gtype == 0) { - static const GEnumValue values[] = { - {MODE_LOW_PASS, "Low pass (default)", - "low-pass"}, - {MODE_HIGH_PASS, "High pass", - "high-pass"}, - {0, NULL, NULL} - }; - - gtype = g_enum_register_static ("GstAudioWSincLimitMode", values); - } - return gtype; -} - -enum -{ - WINDOW_HAMMING = 0, - WINDOW_BLACKMAN -}; - -#define GST_TYPE_AUDIO_WSINC_LIMIT_WINDOW (gst_audio_wsinclimit_window_get_type ()) -static GType -gst_audio_wsinclimit_window_get_type (void) -{ - static GType gtype = 0; - - if (gtype == 0) { - static const GEnumValue values[] = { - {WINDOW_HAMMING, "Hamming window (default)", - "hamming"}, - {WINDOW_BLACKMAN, "Blackman window", - "blackman"}, - {0, NULL, NULL} - }; - - gtype = g_enum_register_static ("GstAudioWSincLimitWindow", values); - } - return gtype; -} - -#define DEBUG_INIT(bla) \ - GST_DEBUG_CATEGORY_INIT (gst_audio_wsinclimit_debug, "audiowsinclimit", 0, \ - "Low-pass and High-pass Windowed sinc filter plugin"); - -GST_BOILERPLATE_FULL (GstAudioWSincLimit, gst_audio_wsinclimit, GstAudioFilter, - GST_TYPE_AUDIO_FX_BASE_FIR_FILTER, DEBUG_INIT); - -static void gst_audio_wsinclimit_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_audio_wsinclimit_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static void gst_audio_wsinclimit_finalize (GObject * object); - -static gboolean gst_audio_wsinclimit_setup (GstAudioFilter * base, - GstRingBufferSpec * format); - -/* Element class */ - -static void -gst_audio_wsinclimit_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_set_details_simple (element_class, - "Low pass & high pass filter", "Filter/Effect/Audio", - "Low pass and high pass windowed sinc filter", - "Thomas Vander Stichele , " - "Steven W. Smith, " - "Dreamlab Technologies Ltd. , " - "Sebastian Dröge "); -} - -static void -gst_audio_wsinclimit_class_init (GstAudioWSincLimitClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass; - - gobject_class->set_property = gst_audio_wsinclimit_set_property; - gobject_class->get_property = gst_audio_wsinclimit_get_property; - gobject_class->finalize = gst_audio_wsinclimit_finalize; - - /* FIXME: Don't use the complete possible range but restrict the upper boundary - * so automatically generated UIs can use a slider */ - g_object_class_install_property (gobject_class, PROP_FREQUENCY, - g_param_spec_float ("cutoff", "Cutoff", - "Cut-off Frequency (Hz)", 0.0, 100000.0, 0.0, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (gobject_class, PROP_LENGTH, - g_param_spec_int ("length", "Length", - "Filter kernel length, will be rounded to the next odd number", - 3, 50000, 101, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_MODE, - g_param_spec_enum ("mode", "Mode", - "Low pass or high pass mode", GST_TYPE_AUDIO_WSINC_LIMIT_MODE, - MODE_LOW_PASS, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property (gobject_class, PROP_WINDOW, - g_param_spec_enum ("window", "Window", - "Window function to use", GST_TYPE_AUDIO_WSINC_LIMIT_WINDOW, - WINDOW_HAMMING, - G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)); - - filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_wsinclimit_setup); -} - -static void -gst_audio_wsinclimit_init (GstAudioWSincLimit * self, - GstAudioWSincLimitClass * g_class) -{ - self->mode = MODE_LOW_PASS; - self->window = WINDOW_HAMMING; - self->kernel_length = 101; - self->cutoff = 0.0; - - self->lock = g_mutex_new (); -} - -static void -gst_audio_wsinclimit_build_kernel (GstAudioWSincLimit * self) -{ - gint i = 0; - gdouble sum = 0.0; - gint len = 0; - gdouble w; - gdouble *kernel = NULL; - - len = self->kernel_length; - - if (GST_AUDIO_FILTER (self)->format.rate == 0) { - GST_DEBUG ("rate not set yet"); - return; - } - - if (GST_AUDIO_FILTER (self)->format.channels == 0) { - GST_DEBUG ("channels not set yet"); - return; - } - - /* Clamp cutoff frequency between 0 and the nyquist frequency */ - self->cutoff = - CLAMP (self->cutoff, 0.0, GST_AUDIO_FILTER (self)->format.rate / 2); - - GST_DEBUG ("gst_audio_wsinclimit_: initializing filter kernel of length %d " - "with cutoff %.2lf Hz " - "for mode %s", - len, self->cutoff, - (self->mode == MODE_LOW_PASS) ? "low-pass" : "high-pass"); - - /* fill the kernel */ - w = 2 * M_PI * (self->cutoff / GST_AUDIO_FILTER (self)->format.rate); - - kernel = g_new (gdouble, len); - - for (i = 0; i < len; ++i) { - if (i == len / 2) - kernel[i] = w; - else - kernel[i] = sin (w * (i - len / 2)) / (i - len / 2); - /* windowing */ - if (self->window == WINDOW_HAMMING) - kernel[i] *= (0.54 - 0.46 * cos (2 * M_PI * i / len)); - else - kernel[i] *= (0.42 - 0.5 * cos (2 * M_PI * i / len) + - 0.08 * cos (4 * M_PI * i / len)); - } - - /* normalize for unity gain at DC */ - for (i = 0; i < len; ++i) - sum += kernel[i]; - for (i = 0; i < len; ++i) - kernel[i] /= sum; - - /* convert to highpass if specified */ - if (self->mode == MODE_HIGH_PASS) { - for (i = 0; i < len; ++i) - kernel[i] = -kernel[i]; - kernel[len / 2] += 1.0; - } - - gst_audio_fx_base_fir_filter_set_kernel (GST_AUDIO_FX_BASE_FIR_FILTER (self), - kernel, self->kernel_length, (len - 1) / 2); -} - -/* GstAudioFilter vmethod implementations */ - -/* get notified of caps and plug in the correct process function */ -static gboolean -gst_audio_wsinclimit_setup (GstAudioFilter * base, GstRingBufferSpec * format) -{ - GstAudioWSincLimit *self = GST_AUDIO_WSINC_LIMIT (base); - - gst_audio_wsinclimit_build_kernel (self); - - return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, format); -} - -static void -gst_audio_wsinclimit_finalize (GObject * object) -{ - GstAudioWSincLimit *self = GST_AUDIO_WSINC_LIMIT (object); - - g_mutex_free (self->lock); - self->lock = NULL; - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_audio_wsinclimit_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAudioWSincLimit *self = GST_AUDIO_WSINC_LIMIT (object); - - g_return_if_fail (GST_IS_AUDIO_WSINC_LIMIT (self)); - - switch (prop_id) { - case PROP_LENGTH:{ - gint val; - - g_mutex_lock (self->lock); - val = g_value_get_int (value); - if (val % 2 == 0) - val++; - - if (val != self->kernel_length) { - gst_audio_fx_base_fir_filter_push_residue (GST_AUDIO_FX_BASE_FIR_FILTER - (self)); - self->kernel_length = val; - gst_audio_wsinclimit_build_kernel (self); - } - g_mutex_unlock (self->lock); - break; - } - case PROP_FREQUENCY: - g_mutex_lock (self->lock); - self->cutoff = g_value_get_float (value); - gst_audio_wsinclimit_build_kernel (self); - g_mutex_unlock (self->lock); - break; - case PROP_MODE: - g_mutex_lock (self->lock); - self->mode = g_value_get_enum (value); - gst_audio_wsinclimit_build_kernel (self); - g_mutex_unlock (self->lock); - break; - case PROP_WINDOW: - g_mutex_lock (self->lock); - self->window = g_value_get_enum (value); - gst_audio_wsinclimit_build_kernel (self); - g_mutex_unlock (self->lock); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_audio_wsinclimit_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAudioWSincLimit *self = GST_AUDIO_WSINC_LIMIT (object); - - switch (prop_id) { - case PROP_LENGTH: - g_value_set_int (value, self->kernel_length); - break; - case PROP_FREQUENCY: - g_value_set_float (value, self->cutoff); - break; - case PROP_MODE: - g_value_set_enum (value, self->mode); - break; - case PROP_WINDOW: - g_value_set_enum (value, self->window); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/audiowsinclimit.h --- a/gst_plugins_good/gst/audiofx/audiowsinclimit.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* -*- c-basic-offset: 2 -*- - * - * GStreamer - * Copyright (C) 1999-2001 Erik Walthinsen - * 2006 Dreamlab Technologies Ltd. - * 2007-2009 Sebastian Dröge - * - * 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. - * - * - * this windowed sinc filter is taken from the freely downloadable DSP book, - * "The Scientist and Engineer's Guide to Digital Signal Processing", - * chapter 16 - * available at http://www.dspguide.com/ - * - */ - -#ifndef __GST_AUDIO_WSINC_LIMIT_H__ -#define __GST_AUDIO_WSINC_LIMIT_H__ - -#include -#include -#include - -#include "audiofxbasefirfilter.h" - -G_BEGIN_DECLS - -#define GST_TYPE_AUDIO_WSINC_LIMIT \ - (gst_audio_wsinclimit_get_type()) -#define GST_AUDIO_WSINC_LIMIT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_WSINC_LIMIT,GstAudioWSincLimit)) -#define GST_AUDIO_WSINC_LIMIT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_WSINC_LIMIT,GstAudioWSincLimitClass)) -#define GST_IS_AUDIO_WSINC_LIMIT(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_WSINC_LIMIT)) -#define GST_IS_AUDIO_WSINC_LIMIT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_WSINC_LIMIT)) - -typedef struct _GstAudioWSincLimit GstAudioWSincLimit; -typedef struct _GstAudioWSincLimitClass GstAudioWSincLimitClass; - -/** - * GstAudioWSincLimit: - * - * Opaque data structure. - */ -struct _GstAudioWSincLimit { - GstAudioFXBaseFIRFilter parent; - - gint mode; - gint window; - gfloat cutoff; - gint kernel_length; - - /* < private > */ - GMutex *lock; -}; - -struct _GstAudioWSincLimitClass { - GstAudioFXBaseFIRFilterClass parent; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_audio_wsinclimit_get_type (void); - -G_END_DECLS - -#endif /* __GST_AUDIO_WSINC_LIMIT_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/audiofx/math_compat.h --- a/gst_plugins_good/gst/audiofx/math_compat.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * GStreamer - * Copyright (C) 2008 Sebastian Dröge - * - * 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. - */ - -#ifndef __MATH_COMPAT_H__ -#define __MATH_COMPAT_H__ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#ifndef HAVE_ASINH -static inline gdouble -asinh (gdouble x) -{ - return log(x + sqrt (x * x + 1)); -} -#endif - -#ifndef HAVE_SINH -static inline gdouble -sinh (gdouble x) -{ - return 0.5 * (exp (x) - exp (-x)); -} -#endif - -#ifndef HAVE_COSH -static inline gdouble -cosh (gdouble x) -{ - return 0.5 * (exp (x) + exp (-x)); -} -#endif - -#endif /* __MATH_COMPAT_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/auparse/gstauparse.c --- a/gst_plugins_good/gst/auparse/gstauparse.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,726 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2006> Tim-Philipp Müller - * - * 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. - */ - -/** - * SECTION:element-auparse - * - * Parses .au files mostly originating from sun os based computers. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#include "gstauparse.h" -#include - -GST_DEBUG_CATEGORY_STATIC (auparse_debug); -#define GST_CAT_DEFAULT (auparse_debug) - -static const GstElementDetails gst_au_parse_details = -GST_ELEMENT_DETAILS ("AU audio demuxer", - "Codec/Demuxer/Audio", - "Parse an .au file into raw audio", - "Erik Walthinsen "); - -static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-au") - ); - -#define GST_AU_PARSE_ALAW_PAD_TEMPLATE_CAPS \ - "audio/x-alaw, " \ - "rate = (int) [ 8000, 192000 ], " \ - "channels = (int) [ 1, 2 ]" - -#define GST_AU_PARSE_MULAW_PAD_TEMPLATE_CAPS \ - "audio/x-mulaw, " \ - "rate = (int) [ 8000, 192000 ], " \ - "channels = (int) [ 1, 2 ]" - -/* Nothing to decode those ADPCM streams for now */ -#define GST_AU_PARSE_ADPCM_PAD_TEMPLATE_CAPS \ - "audio/x-adpcm, " \ - "layout = (string) { g721, g722, g723_3, g723_5 }" - -static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_SOMETIMES, - GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; " - GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS ";" - GST_AU_PARSE_ALAW_PAD_TEMPLATE_CAPS ";" - GST_AU_PARSE_MULAW_PAD_TEMPLATE_CAPS ";" - GST_AU_PARSE_ADPCM_PAD_TEMPLATE_CAPS)); - - -static void gst_au_parse_dispose (GObject * object); -static GstFlowReturn gst_au_parse_chain (GstPad * pad, GstBuffer * buf); -static GstStateChangeReturn gst_au_parse_change_state (GstElement * element, - GstStateChange transition); -static void gst_au_parse_reset (GstAuParse * auparse); -static gboolean gst_au_parse_remove_srcpad (GstAuParse * auparse); -static gboolean gst_au_parse_add_srcpad (GstAuParse * auparse, GstCaps * caps); -static gboolean gst_au_parse_src_query (GstPad * pad, GstQuery * query); -static gboolean gst_au_parse_src_event (GstPad * pad, GstEvent * event); -static gboolean gst_au_parse_sink_event (GstPad * pad, GstEvent * event); - -GST_BOILERPLATE (GstAuParse, gst_au_parse, GstElement, GST_TYPE_ELEMENT); - -static void -gst_au_parse_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_template)); - gst_element_class_set_details (element_class, &gst_au_parse_details); - - GST_DEBUG_CATEGORY_INIT (auparse_debug, "auparse", 0, ".au parser"); -} - -static void -gst_au_parse_class_init (GstAuParseClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - gobject_class->dispose = gst_au_parse_dispose; - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_au_parse_change_state); -} - -static void -gst_au_parse_init (GstAuParse * auparse, GstAuParseClass * klass) -{ - auparse->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); - gst_pad_set_chain_function (auparse->sinkpad, - GST_DEBUG_FUNCPTR (gst_au_parse_chain)); - gst_pad_set_event_function (auparse->sinkpad, - GST_DEBUG_FUNCPTR (gst_au_parse_sink_event)); - gst_element_add_pad (GST_ELEMENT (auparse), auparse->sinkpad); - - auparse->srcpad = NULL; - auparse->adapter = gst_adapter_new (); - gst_au_parse_reset (auparse); -} - -static void -gst_au_parse_dispose (GObject * object) -{ - GstAuParse *au = GST_AU_PARSE (object); - - if (au->adapter != NULL) { - g_object_unref (au->adapter); - au->adapter = NULL; - } - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static void -gst_au_parse_reset (GstAuParse * auparse) -{ - gst_au_parse_remove_srcpad (auparse); - - auparse->offset = 0; - auparse->buffer_offset = 0; - auparse->encoding = 0; - auparse->samplerate = 0; - auparse->channels = 0; - - gst_adapter_clear (auparse->adapter); - - /* gst_segment_init (&auparse->segment, GST_FORMAT_TIME); */ -} - -static gboolean -gst_au_parse_add_srcpad (GstAuParse * auparse, GstCaps * new_caps) -{ - if (auparse->src_caps && gst_caps_is_equal (new_caps, auparse->src_caps)) { - GST_LOG_OBJECT (auparse, "same caps, nothing to do"); - return TRUE; - } - - gst_caps_replace (&auparse->src_caps, new_caps); - if (auparse->srcpad != NULL) { - GST_DEBUG_OBJECT (auparse, "Changing src pad caps to %" GST_PTR_FORMAT, - auparse->src_caps); - gst_pad_set_caps (auparse->srcpad, auparse->src_caps); - } - - if (auparse->srcpad == NULL) { - auparse->srcpad = gst_pad_new_from_static_template (&src_template, "src"); - g_return_val_if_fail (auparse->srcpad != NULL, FALSE); - -#if 0 - gst_pad_set_query_type_function (auparse->srcpad, - GST_DEBUG_FUNCPTR (gst_au_parse_src_get_query_types)); -#endif - gst_pad_set_query_function (auparse->srcpad, - GST_DEBUG_FUNCPTR (gst_au_parse_src_query)); - gst_pad_set_event_function (auparse->srcpad, - GST_DEBUG_FUNCPTR (gst_au_parse_src_event)); - - gst_pad_use_fixed_caps (auparse->srcpad); - gst_pad_set_active (auparse->srcpad, TRUE); - - if (auparse->src_caps) - gst_pad_set_caps (auparse->srcpad, auparse->src_caps); - - GST_DEBUG_OBJECT (auparse, "Adding src pad with caps %" GST_PTR_FORMAT, - auparse->src_caps); - - gst_object_ref (auparse->srcpad); - if (!gst_element_add_pad (GST_ELEMENT (auparse), auparse->srcpad)) - return FALSE; - gst_element_no_more_pads (GST_ELEMENT (auparse)); - } - - return TRUE; -} - -static gboolean -gst_au_parse_remove_srcpad (GstAuParse * auparse) -{ - gboolean res = TRUE; - - if (auparse->srcpad != NULL) { - GST_DEBUG_OBJECT (auparse, "Removing src pad"); - res = gst_element_remove_pad (GST_ELEMENT (auparse), auparse->srcpad); - g_return_val_if_fail (res != FALSE, FALSE); - gst_object_unref (auparse->srcpad); - auparse->srcpad = NULL; - } - - return res; -} - -static GstFlowReturn -gst_au_parse_parse_header (GstAuParse * auparse) -{ - GstCaps *tempcaps; - guint32 size; - guint8 *head; - gchar layout[7] = { 0, }; - gint law = 0, depth = 0, ieee = 0; - - head = (guint8 *) gst_adapter_peek (auparse->adapter, 24); - g_assert (head != NULL); - - GST_DEBUG_OBJECT (auparse, "[%c%c%c%c]", head[0], head[1], head[2], head[3]); - - switch (GST_READ_UINT32_BE (head)) { - /* normal format is big endian (au is a Sparc format) */ - case 0x2e736e64:{ /* ".snd" */ - auparse->endianness = G_BIG_ENDIAN; - break; - } - /* and of course, someone had to invent a little endian - * version. Used by DEC systems. */ - case 0x646e732e: /* dns. */ - case 0x0064732e:{ /* other source say it is "dns." */ - auparse->endianness = G_LITTLE_ENDIAN; - break; - } - default:{ - goto unknown_header; - } - } - - auparse->offset = GST_READ_UINT32_BE (head + 4); - /* Do not trust size, could be set to -1 : unknown */ - size = GST_READ_UINT32_BE (head + 8); - auparse->encoding = GST_READ_UINT32_BE (head + 12); - auparse->samplerate = GST_READ_UINT32_BE (head + 16); - auparse->channels = GST_READ_UINT32_BE (head + 20); - - if (auparse->samplerate < 8000 || auparse->samplerate > 192000) - goto unsupported_sample_rate; - - if (auparse->channels < 1 || auparse->channels > 2) - goto unsupported_number_of_channels; - - GST_DEBUG_OBJECT (auparse, "offset %" G_GINT64_FORMAT ", size %u, " - "encoding %u, frequency %u, channels %u", auparse->offset, size, - auparse->encoding, auparse->samplerate, auparse->channels); - - /* Docs: - * http://www.opengroup.org/public/pubs/external/auformat.html - * http://astronomy.swin.edu.au/~pbourke/dataformats/au/ - * Solaris headers : /usr/include/audio/au.h - * libsndfile : src/au.c - * - * Samples : - * http://www.tsp.ece.mcgill.ca/MMSP/Documents/AudioFormats/AU/Samples.html - */ - - switch (auparse->encoding) { - case 1: /* 8-bit ISDN mu-law G.711 */ - law = 1; - depth = 8; - break; - case 27: /* 8-bit ISDN A-law G.711 */ - law = 2; - depth = 8; - break; - - case 2: /* 8-bit linear PCM */ - depth = 8; - break; - case 3: /* 16-bit linear PCM */ - depth = 16; - break; - case 4: /* 24-bit linear PCM */ - depth = 24; - break; - case 5: /* 32-bit linear PCM */ - depth = 32; - break; - - case 6: /* 32-bit IEEE floating point */ - ieee = 1; - depth = 32; - break; - case 7: /* 64-bit IEEE floating point */ - ieee = 1; - depth = 64; - break; - - case 23: /* 4-bit CCITT G.721 ADPCM 32kbps -> modplug/libsndfile (compressed 8-bit mu-law) */ - strcpy (layout, "g721"); - break; - case 24: /* 8-bit CCITT G.722 ADPCM -> rtp */ - strcpy (layout, "g722"); - break; - case 25: /* 3-bit CCITT G.723.3 ADPCM 24kbps -> rtp/xine/modplug/libsndfile */ - strcpy (layout, "g723_3"); - break; - case 26: /* 5-bit CCITT G.723.5 ADPCM 40kbps -> rtp/xine/modplug/libsndfile */ - strcpy (layout, "g723_5"); - break; - - case 8: /* Fragmented sample data */ - case 9: /* AU_ENCODING_NESTED */ - - case 10: /* DSP program */ - case 11: /* DSP 8-bit fixed point */ - case 12: /* DSP 16-bit fixed point */ - case 13: /* DSP 24-bit fixed point */ - case 14: /* DSP 32-bit fixed point */ - - case 16: /* AU_ENCODING_DISPLAY : non-audio display data */ - case 17: /* AU_ENCODING_MULAW_SQUELCH */ - - case 18: /* 16-bit linear with emphasis */ - case 19: /* 16-bit linear compressed (NeXT) */ - case 20: /* 16-bit linear with emphasis and compression */ - - case 21: /* Music kit DSP commands */ - case 22: /* Music kit DSP commands samples */ - - default: - goto unknown_format; - } - - if (law) { - tempcaps = - gst_caps_new_simple ((law == 1) ? "audio/x-mulaw" : "audio/x-alaw", - "rate", G_TYPE_INT, auparse->samplerate, - "channels", G_TYPE_INT, auparse->channels, NULL); - auparse->sample_size = auparse->channels; - } else if (ieee) { - tempcaps = gst_caps_new_simple ("audio/x-raw-float", - "rate", G_TYPE_INT, auparse->samplerate, - "channels", G_TYPE_INT, auparse->channels, - "endianness", G_TYPE_INT, auparse->endianness, - "width", G_TYPE_INT, depth, NULL); - auparse->sample_size = auparse->channels * depth / 8; - } else if (layout[0]) { - tempcaps = gst_caps_new_simple ("audio/x-adpcm", - "layout", G_TYPE_STRING, layout, NULL); - auparse->sample_size = 0; - } else { - tempcaps = gst_caps_new_simple ("audio/x-raw-int", - "rate", G_TYPE_INT, auparse->samplerate, - "channels", G_TYPE_INT, auparse->channels, - "endianness", G_TYPE_INT, auparse->endianness, - "depth", G_TYPE_INT, depth, "width", G_TYPE_INT, depth, - /* FIXME: signed TRUE even for 8-bit PCM? */ - "signed", G_TYPE_BOOLEAN, TRUE, NULL); - auparse->sample_size = auparse->channels * depth / 8; - } - - GST_DEBUG_OBJECT (auparse, "sample_size=%d", auparse->sample_size); - - if (!gst_au_parse_add_srcpad (auparse, tempcaps)) - goto add_pad_failed; - - GST_DEBUG_OBJECT (auparse, "offset=%" G_GINT64_FORMAT, auparse->offset); - gst_adapter_flush (auparse->adapter, auparse->offset); - - gst_caps_unref (tempcaps); - return GST_FLOW_OK; - - /* ERRORS */ -unknown_header: - { - GST_ELEMENT_ERROR (auparse, STREAM, WRONG_TYPE, (NULL), (NULL)); - return GST_FLOW_ERROR; - } -unsupported_sample_rate: - { - GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL), - ("Unsupported samplerate: %u", auparse->samplerate)); - return GST_FLOW_ERROR; - } -unsupported_number_of_channels: - { - GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL), - ("Unsupported number of channels: %u", auparse->channels)); - return GST_FLOW_ERROR; - } -unknown_format: - { - GST_ELEMENT_ERROR (auparse, STREAM, FORMAT, (NULL), - ("Unsupported encoding: %u", auparse->encoding)); - return GST_FLOW_ERROR; - } -add_pad_failed: - { - GST_ELEMENT_ERROR (auparse, STREAM, FAILED, (NULL), - ("Failed to add srcpad")); - gst_caps_unref (tempcaps); - return GST_FLOW_ERROR; - } -} - -#define AU_HEADER_SIZE 24 - -static GstFlowReturn -gst_au_parse_chain (GstPad * pad, GstBuffer * buf) -{ - GstFlowReturn ret = GST_FLOW_OK; - GstAuParse *auparse; - gint avail, sendnow = 0; - - auparse = GST_AU_PARSE (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (auparse, "got buffer of size %u", GST_BUFFER_SIZE (buf)); - - gst_adapter_push (auparse->adapter, buf); - buf = NULL; - - /* if we haven't seen any data yet... */ - if (auparse->srcpad == NULL) { - if (gst_adapter_available (auparse->adapter) < AU_HEADER_SIZE) { - GST_DEBUG_OBJECT (auparse, "need more data to parse header"); - ret = GST_FLOW_OK; - goto out; - } - - ret = gst_au_parse_parse_header (auparse); - if (ret != GST_FLOW_OK) - goto out; - - gst_pad_push_event (auparse->srcpad, - gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_DEFAULT, - 0, GST_CLOCK_TIME_NONE, 0)); - } - - avail = gst_adapter_available (auparse->adapter); - - if (auparse->sample_size > 0) { - /* Ensure we push a buffer that's a multiple of the frame size downstream */ - sendnow = avail - (avail % auparse->sample_size); - } else { - /* It's something non-trivial (such as ADPCM), we don't understand it, so - * just push downstream and assume it will know what to do with it */ - sendnow = avail; - } - - if (sendnow > 0) { - GstBuffer *outbuf; - const guint8 *data; - - ret = gst_pad_alloc_buffer_and_set_caps (auparse->srcpad, - auparse->buffer_offset, sendnow, GST_PAD_CAPS (auparse->srcpad), - &outbuf); - - if (ret != GST_FLOW_OK) { - GST_DEBUG_OBJECT (auparse, "pad alloc flow: %s", gst_flow_get_name (ret)); - goto out; - } - - data = gst_adapter_peek (auparse->adapter, sendnow); - memcpy (GST_BUFFER_DATA (outbuf), data, sendnow); - gst_adapter_flush (auparse->adapter, sendnow); - - auparse->buffer_offset += sendnow; - - ret = gst_pad_push (auparse->srcpad, outbuf); - } - -out: - - gst_object_unref (auparse); - return ret; -} - -static gboolean -gst_au_parse_src_convert (GstAuParse * auparse, GstFormat src_format, - gint64 srcval, GstFormat dest_format, gint64 * destval) -{ - gboolean ret = TRUE; - guint samplesize, rate; - - if (dest_format == src_format) { - *destval = srcval; - return TRUE; - } - - GST_OBJECT_LOCK (auparse); - samplesize = auparse->sample_size; - rate = auparse->samplerate; - GST_OBJECT_UNLOCK (auparse); - - if (samplesize == 0 || rate == 0) { - GST_LOG_OBJECT (auparse, "cannot convert, sample_size or rate unknown"); - return FALSE; - } - - switch (src_format) { - case GST_FORMAT_BYTES: - srcval /= samplesize; - /* fallthrough */ - case GST_FORMAT_DEFAULT:{ - switch (dest_format) { - case GST_FORMAT_BYTES: - *destval = srcval * samplesize; - break; - case GST_FORMAT_TIME: - *destval = gst_util_uint64_scale_int (srcval, GST_SECOND, rate); - break; - default: - ret = FALSE; - break; - } - break; - } - case GST_FORMAT_TIME:{ - switch (dest_format) { - case GST_FORMAT_BYTES: - *destval = - gst_util_uint64_scale_int (srcval, rate * samplesize, GST_SECOND); - break; - case GST_FORMAT_DEFAULT: - *destval = gst_util_uint64_scale_int (srcval, rate, GST_SECOND); - break; - default: - ret = FALSE; - break; - } - break; - } - default:{ - ret = FALSE; - break; - } - } - - if (!ret) { - GST_DEBUG_OBJECT (auparse, "could not convert from %s to %s format", - gst_format_get_name (src_format), gst_format_get_name (dest_format)); - } - - return ret; -} - -static gboolean -gst_au_parse_src_query (GstPad * pad, GstQuery * query) -{ - GstAuParse *auparse; - gboolean ret = FALSE; - - auparse = GST_AU_PARSE (gst_pad_get_parent (pad)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_DURATION:{ - GstFormat bformat = GST_FORMAT_BYTES; - GstFormat format; - gint64 len, val; - - gst_query_parse_duration (query, &format, NULL); - if (!gst_pad_query_peer_duration (auparse->sinkpad, &bformat, &len)) { - GST_DEBUG_OBJECT (auparse, "failed to query upstream length"); - break; - } - GST_OBJECT_LOCK (auparse); - len -= auparse->offset; - GST_OBJECT_UNLOCK (auparse); - - ret = gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, len, - format, &val); - - if (ret) { - gst_query_set_duration (query, format, val); - } - break; - } - case GST_QUERY_POSITION:{ - GstFormat bformat = GST_FORMAT_BYTES; - GstFormat format; - gint64 pos, val; - - gst_query_parse_position (query, &format, NULL); - if (!gst_pad_query_peer_position (auparse->sinkpad, &bformat, &pos)) { - GST_DEBUG_OBJECT (auparse, "failed to query upstream position"); - break; - } - GST_OBJECT_LOCK (auparse); - pos -= auparse->offset; - GST_OBJECT_UNLOCK (auparse); - - ret = gst_au_parse_src_convert (auparse, GST_FORMAT_BYTES, pos, - format, &val); - - if (ret) { - gst_query_set_position (query, format, val); - } - break; - } - default: - ret = gst_pad_query_default (pad, query); - break; - } - - gst_object_unref (auparse); - return ret; -} - -static gboolean -gst_au_parse_handle_seek (GstAuParse * auparse, GstEvent * event) -{ - GstSeekType start_type, stop_type; - GstSeekFlags flags; - GstFormat format; - gdouble rate; - gint64 start, stop; - - gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start, - &stop_type, &stop); - - if (format != GST_FORMAT_TIME) { - GST_DEBUG_OBJECT (auparse, "only support seeks in TIME format"); - return FALSE; - } - - /* FIXME: implement seeking */ - return FALSE; -} - -static gboolean -gst_au_parse_sink_event (GstPad * pad, GstEvent * event) -{ - GstAuParse *auparse; - gboolean ret; - - auparse = GST_AU_PARSE (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - default: - ret = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (auparse); - return ret; -} - -static gboolean -gst_au_parse_src_event (GstPad * pad, GstEvent * event) -{ - GstAuParse *auparse; - gboolean ret; - - auparse = GST_AU_PARSE (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - ret = gst_au_parse_handle_seek (auparse, event); - break; - default: - ret = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (auparse); - return ret; -} - -static GstStateChangeReturn -gst_au_parse_change_state (GstElement * element, GstStateChange transition) -{ - GstAuParse *auparse = GST_AU_PARSE (element); - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - - ret = parent_class->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_au_parse_reset (auparse); - default: - break; - } - - return ret; -} - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "auparse", GST_RANK_SECONDARY, - GST_TYPE_AU_PARSE)) { - return FALSE; - } - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "auparse", - "parses au streams", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, - GST_PACKAGE_ORIGIN) - -EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC() -{ - return &gst_plugin_desc; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/auparse/gstauparse.h --- a/gst_plugins_good/gst/auparse/gstauparse.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2006> Tim-Philipp Müller - * - * 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. - */ - - -#ifndef __GST_AU_PARSE_H__ -#define __GST_AU_PARSE_H__ - - -#include "gst/gst.h" -#include -#include - - -G_BEGIN_DECLS - -#define GST_TYPE_AU_PARSE \ - (gst_au_parse_get_type()) -#define GST_AU_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AU_PARSE,GstAuParse)) -#define GST_AU_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AU_PARSE,GstAuParseClass)) -#define GST_IS_AU_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AU_PARSE)) -#define GST_IS_AU_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AU_PARSE)) - -typedef struct _GstAuParse GstAuParse; -typedef struct _GstAuParseClass GstAuParseClass; - -struct _GstAuParse { - GstElement element; - - GstPad *sinkpad; - GstPad *srcpad; - - GstCaps *src_caps; - - GstAdapter *adapter; - - /* GstSegment segment; */ - - gint64 offset; /* where sample data starts */ - gint64 buffer_offset; - guint sample_size; - guint encoding; - guint samplerate; - guint endianness; - guint channels; -}; - -struct _GstAuParseClass { - GstElementClass parent_class; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_au_parse_get_type (void); - -G_END_DECLS - -#endif /* __GST_AU_PARSE_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/autodetect/gstautoaudiosink.c --- a/gst_plugins_good/gst/autodetect/gstautoaudiosink.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,452 +0,0 @@ -/* GStreamer - * (c) 2005 Ronald S. Bultje - * (c) 2006 Jan Schmidt - * - * 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. - */ - -/** - * SECTION:element-autoaudiosink - * @see_also: autovideosink, alsasink, osssink - * - * autoaudiosink is an audio sink that automatically detects an appropriate - * audio sink to use. It does so by scanning the registry for all elements - * that have Sink and Audio in the class field - * of their element information, and also have a non-zero autoplugging rank. - * - * - * Example launch line - * |[ - * gst-launch -v -m audiotestsrc ! audioconvert ! audioresample ! autoaudiosink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "gstautoaudiosink.h" -#include "gstautodetect.h" - -/* Properties */ -enum -{ - PROP_0, - PROP_CAPS, -}; - -static GstStateChangeReturn -gst_auto_audio_sink_change_state (GstElement * element, - GstStateChange transition); -static void gst_auto_audio_sink_dispose (GstAutoAudioSink * sink); -static void gst_auto_audio_sink_clear_kid (GstAutoAudioSink * sink); -static void gst_auto_audio_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_auto_audio_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -GST_BOILERPLATE (GstAutoAudioSink, gst_auto_audio_sink, GstBin, GST_TYPE_BIN); - -static const GstElementDetails gst_auto_audio_sink_details = -GST_ELEMENT_DETAILS ("Auto audio sink", - "Sink/Audio", - "Wrapper audio sink for automatically detected audio sink", - "Ronald Bultje \n" - "Jan Schmidt "); - -static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static void -gst_auto_audio_sink_base_init (gpointer klass) -{ - GstElementClass *eklass = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (eklass, - gst_static_pad_template_get (&sink_template)); - - gst_element_class_set_details (eklass, &gst_auto_audio_sink_details); -} - -static void -gst_auto_audio_sink_class_init (GstAutoAudioSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *eklass; - - gobject_class = G_OBJECT_CLASS (klass); - eklass = GST_ELEMENT_CLASS (klass); - - gobject_class->dispose = - (GObjectFinalizeFunc) GST_DEBUG_FUNCPTR (gst_auto_audio_sink_dispose); - eklass->change_state = GST_DEBUG_FUNCPTR (gst_auto_audio_sink_change_state); - gobject_class->set_property = - GST_DEBUG_FUNCPTR (gst_auto_audio_sink_set_property); - gobject_class->get_property = - GST_DEBUG_FUNCPTR (gst_auto_audio_sink_get_property); - - /** - * GstAutoAudioSink:filter-caps - * - * This property will filter out candidate sinks that can handle the specified - * caps. By default only audio sinks that support raw floating point and - * integer audio are selected. - * - * This property can only be set before the element goes to the READY state. - * - * Since: 0.10.7 - **/ - g_object_class_install_property (gobject_class, PROP_CAPS, - g_param_spec_boxed ("filter-caps", "Filter caps", - "Filter sink candidates using these caps.", GST_TYPE_CAPS, - G_PARAM_READWRITE)); -} - -static void -gst_auto_audio_sink_dispose (GstAutoAudioSink * sink) -{ - gst_auto_audio_sink_clear_kid (sink); - - if (sink->filter_caps) - gst_caps_unref (sink->filter_caps); - sink->filter_caps = NULL; - - G_OBJECT_CLASS (parent_class)->dispose ((GObject *) sink); -} - -static void -gst_auto_audio_sink_clear_kid (GstAutoAudioSink * sink) -{ - if (sink->kid) { - gst_element_set_state (sink->kid, GST_STATE_NULL); - gst_bin_remove (GST_BIN (sink), sink->kid); - sink->kid = NULL; - } -} - -/* - * Hack to make initial linking work; ideally, this'd work even when - * no target has been assigned to the ghostpad yet. - */ -static void -gst_auto_audio_sink_reset (GstAutoAudioSink * sink) -{ - GstPad *targetpad; - - gst_auto_audio_sink_clear_kid (sink); - - /* fakesink placeholder */ - sink->kid = gst_element_factory_make ("fakesink", "tempsink"); - gst_bin_add (GST_BIN (sink), sink->kid); - - /* pad */ - targetpad = gst_element_get_static_pad (sink->kid, "sink"); - gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad); - gst_object_unref (targetpad); -} - -static GstStaticCaps raw_caps = - GST_STATIC_CAPS ("audio/x-raw-int; audio/x-raw-float"); - -static void -gst_auto_audio_sink_init (GstAutoAudioSink * sink, - GstAutoAudioSinkClass * g_class) -{ - sink->pad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK); - gst_element_add_pad (GST_ELEMENT (sink), sink->pad); - - gst_auto_audio_sink_reset (sink); - - /* set the default raw audio caps */ - sink->filter_caps = gst_static_caps_get (&raw_caps); - - /* mark as sink */ - GST_OBJECT_FLAG_SET (sink, GST_ELEMENT_IS_SINK); -} - -static gboolean -gst_auto_audio_sink_factory_filter (GstPluginFeature * feature, gpointer data) -{ - guint rank; - const gchar *klass; - - /* we only care about element factories */ - if (!GST_IS_ELEMENT_FACTORY (feature)) - return FALSE; - - /* audio sinks */ - klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature)); - if (!(strstr (klass, "Sink") && strstr (klass, "Audio"))) - return FALSE; - - /* only select elements with autoplugging rank */ - rank = gst_plugin_feature_get_rank (feature); - if (rank < GST_RANK_MARGINAL) - return FALSE; - - return TRUE; -} - -static gint -gst_auto_audio_sink_compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2) -{ - gint diff; - - diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1); - if (diff != 0) - return diff; - return strcmp (gst_plugin_feature_get_name (f2), - gst_plugin_feature_get_name (f1)); -} - -static GstElement * -gst_auto_audio_sink_create_element_with_pretty_name (GstAutoAudioSink * sink, - GstElementFactory * factory) -{ - GstElement *element; - gchar *name, *marker; - - marker = g_strdup (GST_PLUGIN_FEATURE (factory)->name); - if (g_str_has_suffix (marker, "sink")) - marker[strlen (marker) - 4] = '\0'; - if (g_str_has_prefix (marker, "gst")) - g_memmove (marker, marker + 3, strlen (marker + 3) + 1); - name = g_strdup_printf ("%s-actual-sink-%s", GST_OBJECT_NAME (sink), marker); - g_free (marker); - - element = gst_element_factory_create (factory, name); - g_free (name); - - return element; -} - -static GstElement * -gst_auto_audio_sink_find_best (GstAutoAudioSink * sink) -{ - GList *list, *item; - GstElement *choice = NULL; - GstMessage *message = NULL; - GSList *errors = NULL; - GstBus *bus = gst_bus_new (); - GstPad *el_pad = NULL; - GstCaps *el_caps = NULL, *intersect = NULL; - gboolean no_match = TRUE; - - list = gst_registry_feature_filter (gst_registry_get_default (), - (GstPluginFeatureFilter) gst_auto_audio_sink_factory_filter, FALSE, sink); - list = g_list_sort (list, (GCompareFunc) gst_auto_audio_sink_compare_ranks); - - /* We don't treat sound server sinks special. Our policy is that sound - * server sinks that have a rank must not auto-spawn a daemon under any - * circumstances, so there's nothing for us to worry about here */ - GST_LOG_OBJECT (sink, "Trying to find usable audio devices ..."); - - for (item = list; item != NULL; item = item->next) { - GstElementFactory *f = GST_ELEMENT_FACTORY (item->data); - GstElement *el; - - if ((el = gst_auto_audio_sink_create_element_with_pretty_name (sink, f))) { - GstStateChangeReturn ret; - - GST_DEBUG_OBJECT (sink, "Testing %s", GST_PLUGIN_FEATURE (f)->name); - - /* If autoaudiosink has been provided with filter caps, - * accept only sinks that match with the filter caps */ - if (sink->filter_caps) { - el_pad = gst_element_get_static_pad (GST_ELEMENT (el), "sink"); - el_caps = gst_pad_get_caps (el_pad); - gst_object_unref (el_pad); - GST_DEBUG_OBJECT (sink, - "Checking caps: %" GST_PTR_FORMAT " vs. %" GST_PTR_FORMAT, - sink->filter_caps, el_caps); - intersect = gst_caps_intersect (sink->filter_caps, el_caps); - no_match = gst_caps_is_empty (intersect); - gst_caps_unref (el_caps); - gst_caps_unref (intersect); - - if (no_match) { - GST_DEBUG_OBJECT (sink, "Incompatible caps"); - gst_object_unref (el); - continue; - } else { - GST_DEBUG_OBJECT (sink, "Found compatible caps"); - } - } - - gst_element_set_bus (el, bus); - ret = gst_element_set_state (el, GST_STATE_READY); - if (ret == GST_STATE_CHANGE_SUCCESS) { - GST_DEBUG_OBJECT (sink, "This worked!"); - choice = el; - break; - } - - /* collect all error messages */ - while ((message = gst_bus_pop_filtered (bus, GST_MESSAGE_ERROR))) { - GST_DEBUG_OBJECT (sink, "error message %" GST_PTR_FORMAT, message); - errors = g_slist_append (errors, message); - } - - gst_element_set_state (el, GST_STATE_NULL); - gst_object_unref (el); - } - } - - GST_DEBUG_OBJECT (sink, "done trying"); - if (!choice) { - if (errors) { - /* FIXME: we forward the first error for now; but later on it might make - * sense to actually analyse them */ - gst_message_ref (GST_MESSAGE (errors->data)); - GST_DEBUG_OBJECT (sink, "reposting message %p", errors->data); - gst_element_post_message (GST_ELEMENT (sink), GST_MESSAGE (errors->data)); - } else { - /* send warning message to application and use a fakesink */ - GST_ELEMENT_WARNING (sink, RESOURCE, NOT_FOUND, (NULL), - ("Failed to find a usable audio sink")); - choice = gst_element_factory_make ("fakesink", "fake-audio-sink"); - if (g_object_class_find_property (G_OBJECT_GET_CLASS (choice), "sync")) - g_object_set (choice, "sync", TRUE, NULL); - gst_element_set_state (choice, GST_STATE_READY); - } - } - gst_object_unref (bus); - gst_plugin_feature_list_free (list); - g_slist_foreach (errors, (GFunc) gst_mini_object_unref, NULL); - g_slist_free (errors); - - return choice; -} - -static gboolean -gst_auto_audio_sink_detect (GstAutoAudioSink * sink) -{ - GstElement *esink; - GstPad *targetpad; - - gst_auto_audio_sink_clear_kid (sink); - - /* find element */ - GST_DEBUG_OBJECT (sink, "Creating new kid"); - if (!(esink = gst_auto_audio_sink_find_best (sink))) - goto no_sink; - - sink->kid = esink; - /* Ensure the child is brought up to the right state to match the parent - * although it's currently always in READY and - * we're always doing NULL->READY. */ - if (GST_STATE (sink->kid) < GST_STATE (sink)) - gst_element_set_state (sink->kid, GST_STATE (sink)); - - gst_bin_add (GST_BIN (sink), esink); - - /* attach ghost pad */ - GST_DEBUG_OBJECT (sink, "Re-assigning ghostpad"); - targetpad = gst_element_get_static_pad (sink->kid, "sink"); - if (!gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad)) - goto target_failed; - - gst_object_unref (targetpad); - GST_DEBUG_OBJECT (sink, "done changing auto audio sink"); - - return TRUE; - - /* ERRORS */ -no_sink: - { - GST_ELEMENT_ERROR (sink, LIBRARY, INIT, (NULL), - ("Failed to find a supported audio sink")); - return FALSE; - } -target_failed: - { - GST_ELEMENT_ERROR (sink, LIBRARY, INIT, (NULL), - ("Failed to set target pad")); - gst_object_unref (targetpad); - return FALSE; - } -} - -static GstStateChangeReturn -gst_auto_audio_sink_change_state (GstElement * element, - GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstAutoAudioSink *sink = GST_AUTO_AUDIO_SINK (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!gst_auto_audio_sink_detect (sink)) - return GST_STATE_CHANGE_FAILURE; - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - gst_auto_audio_sink_reset (sink); - break; - default: - break; - } - - return ret; -} - -static void -gst_auto_audio_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAutoAudioSink *sink = GST_AUTO_AUDIO_SINK (object); - - switch (prop_id) { - case PROP_CAPS: - if (sink->filter_caps) - gst_caps_unref (sink->filter_caps); - sink->filter_caps = gst_caps_copy (gst_value_get_caps (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_auto_audio_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAutoAudioSink *sink = GST_AUTO_AUDIO_SINK (object); - - switch (prop_id) { - case PROP_CAPS:{ - gst_value_set_caps (value, sink->filter_caps); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/autodetect/gstautoaudiosink.h --- a/gst_plugins_good/gst/autodetect/gstautoaudiosink.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* GStreamer - * (c) 2005 Ronald S. Bultje - * - * 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. - */ - -#ifndef __GST_AUTO_AUDIO_SINK_H__ -#define __GST_AUTO_AUDIO_SINK_H__ - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_AUTO_AUDIO_SINK \ - (gst_auto_audio_sink_get_type ()) -#define GST_AUTO_AUDIO_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AUTO_AUDIO_SINK, \ - GstAutoAudioSink)) -#define GST_AUTO_AUDIO_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AUTO_AUDIO_SINK, \ - GstAutoAudioSinkClass)) -#define GST_IS_AUTO_AUDIO_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AUTO_AUDIO_SINK)) -#define GST_IS_AUTO_AUDIO_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AUTO_AUDIO_SINK)) - -typedef struct _GstAutoAudioSink { - GstBin parent; - - /* explicit pointers to stuff used */ - GstPad *pad; - GstElement *kid; - GstCaps *filter_caps; -} GstAutoAudioSink; - -typedef struct _GstAutoAudioSinkClass { - GstBinClass parent_class; -} GstAutoAudioSinkClass; - -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - -GType gst_auto_audio_sink_get_type (void); - -G_END_DECLS - -#endif /* __GST_AUTO_AUDIO_SINK_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/autodetect/gstautoaudiosrc.c --- a/gst_plugins_good/gst/autodetect/gstautoaudiosrc.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,453 +0,0 @@ -/* GStreamer - * (c) 2005 Ronald S. Bultje - * (c) 2006 Jan Schmidt - * (c) 2008 Stefan Kost - * - * 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. - */ - -/** - * SECTION:element-autoaudiosrc - * @see_also: autovideosrc, alsasrc, osssrc - * - * autoaudiosrc is an audio source that automatically detects an appropriate - * audio source to use. It does so by scanning the registry for all elements - * that have Source and Audio in the class field - * of their element information, and also have a non-zero autoplugging rank. - * - * - * Example launch line - * |[ - * gst-launch -v -m autoaudiosrc ! audioconvert ! audioresample ! autoaudiosink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "gstautoaudiosrc.h" -#include "gstautodetect.h" - -/* Properties */ -enum -{ - PROP_0, - PROP_CAPS, -}; - -static GstStateChangeReturn -gst_auto_audio_src_change_state (GstElement * element, - GstStateChange transition); -static void gst_auto_audio_src_dispose (GstAutoAudioSrc * src); -static void gst_auto_audio_src_clear_kid (GstAutoAudioSrc * src); -static void gst_auto_audio_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_auto_audio_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -GST_BOILERPLATE (GstAutoAudioSrc, gst_auto_audio_src, GstBin, GST_TYPE_BIN); - -static const GstElementDetails gst_auto_audio_src_details = -GST_ELEMENT_DETAILS ("Auto audio source", - "Source/Audio", - "Wrapper audio source for automatically detected audio source", - "Ronald Bultje \n" - "Jan Schmidt \n" - "Stefan Kost "); - -static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static void -gst_auto_audio_src_base_init (gpointer klass) -{ - GstElementClass *eklass = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (eklass, - gst_static_pad_template_get (&src_template)); - - gst_element_class_set_details (eklass, &gst_auto_audio_src_details); -} - -static void -gst_auto_audio_src_class_init (GstAutoAudioSrcClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *eklass; - - gobject_class = G_OBJECT_CLASS (klass); - eklass = GST_ELEMENT_CLASS (klass); - - gobject_class->dispose = - (GObjectFinalizeFunc) GST_DEBUG_FUNCPTR (gst_auto_audio_src_dispose); - eklass->change_state = GST_DEBUG_FUNCPTR (gst_auto_audio_src_change_state); - gobject_class->set_property = - GST_DEBUG_FUNCPTR (gst_auto_audio_src_set_property); - gobject_class->get_property = - GST_DEBUG_FUNCPTR (gst_auto_audio_src_get_property); - - /** - * GstAutoAudioSrc:filter-caps - * - * This property will filter out candidate sinks that can handle the specified - * caps. By default only audio sinks that support raw floating point and - * integer audio are selected. - * - * This property can only be set before the element goes to the READY state. - * - * Since: 0.10.14 - **/ - g_object_class_install_property (gobject_class, PROP_CAPS, - g_param_spec_boxed ("filter-caps", "Filter caps", - "Filter sink candidates using these caps.", GST_TYPE_CAPS, - G_PARAM_READWRITE)); -} - -static void -gst_auto_audio_src_dispose (GstAutoAudioSrc * sink) -{ - gst_auto_audio_src_clear_kid (sink); - - if (sink->filter_caps) - gst_caps_unref (sink->filter_caps); - sink->filter_caps = NULL; - - G_OBJECT_CLASS (parent_class)->dispose ((GObject *) sink); -} - -static void -gst_auto_audio_src_clear_kid (GstAutoAudioSrc * sink) -{ - if (sink->kid) { - gst_element_set_state (sink->kid, GST_STATE_NULL); - gst_bin_remove (GST_BIN (sink), sink->kid); - sink->kid = NULL; - } -} - -/* - * Hack to make initial linking work; ideally, this'd work even when - * no target has been assigned to the ghostpad yet. - */ -static void -gst_auto_audio_src_reset (GstAutoAudioSrc * src) -{ - GstPad *targetpad; - - gst_auto_audio_src_clear_kid (src); - - /* fakesink placeholder */ - src->kid = gst_element_factory_make ("fakesrc", "tempsrc"); - gst_bin_add (GST_BIN (src), src->kid); - - /* pad */ - targetpad = gst_element_get_static_pad (src->kid, "src"); - gst_ghost_pad_set_target (GST_GHOST_PAD (src->pad), targetpad); - gst_object_unref (targetpad); -} - -static GstStaticCaps raw_caps = - GST_STATIC_CAPS ("audio/x-raw-int; audio/x-raw-float"); - -static void -gst_auto_audio_src_init (GstAutoAudioSrc * src, GstAutoAudioSrcClass * g_class) -{ - src->pad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC); - gst_element_add_pad (GST_ELEMENT (src), src->pad); - - gst_auto_audio_src_reset (src); - - /* set the default raw audio caps */ - src->filter_caps = gst_static_caps_get (&raw_caps); - - /* mark as source */ - GST_OBJECT_FLAG_UNSET (src, GST_ELEMENT_IS_SINK); -} - -static gboolean -gst_auto_audio_src_factory_filter (GstPluginFeature * feature, gpointer data) -{ - guint rank; - const gchar *klass; - - /* we only care about element factories */ - if (!GST_IS_ELEMENT_FACTORY (feature)) - return FALSE; - - /* audio sinks */ - klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature)); - if (!(strstr (klass, "Source") && strstr (klass, "Audio"))) - return FALSE; - - /* only select elements with autoplugging rank */ - rank = gst_plugin_feature_get_rank (feature); - if (rank < GST_RANK_MARGINAL) - return FALSE; - - return TRUE; -} - -static gint -gst_auto_audio_src_compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2) -{ - gint diff; - - diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1); - if (diff != 0) - return diff; - return strcmp (gst_plugin_feature_get_name (f2), - gst_plugin_feature_get_name (f1)); -} - -static GstElement * -gst_auto_audio_src_create_element_with_pretty_name (GstAutoAudioSrc * src, - GstElementFactory * factory) -{ - GstElement *element; - gchar *name, *marker; - - marker = g_strdup (GST_PLUGIN_FEATURE (factory)->name); - if (g_str_has_suffix (marker, "src")) - marker[strlen (marker) - 4] = '\0'; - if (g_str_has_prefix (marker, "gst")) - g_memmove (marker, marker + 3, strlen (marker + 3) + 1); - name = g_strdup_printf ("%s-actual-src-%s", GST_OBJECT_NAME (src), marker); - g_free (marker); - - element = gst_element_factory_create (factory, name); - g_free (name); - - return element; -} - -static GstElement * -gst_auto_audio_src_find_best (GstAutoAudioSrc * src) -{ - GList *list, *item; - GstElement *choice = NULL; - GstMessage *message = NULL; - GSList *errors = NULL; - GstBus *bus = gst_bus_new (); - GstPad *el_pad = NULL; - GstCaps *el_caps = NULL, *intersect = NULL; - gboolean no_match = TRUE; - - list = gst_registry_feature_filter (gst_registry_get_default (), - (GstPluginFeatureFilter) gst_auto_audio_src_factory_filter, FALSE, src); - list = g_list_sort (list, (GCompareFunc) gst_auto_audio_src_compare_ranks); - - /* We don't treat sound server sources special. Our policy is that sound - * server sources that have a rank must not auto-spawn a daemon under any - * circumstances, so there's nothing for us to worry about here */ - GST_LOG_OBJECT (src, "Trying to find usable audio devices ..."); - - for (item = list; item != NULL; item = item->next) { - GstElementFactory *f = GST_ELEMENT_FACTORY (item->data); - GstElement *el; - - if ((el = gst_auto_audio_src_create_element_with_pretty_name (src, f))) { - GstStateChangeReturn ret; - - GST_DEBUG_OBJECT (src, "Testing %s", GST_PLUGIN_FEATURE (f)->name); - - /* If autoAudioSrc has been provided with filter caps, - * accept only sources that match with the filter caps */ - if (src->filter_caps) { - el_pad = gst_element_get_static_pad (GST_ELEMENT (el), "src"); - el_caps = gst_pad_get_caps (el_pad); - gst_object_unref (el_pad); - GST_DEBUG_OBJECT (src, - "Checking caps: %" GST_PTR_FORMAT " vs. %" GST_PTR_FORMAT, - src->filter_caps, el_caps); - intersect = gst_caps_intersect (src->filter_caps, el_caps); - no_match = gst_caps_is_empty (intersect); - gst_caps_unref (el_caps); - gst_caps_unref (intersect); - - if (no_match) { - GST_DEBUG_OBJECT (src, "Incompatible caps"); - gst_object_unref (el); - continue; - } else { - GST_DEBUG_OBJECT (src, "Found compatible caps"); - } - } - - gst_element_set_bus (el, bus); - ret = gst_element_set_state (el, GST_STATE_READY); - if (ret == GST_STATE_CHANGE_SUCCESS) { - GST_DEBUG_OBJECT (src, "This worked!"); - choice = el; - break; - } - - /* collect all error messages */ - while ((message = gst_bus_pop_filtered (bus, GST_MESSAGE_ERROR))) { - GST_DEBUG_OBJECT (src, "error message %" GST_PTR_FORMAT, message); - errors = g_slist_append (errors, message); - } - - gst_element_set_state (el, GST_STATE_NULL); - gst_object_unref (el); - } - } - - GST_DEBUG_OBJECT (src, "done trying"); - if (!choice) { - if (errors) { - /* FIXME: we forward the first error for now; but later on it might make - * sense to actually analyse them */ - gst_message_ref (GST_MESSAGE (errors->data)); - GST_DEBUG_OBJECT (src, "reposting message %p", errors->data); - gst_element_post_message (GST_ELEMENT (src), GST_MESSAGE (errors->data)); - } else { - /* send warning message to application and use a fakesrc */ - GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL), - ("Failed to find a usable audio source")); - choice = gst_element_factory_make ("fakesrc", "fake-audio-src"); - if (g_object_class_find_property (G_OBJECT_GET_CLASS (choice), "sync")) - g_object_set (choice, "sync", TRUE, NULL); - gst_element_set_state (choice, GST_STATE_READY); - } - } - gst_object_unref (bus); - gst_plugin_feature_list_free (list); - g_slist_foreach (errors, (GFunc) gst_mini_object_unref, NULL); - g_slist_free (errors); - - return choice; -} - -static gboolean -gst_auto_audio_src_detect (GstAutoAudioSrc * src) -{ - GstElement *esrc; - GstPad *targetpad; - - gst_auto_audio_src_clear_kid (src); - - /* find element */ - GST_DEBUG_OBJECT (src, "Creating new kid"); - if (!(esrc = gst_auto_audio_src_find_best (src))) - goto no_src; - - src->kid = esrc; - /* Ensure the child is brought up to the right state to match the parent - * although it's currently always in READY and - * we're always doing NULL->READY. */ - if (GST_STATE (src->kid) < GST_STATE (src)) - gst_element_set_state (src->kid, GST_STATE (src)); - - gst_bin_add (GST_BIN (src), esrc); - - /* attach ghost pad */ - GST_DEBUG_OBJECT (src, "Re-assigning ghostpad"); - targetpad = gst_element_get_static_pad (src->kid, "src"); - if (!gst_ghost_pad_set_target (GST_GHOST_PAD (src->pad), targetpad)) - goto target_failed; - - gst_object_unref (targetpad); - GST_DEBUG_OBJECT (src, "done changing auto audio source"); - - return TRUE; - - /* ERRORS */ -no_src: - { - GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), - ("Failed to find a supported audio source")); - return FALSE; - } -target_failed: - { - GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), - ("Failed to set target pad")); - gst_object_unref (targetpad); - return FALSE; - } -} - -static GstStateChangeReturn -gst_auto_audio_src_change_state (GstElement * element, - GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstAutoAudioSrc *src = GST_AUTO_AUDIO_SRC (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!gst_auto_audio_src_detect (src)) - return GST_STATE_CHANGE_FAILURE; - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - gst_auto_audio_src_reset (src); - break; - default: - break; - } - - return ret; -} - -static void -gst_auto_audio_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAutoAudioSrc *src = GST_AUTO_AUDIO_SRC (object); - - switch (prop_id) { - case PROP_CAPS: - if (src->filter_caps) - gst_caps_unref (src->filter_caps); - src->filter_caps = gst_caps_copy (gst_value_get_caps (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_auto_audio_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAutoAudioSrc *src = GST_AUTO_AUDIO_SRC (object); - - switch (prop_id) { - case PROP_CAPS:{ - gst_value_set_caps (value, src->filter_caps); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/autodetect/gstautoaudiosrc.h --- a/gst_plugins_good/gst/autodetect/gstautoaudiosrc.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* GStreamer - * (c) 2005 Ronald S. Bultje - * (c) 2008 Stefan Kost - * - * 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. - */ - -#ifndef __GST_AUTO_AUDIO_SRC_H__ -#define __GST_AUTO_AUDIO_SRC_H__ - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_AUTO_AUDIO_SRC \ - (gst_auto_audio_src_get_type ()) -#define GST_AUTO_AUDIO_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AUTO_AUDIO_SRC, \ - GstAutoAudioSrc)) -#define GST_AUTO_AUDIO_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AUTO_AUDIO_SRC, \ - GstAutoAudioSrcClass)) -#define GST_IS_AUTO_AUDIO_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AUTO_AUDIO_SRC)) -#define GST_IS_AUTO_AUDIO_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AUTO_AUDIO_SRC)) - -typedef struct _GstAutoAudioSrc { - GstBin parent; - - /* explicit pointers to stuff used */ - GstPad *pad; - GstElement *kid; - GstCaps *filter_caps; -} GstAutoAudioSrc; - -typedef struct _GstAutoAudioSrcClass { - GstBinClass parent_class; -} GstAutoAudioSrcClass; - -#ifdef __SYMBIAN32__ -IMPORT_C -#endif -GType gst_auto_audio_src_get_type (void); - -G_END_DECLS - -#endif /* __GST_AUTO_AUDIO_SRC_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/autodetect/gstautodetect.c --- a/gst_plugins_good/gst/autodetect/gstautodetect.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* GStreamer - * (c) 2005 Ronald S. Bultje - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "gstautodetect.h" -#include "gstautoaudiosink.h" -#include "gstautoaudiosrc.h" -#include "gstautovideosink.h" -#include "gstautovideosrc.h" - -GST_DEBUG_CATEGORY (autodetect_debug); - -static gboolean -plugin_init (GstPlugin * plugin) -{ - GST_DEBUG_CATEGORY_INIT (autodetect_debug, "autodetect", 0, - "Autodetection audio/video output wrapper elements"); - - return gst_element_register (plugin, "autovideosink", - GST_RANK_NONE, GST_TYPE_AUTO_VIDEO_SINK) && - gst_element_register (plugin, "autovideosrc", - GST_RANK_NONE, GST_TYPE_AUTO_VIDEO_SRC) && - gst_element_register (plugin, "autoaudiosink", - GST_RANK_NONE, GST_TYPE_AUTO_AUDIO_SINK) && - gst_element_register (plugin, "autoaudiosrc", - GST_RANK_NONE, GST_TYPE_AUTO_AUDIO_SRC); -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "autodetect", - "Plugin contains auto-detection plugins for video/audio in- and outputs", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) - -#ifdef __SYMBIAN32__ -EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC() -{ - return &gst_plugin_desc; -} -#endif \ No newline at end of file diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/autodetect/gstautodetect.h --- a/gst_plugins_good/gst/autodetect/gstautodetect.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* GStreamer - * (c) 2005 Ronald S. Bultje - * - * 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. - */ - -#ifndef __GST_AUTO_DETECT_H__ -#define __GST_AUTO_DETECT_H__ - -GST_DEBUG_CATEGORY_EXTERN (autodetect_debug); -#define GST_CAT_DEFAULT autodetect_debug - -#endif /* __GST_AUTO_DETECT_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/autodetect/gstautovideosink.c --- a/gst_plugins_good/gst/autodetect/gstautovideosink.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,441 +0,0 @@ -/* GStreamer - * (c) 2005 Ronald S. Bultje - * (c) 2006 Jan Schmidt - * - * 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. - */ - -/** - * SECTION:element-autovideosink - * @see_also: autoaudiosink, ximagesink, xvimagesink, sdlvideosink - * - * autovideosink is a video sink that automatically detects an appropriate - * video sink to use. It does so by scanning the registry for all elements - * that have Sink and Video in the class field - * of their element information, and also have a non-zero autoplugging rank. - * - * - * Example launch line - * |[ - * gst-launch -v -m videotestsrc ! autovideosink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "gstautovideosink.h" -#include "gstautodetect.h" - -/* Properties */ -enum -{ - PROP_0, - PROP_CAPS, -}; - -static GstStateChangeReturn -gst_auto_video_sink_change_state (GstElement * element, - GstStateChange transition); -static void gst_auto_video_sink_dispose (GstAutoVideoSink * sink); -static void gst_auto_video_sink_clear_kid (GstAutoVideoSink * sink); - -static void gst_auto_video_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_auto_video_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -GST_BOILERPLATE (GstAutoVideoSink, gst_auto_video_sink, GstBin, GST_TYPE_BIN); - -static const GstElementDetails gst_auto_video_sink_details = -GST_ELEMENT_DETAILS ("Auto video sink", - "Sink/Video", - "Wrapper video sink for automatically detected video sink", - "Ronald Bultje \n" - "Jan Schmidt "); - -static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static void -gst_auto_video_sink_base_init (gpointer klass) -{ - GstElementClass *eklass = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (eklass, - gst_static_pad_template_get (&sink_template)); - gst_element_class_set_details (eklass, &gst_auto_video_sink_details); -} - -static void -gst_auto_video_sink_class_init (GstAutoVideoSinkClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *eklass = GST_ELEMENT_CLASS (klass); - - gobject_class = G_OBJECT_CLASS (klass); - gobject_class->dispose = - (GObjectFinalizeFunc) GST_DEBUG_FUNCPTR (gst_auto_video_sink_dispose); - eklass->change_state = GST_DEBUG_FUNCPTR (gst_auto_video_sink_change_state); - gobject_class->set_property = - GST_DEBUG_FUNCPTR (gst_auto_video_sink_set_property); - gobject_class->get_property = - GST_DEBUG_FUNCPTR (gst_auto_video_sink_get_property); - - /** - * GstAutoVideoSink:filter-caps - * - * This property will filter out candidate sinks that can handle the specified - * caps. By default only video sinks that support raw rgb and yuv video - * are selected. - * - * This property can only be set before the element goes to the READY state. - * - * Since: 0.10.7 - **/ - g_object_class_install_property (gobject_class, PROP_CAPS, - g_param_spec_boxed ("filter-caps", "Filter caps", - "Filter sink candidates using these caps.", GST_TYPE_CAPS, - G_PARAM_READWRITE)); -} - -static void -gst_auto_video_sink_dispose (GstAutoVideoSink * sink) -{ - gst_auto_video_sink_clear_kid (sink); - - if (sink->filter_caps) - gst_caps_unref (sink->filter_caps); - sink->filter_caps = NULL; - - G_OBJECT_CLASS (parent_class)->dispose ((GObject *) sink); -} - -static void -gst_auto_video_sink_clear_kid (GstAutoVideoSink * sink) -{ - if (sink->kid) { - gst_element_set_state (sink->kid, GST_STATE_NULL); - gst_bin_remove (GST_BIN (sink), sink->kid); - sink->kid = NULL; - } -} - -/* - * Hack to make initial linking work; ideally, this'd work even when - * no target has been assigned to the ghostpad yet. - */ - -static void -gst_auto_video_sink_reset (GstAutoVideoSink * sink) -{ - GstPad *targetpad; - - /* Remove any existing element */ - gst_auto_video_sink_clear_kid (sink); - - /* fakesink placeholder */ - sink->kid = gst_element_factory_make ("fakesink", "tempsink"); - gst_bin_add (GST_BIN (sink), sink->kid); - - /* pad, setting this target should always work */ - targetpad = gst_element_get_static_pad (sink->kid, "sink"); - gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad); - gst_object_unref (targetpad); -} - -static GstStaticCaps raw_caps = - GST_STATIC_CAPS ("video/x-raw-yuv; video/x-raw-rgb"); - -static void -gst_auto_video_sink_init (GstAutoVideoSink * sink, - GstAutoVideoSinkClass * g_class) -{ - sink->pad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK); - gst_element_add_pad (GST_ELEMENT (sink), sink->pad); - - gst_auto_video_sink_reset (sink); - - /* set the default raw video caps */ - sink->filter_caps = gst_static_caps_get (&raw_caps); - - /* mark as sink */ - GST_OBJECT_FLAG_SET (sink, GST_ELEMENT_IS_SINK); -} - -static gboolean -gst_auto_video_sink_factory_filter (GstPluginFeature * feature, gpointer data) -{ - guint rank; - const gchar *klass; - - /* we only care about element factories */ - if (!GST_IS_ELEMENT_FACTORY (feature)) - return FALSE; - - /* video sinks */ - klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature)); - if (!(strstr (klass, "Sink") && strstr (klass, "Video"))) - return FALSE; - - /* only select elements with autoplugging rank */ - rank = gst_plugin_feature_get_rank (feature); - if (rank < GST_RANK_MARGINAL) - return FALSE; - - return TRUE; -} - -static gint -gst_auto_video_sink_compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2) -{ - gint diff; - - diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1); - if (diff != 0) - return diff; - return strcmp (gst_plugin_feature_get_name (f2), - gst_plugin_feature_get_name (f1)); -} - -static GstElement * -gst_auto_video_sink_create_element_with_pretty_name (GstAutoVideoSink * sink, - GstElementFactory * factory) -{ - GstElement *element; - gchar *name, *marker; - - marker = g_strdup (GST_PLUGIN_FEATURE (factory)->name); - if (g_str_has_suffix (marker, "sink")) - marker[strlen (marker) - 4] = '\0'; - if (g_str_has_prefix (marker, "gst")) - g_memmove (marker, marker + 3, strlen (marker + 3) + 1); - name = g_strdup_printf ("%s-actual-sink-%s", GST_OBJECT_NAME (sink), marker); - g_free (marker); - - element = gst_element_factory_create (factory, name); - g_free (name); - - return element; -} - -static GstElement * -gst_auto_video_sink_find_best (GstAutoVideoSink * sink) -{ - GList *list, *item; - GstElement *choice = NULL; - GstMessage *message = NULL; - GSList *errors = NULL; - GstBus *bus = gst_bus_new (); - GstPad *el_pad = NULL; - GstCaps *el_caps = NULL, *intersect = NULL; - gboolean no_match = TRUE; - - list = gst_registry_feature_filter (gst_registry_get_default (), - (GstPluginFeatureFilter) gst_auto_video_sink_factory_filter, FALSE, sink); - list = g_list_sort (list, (GCompareFunc) gst_auto_video_sink_compare_ranks); - - GST_LOG_OBJECT (sink, "Trying to find usable video devices ..."); - - for (item = list; item != NULL; item = item->next) { - GstElementFactory *f = GST_ELEMENT_FACTORY (item->data); - GstElement *el; - - if ((el = gst_auto_video_sink_create_element_with_pretty_name (sink, f))) { - GstStateChangeReturn ret; - - GST_DEBUG_OBJECT (sink, "Testing %s", GST_PLUGIN_FEATURE (f)->name); - - /* If autovideosink has been provided with filter caps, - * accept only sinks that match with the filter caps */ - if (sink->filter_caps) { - el_pad = gst_element_get_static_pad (GST_ELEMENT (el), "sink"); - el_caps = gst_pad_get_caps (el_pad); - gst_object_unref (el_pad); - GST_DEBUG_OBJECT (sink, - "Checking caps: %" GST_PTR_FORMAT " vs. %" GST_PTR_FORMAT, - sink->filter_caps, el_caps); - intersect = gst_caps_intersect (sink->filter_caps, el_caps); - no_match = gst_caps_is_empty (intersect); - gst_caps_unref (el_caps); - gst_caps_unref (intersect); - - if (no_match) { - GST_DEBUG_OBJECT (sink, "Incompatible caps"); - gst_object_unref (el); - continue; - } else { - GST_DEBUG_OBJECT (sink, "Found compatible caps"); - } - } - - gst_element_set_bus (el, bus); - ret = gst_element_set_state (el, GST_STATE_READY); - if (ret == GST_STATE_CHANGE_SUCCESS) { - GST_DEBUG_OBJECT (sink, "This worked!"); - choice = el; - break; - } - - /* collect all error messages */ - while ((message = gst_bus_pop_filtered (bus, GST_MESSAGE_ERROR))) { - GST_DEBUG_OBJECT (sink, "error message %" GST_PTR_FORMAT, message); - errors = g_slist_append (errors, message); - } - - gst_element_set_state (el, GST_STATE_NULL); - gst_object_unref (el); - } - } - - GST_DEBUG_OBJECT (sink, "done trying"); - if (!choice) { - if (errors) { - /* FIXME: we forward the first error for now; but later on it might make - * sense to actually analyse them */ - gst_message_ref (GST_MESSAGE (errors->data)); - GST_DEBUG_OBJECT (sink, "reposting message %p", errors->data); - gst_element_post_message (GST_ELEMENT (sink), GST_MESSAGE (errors->data)); - } else { - /* send warning message to application and use a fakesink */ - GST_ELEMENT_WARNING (sink, RESOURCE, NOT_FOUND, (NULL), - ("Failed to find a usable video sink")); - choice = gst_element_factory_make ("fakesink", "fake-video-sink"); - if (g_object_class_find_property (G_OBJECT_GET_CLASS (choice), "sync")) - g_object_set (choice, "sync", TRUE, NULL); - gst_element_set_state (choice, GST_STATE_READY); - } - } - gst_object_unref (bus); - gst_plugin_feature_list_free (list); - g_slist_foreach (errors, (GFunc) gst_mini_object_unref, NULL); - g_slist_free (errors); - - return choice; -} - -static gboolean -gst_auto_video_sink_detect (GstAutoVideoSink * sink) -{ - GstElement *esink; - GstPad *targetpad; - - gst_auto_video_sink_clear_kid (sink); - - /* find element */ - GST_DEBUG_OBJECT (sink, "Creating new kid"); - if (!(esink = gst_auto_video_sink_find_best (sink))) - goto no_sink; - - sink->kid = esink; - gst_bin_add (GST_BIN (sink), esink); - - /* attach ghost pad */ - GST_DEBUG_OBJECT (sink, "Re-assigning ghostpad"); - targetpad = gst_element_get_static_pad (sink->kid, "sink"); - if (!gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad)) - goto target_failed; - - gst_object_unref (targetpad); - GST_DEBUG_OBJECT (sink, "done changing auto video sink"); - - return TRUE; - - /* ERRORS */ -no_sink: - { - GST_ELEMENT_ERROR (sink, LIBRARY, INIT, (NULL), - ("Failed to find a supported video sink")); - return FALSE; - } -target_failed: - { - GST_ELEMENT_ERROR (sink, LIBRARY, INIT, (NULL), - ("Failed to set target pad")); - gst_object_unref (targetpad); - return FALSE; - } -} - -static GstStateChangeReturn -gst_auto_video_sink_change_state (GstElement * element, - GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstAutoVideoSink *sink = GST_AUTO_VIDEO_SINK (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!gst_auto_video_sink_detect (sink)) - return GST_STATE_CHANGE_FAILURE; - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - gst_auto_video_sink_reset (sink); - break; - default: - break; - } - - return ret; -} - -static void -gst_auto_video_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAutoVideoSink *sink = GST_AUTO_VIDEO_SINK (object); - - switch (prop_id) { - case PROP_CAPS: - if (sink->filter_caps) - gst_caps_unref (sink->filter_caps); - sink->filter_caps = gst_caps_copy (gst_value_get_caps (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_auto_video_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAutoVideoSink *sink = GST_AUTO_VIDEO_SINK (object); - - switch (prop_id) { - case PROP_CAPS:{ - gst_value_set_caps (value, sink->filter_caps); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/autodetect/gstautovideosink.h --- a/gst_plugins_good/gst/autodetect/gstautovideosink.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* GStreamer - * (c) 2005 Ronald S. Bultje - * - * 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. - */ - -#ifndef __GST_AUTO_VIDEO_SINK_H__ -#define __GST_AUTO_VIDEO_SINK_H__ - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_AUTO_VIDEO_SINK \ - (gst_auto_video_sink_get_type ()) -#define GST_AUTO_VIDEO_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AUTO_VIDEO_SINK, \ - GstAutoVideoSink)) -#define GST_AUTO_VIDEO_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AUTO_VIDEO_SINK, \ - GstAutoVideoSinkClass)) -#define GST_IS_AUTO_VIDEO_SINK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AUTO_VIDEO_SINK)) -#define GST_IS_AUTO_VIDEO_SINK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AUTO_VIDEO_SINK)) - -typedef struct _GstAutoVideoSink { - GstBin parent; - - /* explicit pointers to stuff used */ - GstPad *pad; - GstElement *kid; - GstCaps *filter_caps; -} GstAutoVideoSink; - -typedef struct _GstAutoVideoSinkClass { - GstBinClass parent_class; -} GstAutoVideoSinkClass; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_auto_video_sink_get_type (void); - -G_END_DECLS - -#endif /* __GST_AUTO_VIDEO_SINK_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/autodetect/gstautovideosrc.c --- a/gst_plugins_good/gst/autodetect/gstautovideosrc.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,442 +0,0 @@ -/* GStreamer - * (c) 2005 Ronald S. Bultje - * (c) 2006 Jan Schmidt - * (c) 2008 Stefan Kost - * - * 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. - */ - -/** - * SECTION:element-autovideosrc - * @see_also: autoaudiosrc, v4l2src, v4lsrc - * - * autovideosrc is a video src that automatically detects an appropriate - * video source to use. It does so by scanning the registry for all elements - * that have Source and Video in the class field - * of their element information, and also have a non-zero autoplugging rank. - * - * - * Example launch line - * |[ - * gst-launch -v -m autovideosrc ! xvimagesink - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "gstautovideosrc.h" -#include "gstautodetect.h" - -/* Properties */ -enum -{ - PROP_0, - PROP_CAPS, -}; - -static GstStateChangeReturn -gst_auto_video_src_change_state (GstElement * element, - GstStateChange transition); -static void gst_auto_video_src_dispose (GstAutoVideoSrc * src); -static void gst_auto_video_src_clear_kid (GstAutoVideoSrc * src); - -static void gst_auto_video_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_auto_video_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - -GST_BOILERPLATE (GstAutoVideoSrc, gst_auto_video_src, GstBin, GST_TYPE_BIN); - -static const GstElementDetails gst_auto_video_src_details = -GST_ELEMENT_DETAILS ("Auto video source", - "Source/Video", - "Wrapper video source for automatically detected video source", - "Ronald Bultje \n" - "Jan Schmidt \n" - "Stefan Kost "); - -static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static void -gst_auto_video_src_base_init (gpointer klass) -{ - GstElementClass *eklass = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (eklass, - gst_static_pad_template_get (&src_template)); - gst_element_class_set_details (eklass, &gst_auto_video_src_details); -} - -static void -gst_auto_video_src_class_init (GstAutoVideoSrcClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *eklass = GST_ELEMENT_CLASS (klass); - - gobject_class = G_OBJECT_CLASS (klass); - gobject_class->dispose = - (GObjectFinalizeFunc) GST_DEBUG_FUNCPTR (gst_auto_video_src_dispose); - eklass->change_state = GST_DEBUG_FUNCPTR (gst_auto_video_src_change_state); - gobject_class->set_property = - GST_DEBUG_FUNCPTR (gst_auto_video_src_set_property); - gobject_class->get_property = - GST_DEBUG_FUNCPTR (gst_auto_video_src_get_property); - - /** - * GstAutoVideoSrc:filter-caps - * - * This property will filter out candidate sources that can handle the specified - * caps. By default only video sources that support raw rgb and yuv video - * are selected. - * - * This property can only be set before the element goes to the READY state. - * - * Since: 0.10.14 - **/ - g_object_class_install_property (gobject_class, PROP_CAPS, - g_param_spec_boxed ("filter-caps", "Filter caps", - "Filter src candidates using these caps.", GST_TYPE_CAPS, - G_PARAM_READWRITE)); -} - -static void -gst_auto_video_src_dispose (GstAutoVideoSrc * src) -{ - gst_auto_video_src_clear_kid (src); - - if (src->filter_caps) - gst_caps_unref (src->filter_caps); - src->filter_caps = NULL; - - G_OBJECT_CLASS (parent_class)->dispose ((GObject *) src); -} - -static void -gst_auto_video_src_clear_kid (GstAutoVideoSrc * src) -{ - if (src->kid) { - gst_element_set_state (src->kid, GST_STATE_NULL); - gst_bin_remove (GST_BIN (src), src->kid); - src->kid = NULL; - } -} - -/* - * Hack to make initial linking work; ideally, this'd work even when - * no target has been assigned to the ghostpad yet. - */ - -static void -gst_auto_video_src_reset (GstAutoVideoSrc * src) -{ - GstPad *targetpad; - - /* Remove any existing element */ - gst_auto_video_src_clear_kid (src); - - /* fakesrc placeholder */ - src->kid = gst_element_factory_make ("fakesrc", "tempsrc"); - gst_bin_add (GST_BIN (src), src->kid); - - /* pad */ - targetpad = gst_element_get_static_pad (src->kid, "src"); - gst_ghost_pad_set_target (GST_GHOST_PAD (src->pad), targetpad); - gst_object_unref (targetpad); -} - -static GstStaticCaps raw_caps = - GST_STATIC_CAPS ("video/x-raw-yuv; video/x-raw-rgb"); - -static void -gst_auto_video_src_init (GstAutoVideoSrc * src, GstAutoVideoSrcClass * g_class) -{ - src->pad = gst_ghost_pad_new_no_target ("src", GST_PAD_SRC); - gst_element_add_pad (GST_ELEMENT (src), src->pad); - - gst_auto_video_src_reset (src); - - /* set the default raw video caps */ - src->filter_caps = gst_static_caps_get (&raw_caps); - - /* mark as source */ - GST_OBJECT_FLAG_UNSET (src, GST_ELEMENT_IS_SINK); -} - -static gboolean -gst_auto_video_src_factory_filter (GstPluginFeature * feature, gpointer data) -{ - guint rank; - const gchar *klass; - - /* we only care about element factories */ - if (!GST_IS_ELEMENT_FACTORY (feature)) - return FALSE; - - /* video sources */ - klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature)); - if (!(strstr (klass, "Source") && strstr (klass, "Video"))) - return FALSE; - - /* only select elements with autoplugging rank */ - rank = gst_plugin_feature_get_rank (feature); - if (rank < GST_RANK_MARGINAL) - return FALSE; - - return TRUE; -} - -static gint -gst_auto_video_src_compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2) -{ - gint diff; - - diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1); - if (diff != 0) - return diff; - return strcmp (gst_plugin_feature_get_name (f2), - gst_plugin_feature_get_name (f1)); -} - -static GstElement * -gst_auto_video_src_create_element_with_pretty_name (GstAutoVideoSrc * src, - GstElementFactory * factory) -{ - GstElement *element; - gchar *name, *marker; - - marker = g_strdup (GST_PLUGIN_FEATURE (factory)->name); - if (g_str_has_suffix (marker, "src")) - marker[strlen (marker) - 4] = '\0'; - if (g_str_has_prefix (marker, "gst")) - g_memmove (marker, marker + 3, strlen (marker + 3) + 1); - name = g_strdup_printf ("%s-actual-src-%s", GST_OBJECT_NAME (src), marker); - g_free (marker); - - element = gst_element_factory_create (factory, name); - g_free (name); - - return element; -} - -static GstElement * -gst_auto_video_src_find_best (GstAutoVideoSrc * src) -{ - GList *list, *item; - GstElement *choice = NULL; - GstMessage *message = NULL; - GSList *errors = NULL; - GstBus *bus = gst_bus_new (); - GstPad *el_pad = NULL; - GstCaps *el_caps = NULL, *intersect = NULL; - gboolean no_match = TRUE; - - list = gst_registry_feature_filter (gst_registry_get_default (), - (GstPluginFeatureFilter) gst_auto_video_src_factory_filter, FALSE, src); - list = g_list_sort (list, (GCompareFunc) gst_auto_video_src_compare_ranks); - - GST_LOG_OBJECT (src, "Trying to find usable video devices ..."); - - for (item = list; item != NULL; item = item->next) { - GstElementFactory *f = GST_ELEMENT_FACTORY (item->data); - GstElement *el; - - if ((el = gst_auto_video_src_create_element_with_pretty_name (src, f))) { - GstStateChangeReturn ret; - - GST_DEBUG_OBJECT (src, "Testing %s", GST_PLUGIN_FEATURE (f)->name); - - /* If AutoVideoSrc has been provided with filter caps, - * accept only sources that match with the filter caps */ - if (src->filter_caps) { - el_pad = gst_element_get_static_pad (GST_ELEMENT (el), "src"); - el_caps = gst_pad_get_caps (el_pad); - gst_object_unref (el_pad); - GST_DEBUG_OBJECT (src, - "Checking caps: %" GST_PTR_FORMAT " vs. %" GST_PTR_FORMAT, - src->filter_caps, el_caps); - intersect = gst_caps_intersect (src->filter_caps, el_caps); - no_match = gst_caps_is_empty (intersect); - gst_caps_unref (el_caps); - gst_caps_unref (intersect); - - if (no_match) { - GST_DEBUG_OBJECT (src, "Incompatible caps"); - gst_object_unref (el); - continue; - } else { - GST_DEBUG_OBJECT (src, "Found compatible caps"); - } - } - - gst_element_set_bus (el, bus); - ret = gst_element_set_state (el, GST_STATE_READY); - if (ret == GST_STATE_CHANGE_SUCCESS) { - GST_DEBUG_OBJECT (src, "This worked!"); - choice = el; - break; - } - - /* collect all error messages */ - while ((message = gst_bus_pop_filtered (bus, GST_MESSAGE_ERROR))) { - GST_DEBUG_OBJECT (src, "error message %" GST_PTR_FORMAT, message); - errors = g_slist_append (errors, message); - } - - gst_element_set_state (el, GST_STATE_NULL); - gst_object_unref (el); - } - } - - GST_DEBUG_OBJECT (src, "done trying"); - if (!choice) { - if (errors) { - /* FIXME: we forward the first error for now; but later on it might make - * sense to actually analyse them */ - gst_message_ref (GST_MESSAGE (errors->data)); - GST_DEBUG_OBJECT (src, "reposting message %p", errors->data); - gst_element_post_message (GST_ELEMENT (src), GST_MESSAGE (errors->data)); - } else { - /* send warning message to application and use a fakesrc */ - GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL), - ("Failed to find a usable video source")); - choice = gst_element_factory_make ("fakesrc", "fake-video-src"); - if (g_object_class_find_property (G_OBJECT_GET_CLASS (choice), "sync")) - g_object_set (choice, "sync", TRUE, NULL); - gst_element_set_state (choice, GST_STATE_READY); - } - } - gst_object_unref (bus); - gst_plugin_feature_list_free (list); - g_slist_foreach (errors, (GFunc) gst_mini_object_unref, NULL); - g_slist_free (errors); - - return choice; -} - -static gboolean -gst_auto_video_src_detect (GstAutoVideoSrc * src) -{ - GstElement *esrc; - GstPad *targetpad; - - gst_auto_video_src_clear_kid (src); - - /* find element */ - GST_DEBUG_OBJECT (src, "Creating new kid"); - if (!(esrc = gst_auto_video_src_find_best (src))) - goto no_src; - - src->kid = esrc; - gst_bin_add (GST_BIN (src), esrc); - - /* attach ghost pad */ - GST_DEBUG_OBJECT (src, "Re-assigning ghostpad"); - targetpad = gst_element_get_static_pad (src->kid, "src"); - if (!gst_ghost_pad_set_target (GST_GHOST_PAD (src->pad), targetpad)) - goto target_failed; - - gst_object_unref (targetpad); - GST_DEBUG_OBJECT (src, "done changing auto video source"); - - return TRUE; - - /* ERRORS */ -no_src: - { - GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), - ("Failed to find a supported video source")); - return FALSE; - } -target_failed: - { - GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL), - ("Failed to set target pad")); - gst_object_unref (targetpad); - return FALSE; - } -} - -static GstStateChangeReturn -gst_auto_video_src_change_state (GstElement * element, - GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstAutoVideoSrc *src = GST_AUTO_VIDEO_SRC (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - if (!gst_auto_video_src_detect (src)) - return GST_STATE_CHANGE_FAILURE; - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_NULL: - gst_auto_video_src_reset (src); - break; - default: - break; - } - - return ret; -} - -static void -gst_auto_video_src_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstAutoVideoSrc *src = GST_AUTO_VIDEO_SRC (object); - - switch (prop_id) { - case PROP_CAPS: - if (src->filter_caps) - gst_caps_unref (src->filter_caps); - src->filter_caps = gst_caps_copy (gst_value_get_caps (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_auto_video_src_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstAutoVideoSrc *src = GST_AUTO_VIDEO_SRC (object); - - switch (prop_id) { - case PROP_CAPS:{ - gst_value_set_caps (value, src->filter_caps); - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/autodetect/gstautovideosrc.h --- a/gst_plugins_good/gst/autodetect/gstautovideosrc.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* GStreamer - * (c) 2005 Ronald S. Bultje - * (c) 2008 Stefan Kost - * - * 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. - */ - -#ifndef __GST_AUTO_VIDEO_SRC_H__ -#define __GST_AUTO_VIDEO_SRC_H__ - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_AUTO_VIDEO_SRC \ - (gst_auto_video_src_get_type ()) -#define GST_AUTO_VIDEO_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AUTO_VIDEO_SRC, \ - GstAutoVideoSrc)) -#define GST_AUTO_VIDEO_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AUTO_VIDEO_SRC, \ - GstAutoVideoSrcClass)) -#define GST_IS_AUTO_VIDEO_SRC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AUTO_VIDEO_SRC)) -#define GST_IS_AUTO_VIDEO_SRC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AUTO_VIDEO_SRC)) - -typedef struct _GstAutoVideoSrc { - GstBin parent; - - /* explicit pointers to stuff used */ - GstPad *pad; - GstElement *kid; - GstCaps *filter_caps; -} GstAutoVideoSrc; - -typedef struct _GstAutoVideoSrcClass { - GstBinClass parent_class; -} GstAutoVideoSrcClass; - -#ifdef __SYMBIAN32__ -IMPORT_C -#endif -GType gst_auto_video_src_get_type (void); - -G_END_DECLS - -#endif /* __GST_AUTO_VIDEO_SRC_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/avi/README --- a/gst_plugins_good/gst/avi/README Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -The avi decoder plugins ------------------------ - -The avi decoder consists of a set of gstreamer plugins: - - - demuxer (avidemux) - - avi to gstreamer type converter (avitypes) - - windows dlls wrappers. - -the avidecoder element uses the above plugins to perform the avi -decoding. It is constructed as a custom bin which initially only has -the demuxer element in it. The demuxer has a set of padtemplates for -raw audio and video. - - (------------------------------------) - ! avidecoder ! - ! (video/raw)... - ! (----------) ! - ! ! demuxer (video/x-msvideo, auds).. - ! ! ! ! - ! -src ! ! - ! / ! (video/x-msvideo, vids).. - - src ! ! ! - ! (----------) (audio/raw)... - ! ! - (------------------------------------) - -the demuxer has a set of padtemplates for the raw avi header properties. - -The avi decoder will act on the new_pad signal of the demuxer element -and will attach an avitype plugin to the new pad. Caps negotiation will -convert the raw avi caps to the gstreamer caps. If the src pad of the -avitypes plugin are compatible with the avidecoder padtemplate, the -avitype pad is ghosted to the avidecoder bin, this is the case where no -codec is needed (for raw PCM samples, for example). - -When the avitypes caps are not compatible with one of the avidecoder -templates, a static autoplugger is used the find an element to connect -the demuxers pad to the decoders padtemplate. - -When no element could be found, an windec plugin is attached to the -demuxers pad and the avitypes plugin is removed from the decoder. - - -example: --------- - - An avidecoder that has a video pad (decoded with windows dlls) and an - audio pad (raw PCM). - - (----------------------------------------------------------------) - ! avidecoder (--------) (------) ! - ! !avitypes! !windec! /-- (video/raw) - ! (----------) /-sink src--sink src ----- ! - ! !demuxer (video/x-msvideo, ! ! ! ! - ! ! ! auds).. (--------) (------) ! - ! -sink ! (--------) ! - ! / ! (video/x-..,!avitypes! ! - -sink ! ! vids).. ! ! ! - ! (----------) \-sink src -------------------- (audio/raw) - ! (--------) ! - (----------------------------------------------------------------) - - - -TODO ----- - -automatically generate the padtemplates from all possible avi types -found in the registry. - - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/avi/avi-ids.h --- a/gst_plugins_good/gst/avi/avi-ids.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* GStreamer - * 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. - */ - -#ifndef __GST_AVI_H__ -#define __GST_AVI_H__ - -#include - -typedef struct _gst_riff_avih { - guint32 us_frame; /* microsec per frame */ - guint32 max_bps; /* byte/s overall */ - guint32 pad_gran; /* pad_granularity */ - guint32 flags; -/* flags values */ -#define GST_RIFF_AVIH_HASINDEX 0x00000010 /* has idx1 chunk */ -#define GST_RIFF_AVIH_MUSTUSEINDEX 0x00000020 /* must use idx1 chunk to determine order */ -#define GST_RIFF_AVIH_ISINTERLEAVED 0x00000100 /* AVI file is interleaved */ -#define GST_RIFF_AVIH_WASCAPTUREFILE 0x00010000 /* specially allocated used for capturing real time video */ -#define GST_RIFF_AVIH_COPYRIGHTED 0x00020000 /* contains copyrighted data */ - guint32 tot_frames; /* # of frames (all) */ - guint32 init_frames; /* initial frames (???) */ - guint32 streams; - guint32 bufsize; /* suggested buffer size */ - guint32 width; - guint32 height; - guint32 scale; - guint32 rate; - guint32 start; - guint32 length; -} gst_riff_avih; - -/* vprp (video properties) ODML header */ -/* see ODML spec for some/more explanation */ -#define GST_RIFF_TAG_vprp GST_MAKE_FOURCC ('v','p','r','p') -#define GST_RIFF_VPRP_VIDEO_FIELDS (2) - -typedef struct _gst_riff_vprp_video_field_desc { - guint32 compressed_bm_height; - guint32 compressed_bm_width; - guint32 valid_bm_height; - guint32 valid_bm_width; - guint32 valid_bm_x_offset; - guint32 valid_bm_y_offset; - guint32 video_x_t_offset; - guint32 video_y_start; -} gst_riff_vprp_video_field_desc; - -typedef struct _gst_riff_vprp { - guint32 format_token; /* whether fields defined by standard */ - guint32 standard; /* video display standard, UNKNOWN, PAL, etc */ - guint32 vert_rate; /* vertical refresh rate */ - guint32 hor_t_total; /* width */ - guint32 vert_lines; /* height */ - guint32 aspect; /* aspect ratio high word:low word */ - guint32 width; /* active width */ - guint32 height; /* active height */ - guint32 fields; /* field count */ - gst_riff_vprp_video_field_desc field_info[GST_RIFF_VPRP_VIDEO_FIELDS]; -} gst_riff_vprp; - -#endif /* __GST_AVI_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/avi/gstavi.c --- a/gst_plugins_good/gst/avi/gstavi.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * gstavi.c: plugin registering - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gst/gst-i18n-plugin.h" - -#include "gstavidemux.h" -#include "gstavimux.h" -#include "gstavisubtitle.h" - -static gboolean -plugin_init (GstPlugin * plugin) -{ - gst_riff_init (); - -#ifdef ENABLE_NLS - setlocale (LC_ALL, ""); - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); -#endif /* ENABLE_NLS */ - - if (!gst_element_register (plugin, "avidemux", GST_RANK_PRIMARY, - GST_TYPE_AVI_DEMUX) || - !gst_element_register (plugin, "avimux", GST_RANK_PRIMARY, - GST_TYPE_AVI_MUX) || - !gst_element_register (plugin, "avisubtitle", GST_RANK_PRIMARY, - GST_TYPE_AVI_SUBTITLE)) { - return FALSE; - } - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "avi", - "AVI stream handling", - plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) - -#ifdef SYMBIAN -EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC() -{ - return &gst_plugin_desc; -} - -#endif diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/avi/gstavidemux.c --- a/gst_plugins_good/gst/avi/gstavidemux.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4574 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2006> Nokia Corporation (contact ) - * - * 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. - */ -/* Element-Checklist-Version: 5 */ - -/** - * SECTION:element-avidemux - * - * Demuxes an .avi file into raw or compressed audio and/or video streams. - * - * This element supports both push and pull-based scheduling, depending on the - * capabilities of the upstream elements. - * - * - * Example launch line - * |[ - * gst-launch filesrc location=test.avi ! avidemux name=demux demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink - * ]| Play (parse and decode) an .avi file and try to output it to - * an automatically detected soundcard and videosink. If the AVI file contains - * compressed audio or video data, this will only work if you have the - * right decoder elements/plugins installed. - * - * - * Last reviewed on 2006-12-29 (0.10.6) - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "gst/riff/riff-media.h" -#include "gstavidemux.h" -#include "avi-ids.h" -#include -#include - -GST_DEBUG_CATEGORY_STATIC (avidemux_debug); -#define GST_CAT_DEFAULT avidemux_debug - -GST_DEBUG_CATEGORY_EXTERN (GST_CAT_EVENT); - -static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-msvideo") - ); - -static void gst_avi_demux_base_init (GstAviDemuxClass * klass); -static void gst_avi_demux_class_init (GstAviDemuxClass * klass); -static void gst_avi_demux_init (GstAviDemux * avi); -static void gst_avi_demux_finalize (GObject * object); - -static void gst_avi_demux_reset (GstAviDemux * avi); - -#if 0 -static const GstEventMask *gst_avi_demux_get_event_mask (GstPad * pad); -#endif -static gboolean gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event); -static gboolean gst_avi_demux_handle_sink_event (GstPad * pad, - GstEvent * event); -static gboolean gst_avi_demux_push_event (GstAviDemux * avi, GstEvent * event); - -#if 0 -static const GstFormat *gst_avi_demux_get_src_formats (GstPad * pad); -#endif -static const GstQueryType *gst_avi_demux_get_src_query_types (GstPad * pad); -static gboolean gst_avi_demux_handle_src_query (GstPad * pad, GstQuery * query); -static gboolean gst_avi_demux_src_convert (GstPad * pad, GstFormat src_format, - gint64 src_value, GstFormat * dest_format, gint64 * dest_value); - -static gboolean gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment); -static gboolean gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad, - GstEvent * event); -static void gst_avi_demux_loop (GstPad * pad); -static gboolean gst_avi_demux_sink_activate (GstPad * sinkpad); -static gboolean gst_avi_demux_sink_activate_pull (GstPad * sinkpad, - gboolean active); -static gboolean gst_avi_demux_activate_push (GstPad * pad, gboolean active); -static GstFlowReturn gst_avi_demux_chain (GstPad * pad, GstBuffer * buf); - -static GstStateChangeReturn gst_avi_demux_change_state (GstElement * element, - GstStateChange transition); - -static GstElementClass *parent_class = NULL; - -/* GObject methods */ - -GType -gst_avi_demux_get_type (void) -{ - static GType avi_demux_type = 0; - - if (!avi_demux_type) { - static const GTypeInfo avi_demux_info = { - sizeof (GstAviDemuxClass), - (GBaseInitFunc) gst_avi_demux_base_init, - NULL, - (GClassInitFunc) gst_avi_demux_class_init, - NULL, - NULL, - sizeof (GstAviDemux), - 0, - (GInstanceInitFunc) gst_avi_demux_init, - }; - - avi_demux_type = - g_type_register_static (GST_TYPE_ELEMENT, - "GstAviDemux", &avi_demux_info, 0); - } - - return avi_demux_type; -} - -static void -gst_avi_demux_base_init (GstAviDemuxClass * klass) -{ - static const GstElementDetails gst_avi_demux_details = - GST_ELEMENT_DETAILS ("Avi demuxer", - "Codec/Demuxer", - "Demultiplex an avi file into audio and video", - "Erik Walthinsen \n" - "Wim Taymans \n" - "Ronald Bultje \n" - "Thijs Vermeir "); - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - GstPadTemplate *videosrctempl, *audiosrctempl, *subsrctempl; - GstCaps *audcaps, *vidcaps, *subcaps; - - audcaps = gst_riff_create_audio_template_caps (); - gst_caps_append (audcaps, gst_caps_new_simple ("audio/x-avi-unknown", NULL)); - audiosrctempl = gst_pad_template_new ("audio_%02d", - GST_PAD_SRC, GST_PAD_SOMETIMES, audcaps); - - vidcaps = gst_riff_create_video_template_caps (); - gst_caps_append (vidcaps, gst_riff_create_iavs_template_caps ()); - gst_caps_append (vidcaps, gst_caps_new_simple ("video/x-avi-unknown", NULL)); - videosrctempl = gst_pad_template_new ("video_%02d", - GST_PAD_SRC, GST_PAD_SOMETIMES, vidcaps); - - subcaps = gst_caps_new_simple ("application/x-subtitle-avi", NULL); - subsrctempl = gst_pad_template_new ("subtitle_%02d", - GST_PAD_SRC, GST_PAD_SOMETIMES, subcaps); - gst_element_class_add_pad_template (element_class, audiosrctempl); - gst_element_class_add_pad_template (element_class, videosrctempl); - gst_element_class_add_pad_template (element_class, subsrctempl); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_templ)); - gst_element_class_set_details (element_class, &gst_avi_demux_details); -} - -static void -gst_avi_demux_class_init (GstAviDemuxClass * klass) -{ - GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); - GObjectClass *gobject_class = (GObjectClass *) klass; - - GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux", - 0, "Demuxer for AVI streams"); - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->finalize = gst_avi_demux_finalize; - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_avi_demux_change_state); -} - -static void -gst_avi_demux_init (GstAviDemux * avi) -{ - avi->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink"); - gst_pad_set_activate_function (avi->sinkpad, - GST_DEBUG_FUNCPTR (gst_avi_demux_sink_activate)); - gst_pad_set_activatepull_function (avi->sinkpad, - GST_DEBUG_FUNCPTR (gst_avi_demux_sink_activate_pull)); - gst_pad_set_activatepush_function (avi->sinkpad, - GST_DEBUG_FUNCPTR (gst_avi_demux_activate_push)); - gst_pad_set_chain_function (avi->sinkpad, - GST_DEBUG_FUNCPTR (gst_avi_demux_chain)); - gst_pad_set_event_function (avi->sinkpad, - GST_DEBUG_FUNCPTR (gst_avi_demux_handle_sink_event)); - gst_element_add_pad (GST_ELEMENT (avi), avi->sinkpad); - - avi->adapter = gst_adapter_new (); - - gst_avi_demux_reset (avi); -} - -static void -gst_avi_demux_finalize (GObject * object) -{ - GstAviDemux *avi = GST_AVI_DEMUX (object); - - GST_DEBUG ("AVI: finalize"); - - g_object_unref (avi->adapter); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_avi_demux_reset (GstAviDemux * avi) -{ - gint i; - - GST_DEBUG ("AVI: reset"); - - for (i = 0; i < avi->num_streams; i++) { - g_free (avi->stream[i].strh); - g_free (avi->stream[i].strf.data); - if (avi->stream[i].name) - g_free (avi->stream[i].name); - if (avi->stream[i].initdata) - gst_buffer_unref (avi->stream[i].initdata); - if (avi->stream[i].extradata) - gst_buffer_unref (avi->stream[i].extradata); - if (avi->stream[i].pad) { - gst_pad_set_active (avi->stream[i].pad, FALSE); - gst_element_remove_pad (GST_ELEMENT (avi), avi->stream[i].pad); - } - if (avi->stream[i].taglist) { - gst_tag_list_free (avi->stream[i].taglist); - avi->stream[i].taglist = NULL; - } - } - memset (&avi->stream, 0, sizeof (avi->stream)); - - avi->header_state = GST_AVI_DEMUX_HEADER_TAG_LIST; - avi->num_streams = 0; - avi->num_v_streams = 0; - avi->num_a_streams = 0; - avi->num_t_streams = 0; - - avi->state = GST_AVI_DEMUX_START; - avi->offset = 0; - - g_free (avi->index_entries); - avi->index_entries = NULL; - avi->index_size = 0; - avi->index_offset = 0; - avi->current_entry = 0; - g_free (avi->avih); - avi->avih = NULL; - - if (avi->seek_event) { - gst_event_unref (avi->seek_event); - avi->seek_event = NULL; - } - - if (avi->globaltags) - gst_tag_list_free (avi->globaltags); - avi->globaltags = NULL; - - avi->got_tags = TRUE; /* we always want to push global tags */ - avi->have_eos = FALSE; - - gst_adapter_clear (avi->adapter); - - gst_segment_init (&avi->segment, GST_FORMAT_TIME); -} - -/* Index helper */ -static gst_avi_index_entry * -gst_avi_demux_index_last (GstAviDemux * avi, gint stream_nr) -{ - gint i; - gst_avi_index_entry *result = NULL; - - for (i = avi->index_size - 1; i >= 0; i--) { - if (avi->index_entries[i].stream_nr == stream_nr) { - result = &avi->index_entries[i]; - break; - } - } - return result; -} - -static gst_avi_index_entry * -gst_avi_demux_index_next (GstAviDemux * avi, gint stream_nr, gint last, - guchar flags) -{ - gint i; - gst_avi_index_entry *result = NULL, *entry; - - for (i = last + 1; i < avi->index_size; i++) { - entry = &avi->index_entries[i]; - - if (entry->stream_nr != stream_nr) - continue; - - if ((entry->flags & flags) == flags) { - result = entry; - break; - } - } - return result; -} - -static gst_avi_index_entry * -gst_avi_demux_index_prev (GstAviDemux * avi, gint stream_nr, gint last, - guchar flags) -{ - gint i; - gst_avi_index_entry *result = NULL, *entry; - - for (i = last - 1; i >= 0; i--) { - entry = &avi->index_entries[i]; - - if (entry->stream_nr != stream_nr) - continue; - - if ((entry->flags & flags) == flags) { - result = entry; - break; - } - } - return result; -} - -static gint -gst_avi_demux_index_entry_search (gst_avi_index_entry * entry, guint64 * time) -{ - if (entry->ts < *time) - return -1; - else if (entry->ts > *time) - return 1; - return 0; -} - -/* - * gst_avi_index_entry: - * @avi: Avi object - * @stream_nr: stream number - * @time: seek time position - * - * Finds the index entry which time is less or equal than the requested time. - * - * Returns: the found index entry or %NULL - */ -static gst_avi_index_entry * -gst_avi_demux_index_entry_for_time (GstAviDemux * avi, - gint stream_nr, guint64 time) -{ - gst_avi_index_entry *entry = NULL; - guint n; - - GST_LOG_OBJECT (avi, "stream_nr:%d , time:%" GST_TIME_FORMAT, - stream_nr, GST_TIME_ARGS (time)); - - entry = gst_util_array_binary_search (avi->index_entries, - avi->index_size, - sizeof (gst_avi_index_entry), - (GCompareDataFunc) gst_avi_demux_index_entry_search, - GST_SEARCH_MODE_BEFORE, &time, NULL); - - n = entry - avi->index_entries; - if (entry == NULL) { - entry = &avi->index_entries[0]; - n = 0; - while (entry->stream_nr != stream_nr && n < avi->index_size - 1) { - n++; - entry = &avi->index_entries[n]; - } - } else if (entry->stream_nr != stream_nr) { - while (entry->stream_nr != stream_nr && n > 0) { - n--; - entry = &avi->index_entries[n]; - } - } - - GST_LOG_OBJECT (avi, - "best at entry %u / ts:%" GST_TIME_FORMAT " / dur:%" GST_TIME_FORMAT - " flags:%02x", n, GST_TIME_ARGS (entry->ts), GST_TIME_ARGS (entry->dur), - entry->flags); - - return entry; -} - -/* GstElement methods */ - -#if 0 -static const GstFormat * -gst_avi_demux_get_src_formats (GstPad * pad) -{ - avi_stream_context *stream = gst_pad_get_element_private (pad); - - static const GstFormat src_a_formats[] = { - GST_FORMAT_TIME, - GST_FORMAT_BYTES, - GST_FORMAT_DEFAULT, - 0 - }; - static const GstFormat src_v_formats[] = { - GST_FORMAT_TIME, - GST_FORMAT_DEFAULT, - 0 - }; - - return (stream->strh->type == GST_RIFF_FCC_auds ? - src_a_formats : src_v_formats); -} -#endif - -/* assumes stream->strf.auds->av_bps != 0 */ -static inline GstClockTime -avi_stream_convert_bytes_to_time_unchecked (avi_stream_context * stream, - guint64 bytes) -{ - return gst_util_uint64_scale (bytes, GST_SECOND, stream->strf.auds->av_bps); -} - -/* assumes stream->strh->rate != 0 */ -static inline GstClockTime -avi_stream_convert_frames_to_time_unchecked (avi_stream_context * stream, - guint64 frames) -{ - return gst_util_uint64_scale (frames, stream->strh->scale * GST_SECOND, - stream->strh->rate); -} - -static gboolean -gst_avi_demux_src_convert (GstPad * pad, - GstFormat src_format, - gint64 src_value, GstFormat * dest_format, gint64 * dest_value) -{ - avi_stream_context *stream = gst_pad_get_element_private (pad); - gboolean res = TRUE; - - GST_LOG_OBJECT (pad, - "Received src_format:%s, src_value:%" G_GUINT64_FORMAT - ", dest_format:%s", gst_format_get_name (src_format), src_value, - gst_format_get_name (*dest_format)); - - if (G_UNLIKELY (src_format == *dest_format)) { - *dest_value = src_value; - goto done; - } - if (G_UNLIKELY (!stream->strh || !stream->strf.data)) { - res = FALSE; - goto done; - } - if (G_UNLIKELY (stream->strh->type == GST_RIFF_FCC_vids && - (src_format == GST_FORMAT_BYTES - || *dest_format == GST_FORMAT_BYTES))) { - res = FALSE; - goto done; - } - - switch (src_format) { - case GST_FORMAT_TIME: - switch (*dest_format) { - case GST_FORMAT_BYTES: - *dest_value = gst_util_uint64_scale (src_value, - (guint64) stream->strf.auds->av_bps, GST_SECOND); - break; - case GST_FORMAT_DEFAULT: - { - gdouble error; - - *dest_value = gst_util_uint64_scale (src_value, stream->strh->rate, - stream->strh->scale * GST_SECOND); - - /* Attempt to round to nearest integer: if the difference is more - * than 0.5 (less than -0.5), it means that gst_util_uint64_scale() - * just truncated an integer, while it had to be rounded - */ - error = *dest_value * GST_SECOND - - src_value * stream->strh->rate / stream->strh->scale; - if (error <= -0.5) - *dest_value += 1; - break; - } - default: - res = FALSE; - break; - } - break; - case GST_FORMAT_BYTES: - switch (*dest_format) { - case GST_FORMAT_TIME: - if (stream->strf.auds->av_bps != 0) { - *dest_value = avi_stream_convert_bytes_to_time_unchecked (stream, - src_value); - } else - res = FALSE; - break; - default: - res = FALSE; - break; - } - break; - case GST_FORMAT_DEFAULT: - switch (*dest_format) { - case GST_FORMAT_TIME: - *dest_value = - avi_stream_convert_frames_to_time_unchecked (stream, src_value); - break; - default: - res = FALSE; - break; - } - break; - default: - res = FALSE; - } - -done: - GST_LOG_OBJECT (pad, - "Returning res:%d dest_format:%s dest_value:%" G_GUINT64_FORMAT, res, - gst_format_get_name (*dest_format), *dest_value); - return res; -} - -static const GstQueryType * -gst_avi_demux_get_src_query_types (GstPad * pad) -{ - static const GstQueryType src_types[] = { - GST_QUERY_POSITION, - GST_QUERY_DURATION, - GST_QUERY_SEEKING, - GST_QUERY_CONVERT, - 0 - }; - - return src_types; -} - -static gboolean -gst_avi_demux_handle_src_query (GstPad * pad, GstQuery * query) -{ - gboolean res = TRUE; - GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad)); - - avi_stream_context *stream = gst_pad_get_element_private (pad); - - if (!stream->strh || !stream->strf.data) - return gst_pad_query_default (pad, query); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION:{ - gint64 pos = 0; - - GST_DEBUG ("pos query for stream %d: frames %d, bytes %" G_GUINT64_FORMAT, - stream->num, stream->current_frame, stream->current_byte); - - if (stream->strh->type == GST_RIFF_FCC_auds) { - if (stream->is_vbr) { - /* VBR */ - pos = gst_util_uint64_scale ((gint64) stream->current_frame * - stream->strh->scale, GST_SECOND, (guint64) stream->strh->rate); - GST_DEBUG_OBJECT (avi, "VBR convert frame %u, time %" - GST_TIME_FORMAT, stream->current_frame, GST_TIME_ARGS (pos)); - } else if (stream->strf.auds->av_bps != 0) { - /* CBR */ - pos = gst_util_uint64_scale (stream->current_byte, GST_SECOND, - (guint64) stream->strf.auds->av_bps); - GST_DEBUG_OBJECT (avi, - "CBR convert bytes %" G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT, - stream->current_byte, GST_TIME_ARGS (pos)); - } else if (stream->total_frames != 0 && stream->total_bytes != 0) { - /* calculate timestamps based on percentage of length */ - guint64 xlen = avi->avih->us_frame * - avi->avih->tot_frames * GST_USECOND; - - if (stream->is_vbr) { - pos = gst_util_uint64_scale (xlen, stream->current_frame, - stream->total_frames); - GST_DEBUG_OBJECT (avi, "VBR perc convert frame %u, time %" - GST_TIME_FORMAT, stream->current_frame, GST_TIME_ARGS (pos)); - } else { - pos = gst_util_uint64_scale (xlen, stream->current_byte, - stream->total_bytes); - GST_DEBUG_OBJECT (avi, "CBR perc convert bytes %" G_GUINT64_FORMAT - ", time %" GST_TIME_FORMAT, stream->current_byte, - GST_TIME_ARGS (pos)); - } - } else { - /* we don't know */ - res = FALSE; - } - } else { - if (stream->strh->rate != 0) { - pos = gst_util_uint64_scale ((guint64) stream->current_frame * - stream->strh->scale, GST_SECOND, (guint64) stream->strh->rate); - } else { - pos = stream->current_frame * avi->avih->us_frame * GST_USECOND; - } - } - if (res) { - GST_DEBUG ("pos query : %" GST_TIME_FORMAT, GST_TIME_ARGS (pos)); - gst_query_set_position (query, GST_FORMAT_TIME, pos); - } else - GST_WARNING ("pos query failed"); - break; - } - case GST_QUERY_DURATION: - { - GstFormat fmt; - - if (stream->strh->type != GST_RIFF_FCC_auds && - stream->strh->type != GST_RIFF_FCC_vids) { - res = FALSE; - break; - } - - gst_query_parse_duration (query, &fmt, NULL); - - switch (fmt) { - case GST_FORMAT_TIME: - gst_query_set_duration (query, fmt, stream->duration); - break; - case GST_FORMAT_DEFAULT: - { - gint64 dur; - GST_DEBUG_OBJECT (query, "total frames is %" G_GUINT32_FORMAT, - stream->total_frames); - - if (stream->total_frames >= 0) - gst_query_set_duration (query, fmt, stream->total_frames); - else if (gst_pad_query_convert (pad, GST_FORMAT_TIME, - stream->duration, &fmt, &dur)) - gst_query_set_duration (query, fmt, dur); - break; - } - default: - res = FALSE; - break; - } - break; - } - case GST_QUERY_SEEKING:{ - GstFormat fmt; - - gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL); - if (fmt == GST_FORMAT_TIME) { - gboolean seekable = TRUE; - - if (avi->streaming) { - seekable = FALSE; - } else { - if (avi->index_entries == NULL) { - seekable = FALSE; - /* FIXME: when building index_entried, count keyframes - if (!(avi->key_frame_ct > 1)) - seekable = FALSE; - */ - } - } - - gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, - 0, stream->duration); - res = TRUE; - } - break; - } - case GST_QUERY_CONVERT:{ - GstFormat src_fmt, dest_fmt; - gint64 src_val, dest_val; - - gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); - if ((res = gst_avi_demux_src_convert (pad, src_fmt, src_val, &dest_fmt, - &dest_val))) - gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); - else - res = gst_pad_query_default (pad, query); - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } - - gst_object_unref (avi); - return res; -} - -#if 0 -static const GstEventMask * -gst_avi_demux_get_event_mask (GstPad * pad) -{ - static const GstEventMask masks[] = { - {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT}, - {0,} - }; - - return masks; -} -#endif - -static gboolean -gst_avi_demux_handle_sink_event (GstPad * pad, GstEvent * event) -{ - gboolean res = TRUE; - GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad)); - - GST_DEBUG_OBJECT (avi, - "have event type %s: %p on sink pad", GST_EVENT_TYPE_NAME (event), event); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - /* Drop NEWSEGMENT events, new ones are generated later */ - gst_event_unref (event); - break; - case GST_EVENT_EOS: - { - if (avi->state != GST_AVI_DEMUX_MOVI) { - gst_event_unref (event); - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, - (NULL), ("got eos and didn't receive a complete header object")); - } else if (!gst_avi_demux_push_event (avi, event)) { - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, - (NULL), ("got eos but no streams (yet)")); - } - break; - } - default: - res = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (avi); - - return res; -} - -static gboolean -gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event) -{ - gboolean res = TRUE; - GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad)); - - GST_DEBUG_OBJECT (avi, - "have event type %s: %p on src pad", GST_EVENT_TYPE_NAME (event), event); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - /* handle seeking only in pull mode */ - if (!avi->streaming) { - res = gst_avi_demux_handle_seek (avi, pad, event); - gst_event_unref (event); - } else { - res = gst_pad_event_default (pad, event); - } - break; - case GST_EVENT_QOS: - case GST_EVENT_NAVIGATION: - res = FALSE; - gst_event_unref (event); - break; - default: - res = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (avi); - - return res; -} - -/* streaming helper (push) */ - -/* - * gst_avi_demux_peek_chunk_info: - * @avi: Avi object - * @tag: holder for tag - * @size: holder for tag size - * - * Peek next chunk info (tag and size) - * - * Returns: TRUE when one chunk info has been got - */ -static gboolean -gst_avi_demux_peek_chunk_info (GstAviDemux * avi, guint32 * tag, guint32 * size) -{ - const guint8 *data = NULL; - - if (gst_adapter_available (avi->adapter) < 8) { - return FALSE; - } - - data = gst_adapter_peek (avi->adapter, 8); - *tag = GST_READ_UINT32_LE (data); - *size = GST_READ_UINT32_LE (data + 4); - - return TRUE; -} - -/* - * gst_avi_demux_peek_chunk: - * @avi: Avi object - * @tag: holder for tag - * @size: holder for tag size - * - * Peek enough data for one full chunk - * - * Returns: %TRUE when one chunk has been got - */ -static gboolean -gst_avi_demux_peek_chunk (GstAviDemux * avi, guint32 * tag, guint32 * size) -{ - guint32 peek_size = 0; - gint available; - - if (!gst_avi_demux_peek_chunk_info (avi, tag, size)) { - return FALSE; - } - /* FIXME: shouldn't this check go to gst_avi_demux_peek_chunk_info() already */ - if (!(*size) || (*size) == -1) { - GST_INFO ("Invalid chunk size %d for tag %" GST_FOURCC_FORMAT, - *size, GST_FOURCC_ARGS (*tag)); - return FALSE; - } - peek_size = (*size + 1) & ~1; - available = gst_adapter_available (avi->adapter); - - GST_DEBUG ("Need to peek chunk of %d bytes to read chunk %" GST_FOURCC_FORMAT - ", %d bytes available", *size, GST_FOURCC_ARGS (*tag), available); - - if (available >= (8 + peek_size)) { - return TRUE; - } else { - return FALSE; - } -} - -/* AVI init */ - -/* - * gst_avi_demux_parse_file_header: - * @element: caller element (used for errors/debug). - * @buf: input data to be used for parsing. - * - * "Open" a RIFF/AVI file. The buffer should be at least 12 - * bytes long. Takes ownership of @buf. - * - * Returns: TRUE if the file is a RIFF/AVI file, FALSE otherwise. - * Throws an error, caller should error out (fatal). - */ -static gboolean -gst_avi_demux_parse_file_header (GstElement * element, GstBuffer * buf) -{ - guint32 doctype; - - /* riff_parse posts an error */ - if (!gst_riff_parse_file_header (element, buf, &doctype)) - return FALSE; - - if (doctype != GST_RIFF_RIFF_AVI) - goto not_avi; - - return TRUE; - - /* ERRORS */ -not_avi: - { - GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL), - ("File is not an AVI file: %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (doctype))); - return FALSE; - } -} - -/* - * Read AVI file tag when streaming - */ -static GstFlowReturn -gst_avi_demux_stream_init_push (GstAviDemux * avi) -{ - if (gst_adapter_available (avi->adapter) >= 12) { - GstBuffer *tmp; - - tmp = gst_adapter_take_buffer (avi->adapter, 12); - - GST_DEBUG ("Parsing avi header"); - if (!gst_avi_demux_parse_file_header (GST_ELEMENT (avi), tmp)) { - return GST_FLOW_ERROR; - } - GST_DEBUG ("header ok"); - avi->offset += 12; - - avi->state = GST_AVI_DEMUX_HEADER; - } - return GST_FLOW_OK; -} - -/* - * Read AVI file tag - */ -static GstFlowReturn -gst_avi_demux_stream_init_pull (GstAviDemux * avi) -{ - GstFlowReturn res; - GstBuffer *buf = NULL; - - res = gst_pad_pull_range (avi->sinkpad, avi->offset, 12, &buf); - if (res != GST_FLOW_OK) - return res; - else if (!gst_avi_demux_parse_file_header (GST_ELEMENT_CAST (avi), buf)) - goto wrong_header; - - avi->offset += 12; - - return GST_FLOW_OK; - - /* ERRORS */ -wrong_header: - { - GST_DEBUG_OBJECT (avi, "error parsing file header"); - return GST_FLOW_ERROR; - } -} - -/* AVI header handling */ - -/* - * gst_avi_demux_parse_avih: - * @element: caller element (used for errors/debug). - * @buf: input data to be used for parsing. - * @avih: pointer to structure (filled in by function) containing - * stream information (such as flags, number of streams, etc.). - * - * Read 'avih' header. Discards buffer after use. - * - * Returns: TRUE on success, FALSE otherwise. Throws an error if - * the header is invalid. The caller should error out - * (fatal). - */ -static gboolean -gst_avi_demux_parse_avih (GstElement * element, - GstBuffer * buf, gst_riff_avih ** _avih) -{ - gst_riff_avih *avih; - - if (buf == NULL) - goto no_buffer; - - if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_avih)) - goto avih_too_small; - - avih = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); - -#if (G_BYTE_ORDER == G_BIG_ENDIAN) - avih->us_frame = GUINT32_FROM_LE (avih->us_frame); - avih->max_bps = GUINT32_FROM_LE (avih->max_bps); - avih->pad_gran = GUINT32_FROM_LE (avih->pad_gran); - avih->flags = GUINT32_FROM_LE (avih->flags); - avih->tot_frames = GUINT32_FROM_LE (avih->tot_frames); - avih->init_frames = GUINT32_FROM_LE (avih->init_frames); - avih->streams = GUINT32_FROM_LE (avih->streams); - avih->bufsize = GUINT32_FROM_LE (avih->bufsize); - avih->width = GUINT32_FROM_LE (avih->width); - avih->height = GUINT32_FROM_LE (avih->height); - avih->scale = GUINT32_FROM_LE (avih->scale); - avih->rate = GUINT32_FROM_LE (avih->rate); - avih->start = GUINT32_FROM_LE (avih->start); - avih->length = GUINT32_FROM_LE (avih->length); -#endif - - /* debug stuff */ - GST_INFO_OBJECT (element, "avih tag found:"); - GST_INFO_OBJECT (element, " us_frame %u", avih->us_frame); - GST_INFO_OBJECT (element, " max_bps %u", avih->max_bps); - GST_INFO_OBJECT (element, " pad_gran %u", avih->pad_gran); - GST_INFO_OBJECT (element, " flags 0x%08x", avih->flags); - GST_INFO_OBJECT (element, " tot_frames %u", avih->tot_frames); - GST_INFO_OBJECT (element, " init_frames %u", avih->init_frames); - GST_INFO_OBJECT (element, " streams %u", avih->streams); - GST_INFO_OBJECT (element, " bufsize %u", avih->bufsize); - GST_INFO_OBJECT (element, " width %u", avih->width); - GST_INFO_OBJECT (element, " height %u", avih->height); - GST_INFO_OBJECT (element, " scale %u", avih->scale); - GST_INFO_OBJECT (element, " rate %u", avih->rate); - GST_INFO_OBJECT (element, " start %u", avih->start); - GST_INFO_OBJECT (element, " length %u", avih->length); - - *_avih = avih; - gst_buffer_unref (buf); - - return TRUE; - - /* ERRORS */ -no_buffer: - { - GST_ELEMENT_ERROR (element, STREAM, DEMUX, (NULL), ("No buffer")); - return FALSE; - } -avih_too_small: - { - GST_ELEMENT_ERROR (element, STREAM, DEMUX, (NULL), - ("Too small avih (%d available, %d needed)", - GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_avih))); - gst_buffer_unref (buf); - return FALSE; - } -} - -/* - * gst_avi_demux_parse_superindex: - * @avi: caller element (used for debugging/errors). - * @buf: input data to use for parsing. - * @locations: locations in the file (byte-offsets) that contain - * the actual indexes (see get_avi_demux_parse_subindex()). - * The array ends with GST_BUFFER_OFFSET_NONE. - * - * Reads superindex (openDML-2 spec stuff) from the provided data. - * - * Returns: TRUE on success, FALSE otherwise. Indexes should be skipped - * on error, but they are not fatal. - */ -static gboolean -gst_avi_demux_parse_superindex (GstAviDemux * avi, - GstBuffer * buf, guint64 ** _indexes) -{ - guint8 *data; - guint16 bpe = 16; - guint32 num, i; - guint64 *indexes; - guint size; - - *_indexes = NULL; - - size = buf ? GST_BUFFER_SIZE (buf) : 0; - if (size < 24) - goto too_small; - - data = GST_BUFFER_DATA (buf); - - /* check type of index. The opendml2 specs state that - * there should be 4 dwords per array entry. Type can be - * either frame or field (and we don't care). */ - if (GST_READ_UINT16_LE (data) != 4 || - (data[2] & 0xfe) != 0x0 || data[3] != 0x0) { - GST_WARNING_OBJECT (avi, - "Superindex for stream has unexpected " - "size_entry %d (bytes) or flags 0x%02x/0x%02x", - GST_READ_UINT16_LE (data), data[2], data[3]); - bpe = GST_READ_UINT16_LE (data) * 4; - } - num = GST_READ_UINT32_LE (&data[4]); - - indexes = g_new (guint64, num + 1); - for (i = 0; i < num; i++) { - if (size < 24 + bpe * (i + 1)) - break; - indexes[i] = GST_READ_UINT64_LE (&data[24 + bpe * i]); - } - indexes[i] = GST_BUFFER_OFFSET_NONE; - *_indexes = indexes; - - gst_buffer_unref (buf); - - return TRUE; - - /* ERRORS */ -too_small: - { - GST_ERROR_OBJECT (avi, - "Not enough data to parse superindex (%d available, 24 needed)", size); - if (buf) - gst_buffer_unref (buf); - return FALSE; - } -} - -/* - * gst_avi_demux_parse_subindex: - * @avi: Avi object - * @buf: input data to use for parsing. - * @stream: stream context. - * @entries_list: a list (returned by the function) containing all the - * indexes parsed in this specific subindex. The first - * entry is also a pointer to allocated memory that needs - * to be free´ed. May be NULL if no supported indexes were - * found. - * - * Reads superindex (openDML-2 spec stuff) from the provided data. - * The buffer will be discarded after use. - * - * Returns: TRUE on success, FALSE otherwise. Errors are fatal, we - * throw an error, caller should bail out asap. - */ -static gboolean -gst_avi_demux_parse_subindex (GstAviDemux * avi, - GstBuffer * buf, avi_stream_context * stream, GList ** _entries_list) -{ - guint8 *data = GST_BUFFER_DATA (buf); - guint16 bpe; - guint32 num, i; - guint64 baseoff; - gst_avi_index_entry *entries, *entry; - GList *entries_list = NULL; - guint size; - - *_entries_list = NULL; - - size = buf ? GST_BUFFER_SIZE (buf) : 0; - - /* check size */ - if (size < 24) - goto too_small; - - /* We don't support index-data yet */ - if (data[3] & 0x80) - goto not_implemented; - - /* check type of index. The opendml2 specs state that - * there should be 4 dwords per array entry. Type can be - * either frame or field (and we don't care). */ - bpe = (data[2] & 0x01) ? 12 : 8; - if (GST_READ_UINT16_LE (data) != bpe / 4 || - (data[2] & 0xfe) != 0x0 || data[3] != 0x1) { - GST_WARNING_OBJECT (avi, - "Superindex for stream %d has unexpected " - "size_entry %d (bytes) or flags 0x%02x/0x%02x", - stream->num, GST_READ_UINT16_LE (data), data[2], data[3]); - bpe = GST_READ_UINT16_LE (data) * 4; - } - num = GST_READ_UINT32_LE (&data[4]); - baseoff = GST_READ_UINT64_LE (&data[12]); - - /* If there's nothing, just return ! */ - if (num == 0) - return TRUE; - - if (!(entries = g_try_new (gst_avi_index_entry, num))) - goto out_of_mem; - - for (i = 0; i < num; i++) { - gint64 next_ts; - - entry = &entries[i]; - - if (size < 24 + bpe * (i + 1)) - break; - - /* fill in */ - entry->offset = baseoff + GST_READ_UINT32_LE (&data[24 + bpe * i]); - entry->size = GST_READ_UINT32_LE (&data[24 + bpe * i + 4]); - entry->flags = - (entry->size & 0x80000000) ? 0 : GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME; - entry->size &= ~0x80000000; - entry->index_nr = i; - entry->stream_nr = stream->num; - - /* stream duration unknown, now we can calculate it */ - if (stream->idx_duration == -1) - stream->idx_duration = 0; - - /* timestamps */ - entry->ts = stream->idx_duration; - if (stream->is_vbr) { - /* VBR stream next timestamp */ - if (stream->strh->type == GST_RIFF_FCC_auds) { - next_ts = avi_stream_convert_frames_to_time_unchecked (stream, - stream->total_blocks + 1); - } else { - next_ts = avi_stream_convert_frames_to_time_unchecked (stream, - stream->total_frames + 1); - } - } else { - /* CBR get next timestamp */ - next_ts = avi_stream_convert_bytes_to_time_unchecked (stream, - stream->total_bytes + entry->size); - } - /* duration is next - current */ - entry->dur = next_ts - entry->ts; - - /* stream position */ - entry->bytes_before = stream->total_bytes; - entry->frames_before = stream->total_frames; - - stream->total_bytes += entry->size; - stream->total_frames++; - if (stream->strh->type == GST_RIFF_FCC_auds) { - if (stream->strf.auds->blockalign > 0) - stream->total_blocks += - (entry->size + stream->strf.auds->blockalign - - 1) / stream->strf.auds->blockalign; - else - stream->total_blocks++; - } - stream->idx_duration = next_ts; - - entries_list = g_list_prepend (entries_list, entry); - } - - GST_LOG_OBJECT (avi, "Read %d index entries", i); - - gst_buffer_unref (buf); - - if (i > 0) { - *_entries_list = g_list_reverse (entries_list); - } else { - g_free (entries); - } - - return TRUE; - - /* ERRORS */ -too_small: - { - GST_ERROR_OBJECT (avi, - "Not enough data to parse subindex (%d available, 24 needed)", size); - if (buf) - gst_buffer_unref (buf); - return TRUE; /* continue */ - } -not_implemented: - { - GST_ELEMENT_ERROR (avi, STREAM, NOT_IMPLEMENTED, (NULL), - ("Subindex-is-data is not implemented")); - gst_buffer_unref (buf); - return FALSE; - } -out_of_mem: - { - GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL), - ("Cannot allocate memory for %u*%u=%u bytes", - (guint) sizeof (gst_avi_index_entry), num, - (guint) sizeof (gst_avi_index_entry) * num)); - gst_buffer_unref (buf); - return FALSE; - } -} - -#if 0 -/* - * Read AVI index when streaming - */ -static void -gst_avi_demux_read_subindexes_push (GstAviDemux * avi, - GList ** index, GList ** alloc_list) -{ - GList *list = NULL; - guint32 tag = 0, size; - GstBuffer *buf = NULL; - gint i, n; - - GST_DEBUG_OBJECT (avi, "gst_avi_demux_read_subindexes_push for %d streams", - avi->num_streams); - - for (n = 0; n < avi->num_streams; n++) { - avi_stream_context *stream = &avi->stream[n]; - - for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) { - if (!gst_avi_demux_peek_chunk (avi, &tag, &size)) - continue; - else if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10, - '0' + stream->num % 10)) && - (tag != GST_MAKE_FOURCC ('0' + stream->num / 10, - '0' + stream->num % 10, 'i', 'x'))) { - GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")", - GST_FOURCC_ARGS (tag)); - continue; - } - - avi->offset += 8 + ((size + 1) & ~1); - - buf = gst_buffer_new (); - GST_BUFFER_DATA (buf) = gst_adapter_take (avi->adapter, size); - GST_BUFFER_SIZE (buf) = size; - - if (!gst_avi_demux_parse_subindex (avi, buf, stream, &list)) - continue; - if (list) { - GST_DEBUG_OBJECT (avi, " adding %d entries", g_list_length (list)); - *alloc_list = g_list_append (*alloc_list, list->data); - *index = g_list_concat (*index, list); - } - } - - g_free (stream->indexes); - stream->indexes = NULL; - } - GST_DEBUG_OBJECT (avi, "index %s", ((*index) ? "!= 0" : "== 0")); -} -#endif - -/* - * Read AVI index - */ -static void -gst_avi_demux_read_subindexes_pull (GstAviDemux * avi, - GList ** index, GList ** alloc_list) -{ - GList *list = NULL; - guint32 tag; - GstBuffer *buf; - gint i, n; - - GST_DEBUG_OBJECT (avi, "gst_avi_demux_read_subindexes_pull for %d streams", - avi->num_streams); - - for (n = 0; n < avi->num_streams; n++) { - avi_stream_context *stream = &avi->stream[n]; - - for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) { - if (gst_riff_read_chunk (GST_ELEMENT (avi), avi->sinkpad, - &stream->indexes[i], &tag, &buf) != GST_FLOW_OK) - continue; - else if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10, - '0' + stream->num % 10)) && - (tag != GST_MAKE_FOURCC ('0' + stream->num / 10, - '0' + stream->num % 10, 'i', 'x'))) { - /* Some ODML files (created by god knows what muxer) have a ##ix format - * instead of the 'official' ix##. They are still valid though. */ - GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")", - GST_FOURCC_ARGS (tag)); - gst_buffer_unref (buf); - continue; - } - - if (!gst_avi_demux_parse_subindex (avi, buf, stream, &list)) - continue; - if (list) { - GST_DEBUG_OBJECT (avi, " adding %5d entries, total %2d %5d", - g_list_length (list), g_list_length (*alloc_list), - g_list_length (*index)); - *alloc_list = g_list_append (*alloc_list, list->data); - *index = g_list_concat (*index, list); - } - } - - g_free (stream->indexes); - stream->indexes = NULL; - } - GST_DEBUG_OBJECT (avi, "index %s", ((*index) ? "!= 0" : "== 0")); -} - -/* - * gst_avi_demux_riff_parse_vprp: - * @element: caller element (used for debugging/error). - * @buf: input data to be used for parsing, stripped from header. - * @vprp: a pointer (returned by this function) to a filled-in vprp - * structure. Caller should free it. - * - * Parses a video stream´s vprp. This function takes ownership of @buf. - * - * Returns: TRUE if parsing succeeded, otherwise FALSE. The stream - * should be skipped on error, but it is not fatal. - */ -static gboolean -gst_avi_demux_riff_parse_vprp (GstElement * element, - GstBuffer * buf, gst_riff_vprp ** _vprp) -{ - gst_riff_vprp *vprp; - gint k; - - g_return_val_if_fail (buf != NULL, FALSE); - g_return_val_if_fail (_vprp != NULL, FALSE); - - if (GST_BUFFER_SIZE (buf) < G_STRUCT_OFFSET (gst_riff_vprp, field_info)) - goto too_small; - - vprp = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); - -#if (G_BYTE_ORDER == G_BIG_ENDIAN) - vprp->format_token = GUINT32_FROM_LE (vprp->format_token); - vprp->standard = GUINT32_FROM_LE (vprp->standard); - vprp->vert_rate = GUINT32_FROM_LE (vprp->vert_rate); - vprp->hor_t_total = GUINT32_FROM_LE (vprp->hor_t_total); - vprp->vert_lines = GUINT32_FROM_LE (vprp->vert_lines); - vprp->aspect = GUINT32_FROM_LE (vprp->aspect); - vprp->width = GUINT32_FROM_LE (vprp->width); - vprp->height = GUINT32_FROM_LE (vprp->height); - vprp->fields = GUINT32_FROM_LE (vprp->fields); -#endif - - /* size checking */ - /* calculate fields based on size */ - k = (GST_BUFFER_SIZE (buf) - G_STRUCT_OFFSET (gst_riff_vprp, field_info)) / - vprp->fields; - if (vprp->fields > k) { - GST_WARNING_OBJECT (element, - "vprp header indicated %d fields, only %d available", vprp->fields, k); - vprp->fields = k; - } - if (vprp->fields > GST_RIFF_VPRP_VIDEO_FIELDS) { - GST_WARNING_OBJECT (element, - "vprp header indicated %d fields, at most %d supported", vprp->fields, - GST_RIFF_VPRP_VIDEO_FIELDS); - vprp->fields = GST_RIFF_VPRP_VIDEO_FIELDS; - } -#if (G_BYTE_ORDER == G_BIG_ENDIAN) - for (k = 0; k < vprp->fields; k++) { - gst_riff_vprp_video_field_desc *fd; - - fd = &vprp->field_info[k]; - fd->compressed_bm_height = GUINT32_FROM_LE (fd->compressed_bm_height); - fd->compressed_bm_width = GUINT32_FROM_LE (fd->compressed_bm_width); - fd->valid_bm_height = GUINT32_FROM_LE (fd->valid_bm_height); - fd->valid_bm_width = GUINT16_FROM_LE (fd->valid_bm_width); - fd->valid_bm_x_offset = GUINT16_FROM_LE (fd->valid_bm_x_offset); - fd->valid_bm_y_offset = GUINT32_FROM_LE (fd->valid_bm_y_offset); - fd->video_x_t_offset = GUINT32_FROM_LE (fd->video_x_t_offset); - fd->video_y_start = GUINT32_FROM_LE (fd->video_y_start); - } -#endif - - /* debug */ - GST_INFO_OBJECT (element, "vprp tag found in context vids:"); - GST_INFO_OBJECT (element, " format_token %d", vprp->format_token); - GST_INFO_OBJECT (element, " standard %d", vprp->standard); - GST_INFO_OBJECT (element, " vert_rate %d", vprp->vert_rate); - GST_INFO_OBJECT (element, " hor_t_total %d", vprp->hor_t_total); - GST_INFO_OBJECT (element, " vert_lines %d", vprp->vert_lines); - GST_INFO_OBJECT (element, " aspect %d:%d", vprp->aspect >> 16, - vprp->aspect & 0xffff); - GST_INFO_OBJECT (element, " width %d", vprp->width); - GST_INFO_OBJECT (element, " height %d", vprp->height); - GST_INFO_OBJECT (element, " fields %d", vprp->fields); - for (k = 0; k < vprp->fields; k++) { - gst_riff_vprp_video_field_desc *fd; - - fd = &(vprp->field_info[k]); - GST_INFO_OBJECT (element, " field %u description:", k); - GST_INFO_OBJECT (element, " compressed_bm_height %d", - fd->compressed_bm_height); - GST_INFO_OBJECT (element, " compressed_bm_width %d", - fd->compressed_bm_width); - GST_INFO_OBJECT (element, " valid_bm_height %d", - fd->valid_bm_height); - GST_INFO_OBJECT (element, " valid_bm_width %d", fd->valid_bm_width); - GST_INFO_OBJECT (element, " valid_bm_x_offset %d", - fd->valid_bm_x_offset); - GST_INFO_OBJECT (element, " valid_bm_y_offset %d", - fd->valid_bm_y_offset); - GST_INFO_OBJECT (element, " video_x_t_offset %d", - fd->video_x_t_offset); - GST_INFO_OBJECT (element, " video_y_start %d", fd->video_y_start); - } - - gst_buffer_unref (buf); - - *_vprp = vprp; - - return TRUE; - - /* ERRORS */ -too_small: - { - GST_ERROR_OBJECT (element, - "Too small vprp (%d available, at least %d needed)", - GST_BUFFER_SIZE (buf), - (int) G_STRUCT_OFFSET (gst_riff_vprp, field_info)); - gst_buffer_unref (buf); - return FALSE; - } -} - -/* - * gst_avi_demux_parse_stream: - * @avi: calling element (used for debugging/errors). - * @buf: input buffer used to parse the stream. - * - * Parses all subchunks in a strl chunk (which defines a single - * stream). Discards the buffer after use. This function will - * increment the stream counter internally. - * - * Returns: whether the stream was identified successfully. - * Errors are not fatal. It does indicate the stream - * was skipped. - */ -static gboolean -gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf) -{ - avi_stream_context *stream; - GstElementClass *klass; - GstPadTemplate *templ; - GstBuffer *sub = NULL; - guint offset = 4; - guint32 tag = 0; - gchar *codec_name = NULL, *padname = NULL; - const gchar *tag_name; - GstCaps *caps = NULL; - GstPad *pad; - GstElement *element; - gboolean got_strh = FALSE, got_strf = FALSE, got_vprp = FALSE; - gst_riff_vprp *vprp = NULL; - - element = GST_ELEMENT_CAST (avi); - - GST_DEBUG_OBJECT (avi, "Parsing stream"); - - if (avi->num_streams >= GST_AVI_DEMUX_MAX_STREAMS) { - GST_WARNING_OBJECT (avi, - "maximum no of streams (%d) exceeded, ignoring stream", - GST_AVI_DEMUX_MAX_STREAMS); - gst_buffer_unref (buf); - /* not a fatal error, let's say */ - return TRUE; - } - - stream = &avi->stream[avi->num_streams]; - - /* initial settings */ - stream->idx_duration = GST_CLOCK_TIME_NONE; - stream->hdr_duration = GST_CLOCK_TIME_NONE; - stream->duration = GST_CLOCK_TIME_NONE; - - while (gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) { - /* sub can be NULL if the chunk is empty */ - if (sub == NULL) { - GST_DEBUG_OBJECT (avi, "ignoring empty chunk %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (tag)); - continue; - } - switch (tag) { - case GST_RIFF_TAG_strh: - { - gst_riff_strh *strh; - - if (got_strh) { - GST_WARNING_OBJECT (avi, "Ignoring additional strh chunk"); - break; - } - if (!gst_riff_parse_strh (element, sub, &stream->strh)) { - /* ownership given away */ - sub = NULL; - GST_WARNING_OBJECT (avi, "Failed to parse strh chunk"); - goto fail; - } - sub = NULL; - strh = stream->strh; - /* sanity check; stream header frame rate matches global header - * frame duration */ - if (stream->strh->type == GST_RIFF_FCC_vids) { - GstClockTime s_dur; - GstClockTime h_dur = avi->avih->us_frame * GST_USECOND; - - s_dur = gst_util_uint64_scale (GST_SECOND, strh->scale, strh->rate); - GST_DEBUG_OBJECT (avi, "verifying stream framerate %d/%d, " - "frame duration = %d ms", strh->rate, strh->scale, - s_dur / GST_MSECOND); - if (h_dur > (10 * GST_MSECOND) && (s_dur > 10 * h_dur)) { - strh->rate = GST_SECOND / GST_USECOND; - strh->scale = h_dur / GST_USECOND; - GST_DEBUG_OBJECT (avi, "correcting stream framerate to %d/%d", - strh->rate, strh->scale); - } - } - /* determine duration as indicated by header */ - stream->hdr_duration = gst_util_uint64_scale ((guint64) strh->length * - strh->scale, GST_SECOND, (guint64) strh->rate); - GST_INFO ("Stream duration according to header: %" GST_TIME_FORMAT, - GST_TIME_ARGS (stream->hdr_duration)); - if (stream->hdr_duration == 0) - stream->hdr_duration = GST_CLOCK_TIME_NONE; - - got_strh = TRUE; - break; - } - case GST_RIFF_TAG_strf: - { - gboolean res = FALSE; - - if (got_strf) { - GST_WARNING_OBJECT (avi, "Ignoring additional strf chunk"); - break; - } - if (!got_strh) { - GST_ERROR_OBJECT (avi, "Found strf chunk before strh chunk"); - goto fail; - } - switch (stream->strh->type) { - case GST_RIFF_FCC_vids: - stream->is_vbr = TRUE; - res = gst_riff_parse_strf_vids (element, sub, - &stream->strf.vids, &stream->extradata); - sub = NULL; - GST_DEBUG_OBJECT (element, "marking video as VBR, res %d", res); - break; - case GST_RIFF_FCC_auds: - stream->is_vbr = (stream->strh->samplesize == 0) - && stream->strh->scale > 1; - res = - gst_riff_parse_strf_auds (element, sub, &stream->strf.auds, - &stream->extradata); - sub = NULL; - GST_DEBUG_OBJECT (element, "marking audio as VBR:%d, res %d", - stream->is_vbr, res); - break; - case GST_RIFF_FCC_iavs: - stream->is_vbr = TRUE; - res = gst_riff_parse_strf_iavs (element, sub, - &stream->strf.iavs, &stream->extradata); - sub = NULL; - GST_DEBUG_OBJECT (element, "marking iavs as VBR, res %d", res); - break; - case GST_RIFF_FCC_txts: - /* nothing to parse here */ - stream->is_vbr = (stream->strh->samplesize == 0) - && (stream->strh->scale > 1); - res = TRUE; - break; - default: - GST_ERROR_OBJECT (avi, - "Don´t know how to handle stream type %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (stream->strh->type)); - break; - } - if (sub) { - gst_buffer_unref (sub); - sub = NULL; - } - if (!res) - goto fail; - got_strf = TRUE; - break; - } - case GST_RIFF_TAG_vprp: - { - if (got_vprp) { - GST_WARNING_OBJECT (avi, "Ignoring additional vprp chunk"); - break; - } - if (!got_strh) { - GST_ERROR_OBJECT (avi, "Found vprp chunk before strh chunk"); - goto fail; - } - if (!got_strf) { - GST_ERROR_OBJECT (avi, "Found vprp chunk before strf chunk"); - goto fail; - } - - if (!gst_avi_demux_riff_parse_vprp (element, sub, &vprp)) { - GST_WARNING_OBJECT (avi, "Failed to parse vprp chunk"); - /* not considered fatal */ - g_free (vprp); - vprp = NULL; - } else - got_vprp = TRUE; - sub = NULL; - break; - } - case GST_RIFF_TAG_strd: - if (stream->initdata) - gst_buffer_unref (stream->initdata); - stream->initdata = sub; - sub = NULL; - break; - case GST_RIFF_TAG_strn: - g_free (stream->name); - if (sub != NULL) { - stream->name = - g_strndup ((gchar *) GST_BUFFER_DATA (sub), - (gsize) GST_BUFFER_SIZE (sub)); - gst_buffer_unref (sub); - sub = NULL; - } else { - stream->name = g_strdup (""); - } - GST_DEBUG_OBJECT (avi, "stream name: %s", stream->name); - break; - default: - if (tag == GST_MAKE_FOURCC ('i', 'n', 'd', 'x') || - tag == GST_MAKE_FOURCC ('i', 'x', '0' + avi->num_streams / 10, - '0' + avi->num_streams % 10)) { - g_free (stream->indexes); - gst_avi_demux_parse_superindex (avi, sub, &stream->indexes); - stream->superindex = TRUE; - sub = NULL; - break; - } - GST_WARNING_OBJECT (avi, - "Unknown stream header tag %" GST_FOURCC_FORMAT ", ignoring", - GST_FOURCC_ARGS (tag)); - /* fall-through */ - case GST_RIFF_TAG_JUNK: - break; - } - if (sub != NULL) { - gst_buffer_unref (sub); - sub = NULL; - } - } - - if (!got_strh) { - GST_WARNING_OBJECT (avi, "Failed to find strh chunk"); - goto fail; - } - - if (!got_strf) { - GST_WARNING_OBJECT (avi, "Failed to find strf chunk"); - goto fail; - } - - /* get class to figure out the template */ - klass = GST_ELEMENT_GET_CLASS (avi); - - /* we now have all info, let´s set up a pad and a caps and be done */ - /* create stream name + pad */ - switch (stream->strh->type) { - case GST_RIFF_FCC_vids:{ - guint32 fourcc; - - fourcc = (stream->strf.vids->compression) ? - stream->strf.vids->compression : stream->strh->fcc_handler; - padname = g_strdup_printf ("video_%02d", avi->num_v_streams); - templ = gst_element_class_get_pad_template (klass, "video_%02d"); - caps = gst_riff_create_video_caps (fourcc, stream->strh, - stream->strf.vids, stream->extradata, stream->initdata, &codec_name); - if (!caps) { - caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc", - GST_TYPE_FOURCC, fourcc, NULL); - } else if (got_vprp && vprp) { - guint32 aspect_n, aspect_d; - gint n, d; - - aspect_n = vprp->aspect >> 16; - aspect_d = vprp->aspect & 0xffff; - /* calculate the pixel aspect ratio using w/h and aspect ratio */ - n = aspect_n * stream->strf.vids->height; - d = aspect_d * stream->strf.vids->width; - if (n && d) - gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION, - n, d, NULL); - /* very local, not needed elsewhere */ - g_free (vprp); - vprp = NULL; - } - tag_name = GST_TAG_VIDEO_CODEC; - avi->num_v_streams++; - break; - } - case GST_RIFF_FCC_auds:{ - padname = g_strdup_printf ("audio_%02d", avi->num_a_streams); - templ = gst_element_class_get_pad_template (klass, "audio_%02d"); - caps = gst_riff_create_audio_caps (stream->strf.auds->format, - stream->strh, stream->strf.auds, stream->extradata, - stream->initdata, &codec_name); - if (!caps) { - caps = gst_caps_new_simple ("audio/x-avi-unknown", "codec_id", - G_TYPE_INT, stream->strf.auds->format, NULL); - } - tag_name = GST_TAG_AUDIO_CODEC; - avi->num_a_streams++; - break; - } - case GST_RIFF_FCC_iavs:{ - guint32 fourcc = stream->strh->fcc_handler; - - padname = g_strdup_printf ("video_%02d", avi->num_v_streams); - templ = gst_element_class_get_pad_template (klass, "video_%02d"); - caps = gst_riff_create_iavs_caps (fourcc, stream->strh, - stream->strf.iavs, stream->extradata, stream->initdata, &codec_name); - if (!caps) { - caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc", - GST_TYPE_FOURCC, fourcc, NULL); - } - tag_name = GST_TAG_VIDEO_CODEC; - avi->num_v_streams++; - break; - } - case GST_RIFF_FCC_txts:{ - padname = g_strdup_printf ("subtitle_%02d", avi->num_t_streams); - templ = gst_element_class_get_pad_template (klass, "subtitle_%02d"); - caps = gst_caps_new_simple ("application/x-subtitle-avi", NULL); - tag_name = NULL; - avi->num_t_streams++; - break; - } - default: - g_assert_not_reached (); - } - - /* no caps means no stream */ - if (!caps) { - GST_ERROR_OBJECT (element, "Did not find caps for stream %s", padname); - goto fail; - } - - GST_DEBUG_OBJECT (element, "codec-name=%s", - (codec_name ? codec_name : "NULL")); - GST_DEBUG_OBJECT (element, "caps=%" GST_PTR_FORMAT, caps); - - /* set proper settings and add it */ - if (stream->pad) - gst_object_unref (stream->pad); - pad = stream->pad = gst_pad_new_from_template (templ, padname); - stream->last_flow = GST_FLOW_OK; - stream->discont = TRUE; - g_free (padname); - - gst_pad_use_fixed_caps (pad); -#if 0 - gst_pad_set_formats_function (pad, - GST_DEBUG_FUNCPTR (gst_avi_demux_get_src_formats)); - gst_pad_set_event_mask_function (pad, - GST_DEBUG_FUNCPTR (gst_avi_demux_get_event_mask)); -#endif - gst_pad_set_event_function (pad, - GST_DEBUG_FUNCPTR (gst_avi_demux_handle_src_event)); - gst_pad_set_query_type_function (pad, - GST_DEBUG_FUNCPTR (gst_avi_demux_get_src_query_types)); - gst_pad_set_query_function (pad, - GST_DEBUG_FUNCPTR (gst_avi_demux_handle_src_query)); -#if 0 - gst_pad_set_convert_function (pad, - GST_DEBUG_FUNCPTR (gst_avi_demux_src_convert)); -#endif - - stream->num = avi->num_streams; - stream->total_bytes = 0; - stream->total_frames = 0; - stream->total_blocks = 0; - stream->current_frame = 0; - stream->current_byte = 0; - gst_pad_set_element_private (pad, stream); - avi->num_streams++; - gst_pad_set_caps (pad, caps); - gst_pad_set_active (pad, TRUE); - gst_element_add_pad (GST_ELEMENT (avi), pad); - GST_LOG_OBJECT (element, "Added pad %s with caps %" GST_PTR_FORMAT, - GST_PAD_NAME (pad), caps); - gst_caps_unref (caps); - - /* make tags */ - if (codec_name) { - if (!stream->taglist) - stream->taglist = gst_tag_list_new (); - - avi->got_tags = TRUE; - - gst_tag_list_add (stream->taglist, GST_TAG_MERGE_APPEND, tag_name, - codec_name, NULL); - g_free (codec_name); - } - - gst_buffer_unref (buf); - - return TRUE; - - /* ERRORS */ -fail: - { - /* unref any mem that may be in use */ - if (buf) - gst_buffer_unref (buf); - if (sub) - gst_buffer_unref (sub); - g_free (vprp); - g_free (codec_name); - g_free (stream->strh); - g_free (stream->strf.data); - g_free (stream->name); - g_free (stream->indexes); - if (stream->initdata) - gst_buffer_unref (stream->initdata); - if (stream->extradata) - gst_buffer_unref (stream->extradata); - memset (stream, 0, sizeof (avi_stream_context)); - avi->num_streams++; - return FALSE; - } -} - -/* - * gst_avi_demux_parse_odml: - * @avi: calling element (used for debug/error). - * @buf: input buffer to be used for parsing. - * - * Read an openDML-2.0 extension header. Fills in the frame number - * in the avi demuxer object when reading succeeds. - */ -static void -gst_avi_demux_parse_odml (GstAviDemux * avi, GstBuffer * buf) -{ - guint32 tag = 0; - guint offset = 4; - GstBuffer *sub = NULL; - - while (gst_riff_parse_chunk (GST_ELEMENT_CAST (avi), buf, &offset, &tag, - &sub)) { - switch (tag) { - case GST_RIFF_TAG_dmlh:{ - gst_riff_dmlh dmlh, *_dmlh; - guint size; - - /* sub == NULL is possible and means an empty buffer */ - size = sub ? GST_BUFFER_SIZE (sub) : 0; - - /* check size */ - if (size < sizeof (gst_riff_dmlh)) { - GST_ERROR_OBJECT (avi, - "DMLH entry is too small (%d bytes, %d needed)", - size, (int) sizeof (gst_riff_dmlh)); - goto next; - } - _dmlh = (gst_riff_dmlh *) GST_BUFFER_DATA (sub); - dmlh.totalframes = GST_READ_UINT32_LE (&_dmlh->totalframes); - - GST_INFO_OBJECT (avi, "dmlh tag found:"); - GST_INFO_OBJECT (avi, " totalframes: %u", dmlh.totalframes); - - avi->avih->tot_frames = dmlh.totalframes; - goto next; - } - - default: - GST_WARNING_OBJECT (avi, - "Unknown tag %" GST_FOURCC_FORMAT " in ODML header", - GST_FOURCC_ARGS (tag)); - /* fall-through */ - case GST_RIFF_TAG_JUNK: - next: - /* skip and move to next chunk */ - if (sub) { - gst_buffer_unref (sub); - sub = NULL; - } - break; - } - } - if (buf) - gst_buffer_unref (buf); -} - -/* - * Sort helper for index entries that sorts by index time. - * If times are equal we sort by stream number. - */ -static gint -sort (gst_avi_index_entry * a, gst_avi_index_entry * b) -{ - if (a->ts > b->ts) - return 1; - else if (a->ts < b->ts) - return -1; - else - return a->stream_nr - b->stream_nr; -} - -/* - * gst_avi_demux_parse_index: - * @avi: calling element (used for debugging/errors). - * @buf: buffer containing the full index. - * @entries_list: list (returned by this function) containing the index - * entries parsed from the buffer. The first in the list - * is also a pointer to the allocated data and should be - * free'ed at some point. - * - * Read index entries from the provided buffer. Takes ownership of @buf. - */ -static void -gst_avi_demux_parse_index (GstAviDemux * avi, - GstBuffer * buf, GList ** _entries_list) -{ - guint64 pos_before = avi->offset; - gst_avi_index_entry *entries = NULL; - guint8 *data; - GList *entries_list = NULL; - guint i, num, n; - -#ifndef GST_DISABLE_GST_DEBUG - gulong _nr_keyframes = 0; -#endif - - if (!buf || !GST_BUFFER_SIZE (buf)) { - *_entries_list = NULL; - GST_DEBUG ("empty index"); - if (buf) - gst_buffer_unref (buf); - return; - } - - data = GST_BUFFER_DATA (buf); - num = GST_BUFFER_SIZE (buf) / sizeof (gst_riff_index_entry); - if (!(entries = g_try_new (gst_avi_index_entry, num))) - goto out_of_mem; - - GST_INFO ("Parsing index, nr_entries = %6d", num); - - for (i = 0, n = 0; i < num; i++) { - gint64 next_ts; - gst_riff_index_entry entry, *_entry; - avi_stream_context *stream; - guint stream_nr; - gst_avi_index_entry *target; - - _entry = &((gst_riff_index_entry *) data)[i]; - entry.id = GST_READ_UINT32_LE (&_entry->id); - entry.offset = GST_READ_UINT32_LE (&_entry->offset); - entry.flags = GST_READ_UINT32_LE (&_entry->flags); - entry.size = GST_READ_UINT32_LE (&_entry->size); - target = &entries[n]; - - if (entry.id == GST_RIFF_rec || entry.id == 0 || - (entry.offset == 0 && n > 0)) - continue; - - stream_nr = CHUNKID_TO_STREAMNR (entry.id); - if (stream_nr >= avi->num_streams) { - GST_WARNING_OBJECT (avi, - "Index entry %d has invalid stream nr %d", i, stream_nr); - continue; - } - target->stream_nr = stream_nr; - stream = &avi->stream[stream_nr]; - - if (!stream->strh) { - GST_WARNING_OBJECT (avi, "Unhandled stream %d, skipping", stream_nr); - continue; - } - - target->index_nr = i; - target->flags = - (entry.flags & GST_RIFF_IF_KEYFRAME) ? GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME - : 0; - target->size = entry.size; - target->offset = entry.offset + 8; - - /* figure out if the index is 0 based or relative to the MOVI start */ - if (n == 0) { - if (target->offset < pos_before) - avi->index_offset = pos_before + 8; - else - avi->index_offset = 0; - GST_DEBUG ("index_offset = %" G_GUINT64_FORMAT, avi->index_offset); - } - - if (stream->strh->type == GST_RIFF_FCC_auds) { - /* all audio frames are keyframes */ - target->flags |= GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME; - } -#ifndef GST_DISABLE_GST_DEBUG - if (target->flags & GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME) - _nr_keyframes++; -#endif - - /* stream duration unknown, now we can calculate it */ - if (stream->idx_duration == -1) - stream->idx_duration = 0; - - /* timestamps */ - target->ts = stream->idx_duration; - if (stream->is_vbr) { - /* VBR stream next timestamp */ - if (stream->strh->type == GST_RIFF_FCC_auds) { - next_ts = avi_stream_convert_frames_to_time_unchecked (stream, - stream->total_blocks + 1); - } else { - next_ts = avi_stream_convert_frames_to_time_unchecked (stream, - stream->total_frames + 1); - } - } else { - /* constant rate stream */ - next_ts = avi_stream_convert_bytes_to_time_unchecked (stream, - stream->total_bytes + target->size); - } - /* duration is next - current */ - target->dur = next_ts - target->ts; - - /* stream position */ - target->bytes_before = stream->total_bytes; - target->frames_before = stream->total_frames; - - stream->total_bytes += target->size; - stream->total_frames++; - if (stream->strh->type == GST_RIFF_FCC_auds) { - if (stream->strf.auds->blockalign > 0) - stream->total_blocks += - (target->size + stream->strf.auds->blockalign - - 1) / stream->strf.auds->blockalign; - else - stream->total_blocks++; - } - stream->idx_duration = next_ts; - - GST_LOG_OBJECT (avi, - "Adding index entry %d (%6u), flags %02x, stream %d, size %u " - ", offset %" G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT ", dur %" - GST_TIME_FORMAT, - target->index_nr, stream->total_frames - 1, target->flags, - target->stream_nr, target->size, target->offset, - GST_TIME_ARGS (target->ts), GST_TIME_ARGS (target->dur)); - entries_list = g_list_prepend (entries_list, target); - - n++; - } - - GST_INFO ("Parsed index, %6d entries, %5ld keyframes, entry size = %2d, " - "total size = %10d", num, _nr_keyframes, - (gint) sizeof (gst_avi_index_entry), - (gint) (num * sizeof (gst_avi_index_entry))); - - gst_buffer_unref (buf); - - if (n > 0) { - *_entries_list = g_list_reverse (entries_list); - } else { - g_free (entries); - } - return; - - /* ERRORS */ -out_of_mem: - { - GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL), - ("Cannot allocate memory for %u*%u=%u bytes", - (guint) sizeof (gst_avi_index_entry), num, - (guint) sizeof (gst_avi_index_entry) * num)); - gst_buffer_unref (buf); - } -} - -/* - * gst_avi_demux_stream_index: - * @avi: avi demuxer object. - * @index: list of index entries, returned by this function. - * @alloc_list: list of allocated data, returned by this function. - * - * Seeks to index and reads it. - */ -static void -gst_avi_demux_stream_index (GstAviDemux * avi, - GList ** index, GList ** alloc_list) -{ - GstFlowReturn res; - guint64 offset = avi->offset; - GstBuffer *buf; - guint32 tag; - guint32 size; - gint i; - - GST_DEBUG ("demux stream index at offset %" G_GUINT64_FORMAT, offset); - - *alloc_list = NULL; - *index = NULL; - - /* get chunk information */ - res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf); - if (res != GST_FLOW_OK) - goto pull_failed; - else if (GST_BUFFER_SIZE (buf) < 8) - goto too_small; - - /* check tag first before blindy trying to read 'size' bytes */ - tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); - size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4); - if (tag == GST_RIFF_TAG_LIST) { - /* this is the movi tag */ - GST_DEBUG_OBJECT (avi, "skip LIST chunk, size %" G_GUINT32_FORMAT, - (8 + ((size + 1) & ~1))); - offset += 8 + ((size + 1) & ~1); - gst_buffer_unref (buf); - res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf); - if (res != GST_FLOW_OK) - goto pull_failed; - else if (GST_BUFFER_SIZE (buf) < 8) - goto too_small; - tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); - size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4); - } - - if (tag != GST_RIFF_TAG_idx1) - goto no_index; - if (!size) - goto zero_index; - - gst_buffer_unref (buf); - - GST_DEBUG ("index found at offset %" G_GUINT64_FORMAT, offset); - - /* read chunk, advance offset */ - if (gst_riff_read_chunk (GST_ELEMENT_CAST (avi), - avi->sinkpad, &offset, &tag, &buf) != GST_FLOW_OK) - return; - - GST_INFO ("will parse index chunk size %u for tag %" - GST_FOURCC_FORMAT, GST_BUFFER_SIZE (buf), GST_FOURCC_ARGS (tag)); - - gst_avi_demux_parse_index (avi, buf, index); - if (*index) - *alloc_list = g_list_append (*alloc_list, (*index)->data); - - /* debug our indexes */ - for (i = 0; i < avi->num_streams; i++) { - avi_stream_context *stream; - - stream = &avi->stream[i]; - GST_DEBUG_OBJECT (avi, "stream %u: %u frames, %" G_GINT64_FORMAT " bytes", - i, stream->total_frames, stream->total_bytes); - } - return; - - /* ERRORS */ -pull_failed: - { - GST_DEBUG_OBJECT (avi, - "pull range failed: pos=%" G_GUINT64_FORMAT " size=8", offset); - return; - } -too_small: - { - GST_DEBUG_OBJECT (avi, "Buffer is too small"); - gst_buffer_unref (buf); - return; - } -no_index: - { - GST_WARNING_OBJECT (avi, - "No index data (idx1) after movi chunk, but %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (tag)); - gst_buffer_unref (buf); - return; - } -zero_index: - { - GST_WARNING_OBJECT (avi, "Empty index data (idx1) after movi chunk"); - gst_buffer_unref (buf); - return; - } -} - -#if 0 -/* - * Sync to next data chunk. - */ -static gboolean -gst_avi_demux_skip (GstAviDemux * avi, gboolean prevent_eos) -{ - GstRiffRead *riff = GST_RIFF_READ (avi); - - if (prevent_eos) { - guint64 pos, length; - guint size; - guint8 *data; - - pos = gst_bytestream_tell (riff->bs); - length = gst_bytestream_length (riff->bs); - - if (pos + 8 > length) - return FALSE; - - if (gst_bytestream_peek_bytes (riff->bs, &data, 8) != 8) - return FALSE; - - size = GST_READ_UINT32_LE (&data[4]); - if (size & 1) - size++; - - /* Note, we're going to skip which might involve seeks. Therefore, - * we need 1 byte more! */ - if (pos + 8 + size >= length) - return FALSE; - } - - return gst_riff_read_skip (riff); -} - -static gboolean -gst_avi_demux_sync (GstAviDemux * avi, guint32 * ret_tag, gboolean prevent_eos) -{ - GstRiffRead *riff = GST_RIFF_READ (avi); - guint32 tag; - guint64 length = gst_bytestream_length (riff->bs); - - if (prevent_eos && gst_bytestream_tell (riff->bs) + 12 >= length) - return FALSE; - - /* peek first (for the end of this 'list/movi' section) */ - if (!(tag = gst_riff_peek_tag (riff, &avi->level_up))) - return FALSE; - - /* if we're at top-level, we didn't read the 'movi' - * list tag yet. This can also be 'AVIX' in case of - * openDML-2.0 AVI files. Lastly, it might be idx1, - * in which case we skip it so we come at EOS. */ - while (1) { - if (prevent_eos && gst_bytestream_tell (riff->bs) + 12 >= length) - return FALSE; - - if (!(tag = gst_riff_peek_tag (riff, NULL))) - return FALSE; - - switch (tag) { - case GST_RIFF_TAG_LIST: - if (!(tag = gst_riff_peek_list (riff))) - return FALSE; - - switch (tag) { - case GST_RIFF_LIST_AVIX: - if (!gst_riff_read_list (riff, &tag)) - return FALSE; - break; - - case GST_RIFF_LIST_movi: - if (!gst_riff_read_list (riff, &tag)) - return FALSE; - /* fall-through */ - - case GST_RIFF_rec: - goto done; - - default: - GST_WARNING ("Unknown list %" GST_FOURCC_FORMAT " before AVI data", - GST_FOURCC_ARGS (tag)); - /* fall-through */ - - case GST_RIFF_TAG_JUNK: - if (!gst_avi_demux_skip (avi, prevent_eos)) - return FALSE; - break; - } - break; - - default: - if ((tag & 0xff) >= '0' && (tag & 0xff) <= '9' && - ((tag >> 8) & 0xff) >= '0' && ((tag >> 8) & 0xff) <= '9') { - goto done; - } - /* pass-through */ - - case GST_RIFF_TAG_idx1: - case GST_RIFF_TAG_JUNK: - if (!gst_avi_demux_skip (avi, prevent_eos)) { - return FALSE; - } - break; - } - } -done: - /* And then, we get the data */ - if (prevent_eos && gst_bytestream_tell (riff->bs) + 12 >= length) - return FALSE; - - if (!(tag = gst_riff_peek_tag (riff, NULL))) - return FALSE; - - /* Support for rec-list files */ - switch (tag) { - case GST_RIFF_TAG_LIST: - if (!(tag = gst_riff_peek_list (riff))) - return FALSE; - if (tag == GST_RIFF_rec) { - /* Simply skip the list */ - if (!gst_riff_read_list (riff, &tag)) - return FALSE; - if (!(tag = gst_riff_peek_tag (riff, NULL))) - return FALSE; - } - break; - - case GST_RIFF_TAG_JUNK: - gst_avi_demux_skip (avi, prevent_eos); - return FALSE; - } - - if (ret_tag) - *ret_tag = tag; - - return TRUE; -} -#endif - -/* - * gst_avi_demux_peek_tag: - * - * Returns the tag and size of the next chunk - */ -static GstFlowReturn -gst_avi_demux_peek_tag (GstAviDemux * avi, guint64 offset, guint32 * tag, - guint * size) -{ - GstFlowReturn res = GST_FLOW_OK; - GstBuffer *buf = NULL; - guint bufsize; - - res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf); - if (res != GST_FLOW_OK) - goto pull_failed; - - bufsize = GST_BUFFER_SIZE (buf); - if (bufsize != 8) - goto wrong_size; - - *tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); - *size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4); - - GST_LOG_OBJECT (avi, "Tag[%" GST_FOURCC_FORMAT "] (size:%d) %" - G_GINT64_FORMAT " -- %" G_GINT64_FORMAT, GST_FOURCC_ARGS (*tag), - *size, offset + 8, offset + 8 + (gint64) * size); -done: - gst_buffer_unref (buf); - - return res; - - /* ERRORS */ -pull_failed: - { - GST_DEBUG_OBJECT (avi, "pull_ranged returned %s", gst_flow_get_name (res)); - return res; - } -wrong_size: - { - GST_DEBUG_OBJECT (avi, "got %d bytes which is <> 8 bytes", bufsize); - res = GST_FLOW_ERROR; - goto done; - } -} - -/* - * gst_avi_demux_next_data_buffer: - * - * Returns the offset and size of the next buffer - * Position is the position of the buffer (after tag and size) - */ -static GstFlowReturn -gst_avi_demux_next_data_buffer (GstAviDemux * avi, guint64 * offset, - guint32 * tag, guint * size) -{ - guint64 off = *offset; - guint _size = 0; - GstFlowReturn res; - - do { - res = gst_avi_demux_peek_tag (avi, off, tag, &_size); - if (res != GST_FLOW_OK) - break; - if (*tag == GST_RIFF_TAG_LIST || *tag == GST_RIFF_TAG_RIFF) - off += 8 + 4; /* skip tag + size + subtag */ - else { - *offset = off + 8; - *size = _size; - break; - } - } while (TRUE); - - return res; -} - -/* - * gst_avi_demux_stream_scan: - * @avi: calling element (used for debugging/errors). - * @index: list of index entries, returned by this function. - * @alloc_list: list of allocated data, returned by this function. - * - * Scan the file for all chunks to "create" a new index. - * Return value indicates if we can continue reading the stream. It - * does not say anything about whether we created an index. - * - * pull-range based - */ -static gboolean -gst_avi_demux_stream_scan (GstAviDemux * avi, - GList ** index, GList ** alloc_list) -{ - GstFlowReturn res; - gst_avi_index_entry *entry, *entries = NULL; - avi_stream_context *stream; - GstFormat format; - guint64 pos = avi->offset; - guint64 length; - gint64 tmplength; - guint32 tag = 0; - GList *list = NULL; - guint index_size = 0; - - /* FIXME: - * - implement non-seekable source support. - */ - GST_DEBUG_OBJECT (avi, - "Creating index %s existing index, starting at offset %" G_GUINT64_FORMAT, - ((*index) ? "with" : "without"), pos); - - format = GST_FORMAT_BYTES; - if (!gst_pad_query_peer_duration (avi->sinkpad, &format, &tmplength)) - return FALSE; - - length = tmplength; - - if (*index) { - entry = g_list_last (*index)->data; - pos = entry->offset + avi->index_offset + entry->size; - if (entry->size & 1) - pos++; - - if (pos >= length) { - GST_LOG_OBJECT (avi, "Complete index, we're done"); - return TRUE; - } - - GST_LOG_OBJECT (avi, "Incomplete index, seeking to last valid entry @ %" - G_GUINT64_FORMAT " of %" G_GUINT64_FORMAT " (%" - G_GUINT64_FORMAT "+%u)", pos, length, entry->offset, entry->size); - } - - while (TRUE) { - guint stream_nr; - guint size = 0; - - res = gst_avi_demux_next_data_buffer (avi, &pos, &tag, &size); - if (G_UNLIKELY (res != GST_FLOW_OK)) - break; - - /* check valid stream */ - stream_nr = CHUNKID_TO_STREAMNR (tag); - if (G_UNLIKELY (stream_nr >= avi->num_streams)) { - GST_WARNING_OBJECT (avi, - "Index entry has invalid stream nr %d", stream_nr); - goto next; - } - - stream = &avi->stream[stream_nr]; - if (G_UNLIKELY (stream->pad == NULL)) { - GST_WARNING_OBJECT (avi, - "Stream %d does not have an output pad, can't create new index", - stream_nr); - goto next; - } - - /* pre-allocate */ - if (G_UNLIKELY (index_size % 1024 == 0)) { - entries = g_new (gst_avi_index_entry, 1024); - *alloc_list = g_list_prepend (*alloc_list, entries); - } - entry = &entries[index_size % 1024]; - - entry->index_nr = index_size++; - entry->stream_nr = stream_nr; - entry->flags = GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME; - entry->offset = pos - avi->index_offset; - entry->size = size; - - /* timestamps, get timestamps of two consecutive frames to calculate - * timestamp and duration. */ - format = GST_FORMAT_TIME; - if (stream->is_vbr) { - /* VBR stream */ - entry->ts = avi_stream_convert_frames_to_time_unchecked (stream, - stream->total_frames); - entry->dur = avi_stream_convert_frames_to_time_unchecked (stream, - stream->total_frames + 1); - } else { - /* constant rate stream */ - entry->ts = avi_stream_convert_bytes_to_time_unchecked (stream, - stream->total_bytes); - entry->dur = avi_stream_convert_bytes_to_time_unchecked (stream, - stream->total_bytes + entry->size); - } - entry->dur -= entry->ts; - - /* stream position */ - entry->bytes_before = stream->total_bytes; - stream->total_bytes += entry->size; - entry->frames_before = stream->total_frames; - stream->total_frames++; - stream->idx_duration = entry->ts + entry->dur; - - list = g_list_prepend (list, entry); - GST_DEBUG_OBJECT (avi, "Added index entry %d (in stream: %d), offset %" - G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT " for stream %d", - index_size - 1, entry->frames_before, entry->offset, - GST_TIME_ARGS (entry->ts), entry->stream_nr); - - next: - /* update position */ - pos += GST_ROUND_UP_2 (size); - if (G_UNLIKELY (pos > length)) { - GST_WARNING_OBJECT (avi, - "Stopping index lookup since we are further than EOF"); - break; - } - } - - /* FIXME: why is this disabled */ -#if 0 - while (gst_avi_demux_sync (avi, &tag, TRUE)) { - guint stream_nr = CHUNKID_TO_STREAMNR (tag); - guint8 *data; - GstFormat format = GST_FORMAT_TIME; - - if (stream_nr >= avi->num_streams) - goto next; - stream = &avi->stream[stream_nr]; - - /* get chunk size */ - if (gst_bytestream_peek_bytes (riff->bs, &data, 8) != 8) - goto next; - - /* fill in */ - entry->index_nr = index_size++; - entry->stream_nr = stream_nr; - entry->flags = GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME; - entry->offset = gst_bytestream_tell (riff->bs) + 8 - avi->index_offset; - entry->size = GST_READ_UINT32_LE (&data[4]); - - /* timestamps */ - if (stream->is_vbr) { - /* VBR stream */ - entry->ts = avi_stream_convert_frames_to_time_unchecked (stream, - stream->total_frames); - entry->dur = avi_stream_convert_frames_to_time_unchecked (stream, - stream->total_frames + 1); - } else { - /* constant rate stream */ - entry->ts = avi_stream_convert_bytes_to_time_unchecked (stream, - stream->total_bytes); - entry->dur = avi_stream_convert_bytes_to_time_unchecked (stream, - stream->total_bytes + entry->size); - } - entry->dur -= entry->ts; - - /* stream position */ - entry->bytes_before = stream->total_bytes; - stream->total_bytes += entry->size; - entry->frames_before = stream->total_frames; - stream->total_frames++; - - list = g_list_prepend (list, entry); - GST_DEBUG_OBJECT (avi, "Added index entry %d (in stream: %d), offset %" - G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT " for stream %d", - index_size - 1, entry->frames_before, entry->offset, - GST_TIME_ARGS (entry->ts), entry->stream_nr); - - next: - if (!gst_avi_demux_skip (avi, TRUE)) - break; - } - /* seek back */ - if (!(event = gst_riff_read_seek (riff, pos))) { - g_list_free (list); - return FALSE; - } - gst_event_unref (event); - -#endif - - GST_DEBUG_OBJECT (avi, "index created, %d items", index_size); - - *index = g_list_concat (*index, g_list_reverse (list)); - - return TRUE; -} - -/* - * gst_avi_demux_massage_index: - * @avi: calling element (used for debugging/errors). - * - * We're going to go over each entry in the index and finetune - * some things we don't like about AVI. For example, a single - * chunk might be too long. Also, individual streams might be - * out-of-sync. In the first case, we cut the chunk in several - * smaller pieces. In the second case, we re-order chunk reading - * order. The end result should be a smoother playing AVI. - */ -static gboolean -gst_avi_demux_massage_index (GstAviDemux * avi, - GList * list, GList * alloc_list) -{ - gst_avi_index_entry *entry; - avi_stream_context *stream; - guint i; - GList *node; - gint64 delay = G_GINT64_CONSTANT (0); - - GST_LOG_OBJECT (avi, "Starting index massage, nr_entries = %d", - list ? g_list_length (list) : 0); - - if (list) { -#ifndef GST_DISABLE_GST_DEBUG - guint num_added_total = 0; - guint num_per_stream[GST_AVI_DEMUX_MAX_STREAMS] = { 0, }; -#endif - GST_LOG_OBJECT (avi, - "I'm now going to cut large chunks into smaller pieces"); - - /* cut chunks in small (seekable) pieces - * FIXME: this should be a property where a value of - * GST_CLOCK_TIME_NONE would disable the chunking - */ -#define MAX_DURATION (GST_SECOND / 2) - for (i = 0; i < avi->num_streams; i++) { - /* only chop streams that have exactly *one* chunk */ - if (avi->stream[i].total_frames != 1) - continue; - - for (node = list; node != NULL; node = node->next) { - entry = node->data; - - if (entry->stream_nr != i) - continue; - - /* check for max duration of a single buffer. I suppose that - * the allocation of index entries could be improved. */ - stream = &avi->stream[entry->stream_nr]; - if (entry->dur > MAX_DURATION - && stream->strh->type == GST_RIFF_FCC_auds) { - guint32 ideal_size; - gst_avi_index_entry *entries; - guint old_size, num_added; - GList *node2; - - /* cut in 1/10th of a second */ - ideal_size = stream->strf.auds->av_bps / 10; - - /* ensure chunk size is multiple of blockalign */ - if (stream->strf.auds->blockalign > 1) - ideal_size -= ideal_size % stream->strf.auds->blockalign; - - /* copy index */ - old_size = entry->size; - num_added = (entry->size - 1) / ideal_size; - avi->index_size += num_added; - entries = g_malloc (sizeof (gst_avi_index_entry) * num_added); - alloc_list = g_list_prepend (alloc_list, entries); - for (node2 = node->next; node2 != NULL; node2 = node2->next) { - gst_avi_index_entry *entry2 = node2->data; - - entry2->index_nr += num_added; - if (entry2->stream_nr == entry->stream_nr) - entry2->frames_before += num_added; - } - - /* new sized index chunks */ - for (i = 0; i < num_added + 1; i++) { - gst_avi_index_entry *entry2; - - if (i == 0) { - entry2 = entry; - } else { - entry2 = &entries[i - 1]; - list = g_list_insert_before (list, node->next, entry2); - entry = node->data; - node = node->next; - memcpy (entry2, entry, sizeof (gst_avi_index_entry)); - } - - if (old_size >= ideal_size) { - entry2->size = ideal_size; - old_size -= ideal_size; - } else { - entry2->size = old_size; - } - - entry2->dur = GST_SECOND * entry2->size / stream->strf.auds->av_bps; - if (i != 0) { - entry2->index_nr++; - entry2->ts += entry->dur; - entry2->offset += entry->size; - entry2->bytes_before += entry->size; - entry2->frames_before++; - } - } -#ifndef GST_DISABLE_GST_DEBUG - num_added_total += num_added; -#endif - } - } - } -#ifndef GST_DISABLE_GST_DEBUG - if (num_added_total) - GST_LOG ("added %u new index entries", num_added_total); -#endif - - GST_LOG_OBJECT (avi, "I'm now going to reorder the index entries for time"); - - /* re-order for time */ - list = g_list_sort (list, (GCompareFunc) sort); - - /* make a continous array out of the list */ - avi->index_size = g_list_length (list); - avi->index_entries = g_try_new (gst_avi_index_entry, avi->index_size); - if (!avi->index_entries) - goto out_of_mem; - - entry = (gst_avi_index_entry *) (list->data); - delay = entry->ts; - - GST_LOG_OBJECT (avi, - "Building index array, nr_entries = %d (time offset = %" - GST_TIME_FORMAT, avi->index_size, GST_TIME_ARGS (delay)); - - for (i = 0, node = list; node != NULL; node = node->next, i++) { - entry = node->data; - entry->index_nr = i; - entry->ts -= delay; - memcpy (&avi->index_entries[i], entry, sizeof (gst_avi_index_entry)); -#ifndef GST_DISABLE_GST_DEBUG - num_per_stream[entry->stream_nr]++; -#endif - - GST_LOG_OBJECT (avi, "Sorted index entry %3d for stream %d of size %6u" - " at offset %7" G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT - " dur %" GST_TIME_FORMAT, - avi->index_entries[i].index_nr, entry->stream_nr, entry->size, - entry->offset, GST_TIME_ARGS (entry->ts), GST_TIME_ARGS (entry->dur)); - } - if (delay) { - for (i = 0; i < avi->num_streams; i++) { - stream = &avi->stream[i]; - stream->idx_duration -= delay; - } - } -#ifndef GST_DISABLE_GST_DEBUG - { - gchar str[GST_AVI_DEMUX_MAX_STREAMS * (1 + 6 + 2)]; - gchar *pad_name; - - for (i = 0; i < avi->num_streams; i++) { - if (!avi->stream[i].pad) - continue; - pad_name = GST_OBJECT_NAME (avi->stream[i].pad); - sprintf (&str[i * (1 + 6 + 2)], " %6u %c", num_per_stream[i], - pad_name[0]); - } - GST_LOG_OBJECT (avi, "indizies per stream:%20s", str); - } -#endif - - GST_LOG_OBJECT (avi, "Freeing original index list"); - /* all the node->data in list point to alloc_list chunks */ - - g_list_free (list); - } - if (alloc_list) { - g_list_foreach (alloc_list, (GFunc) g_free, NULL); - g_list_free (alloc_list); - } -#ifndef GST_DISABLE_GST_DEBUG - for (i = 0; i < avi->num_streams; i++) { - GST_LOG_OBJECT (avi, "Stream %d, %d frames, %8" G_GUINT64_FORMAT " bytes", - i, avi->stream[i].total_frames, avi->stream[i].total_bytes); - } -#endif - - GST_LOG_OBJECT (avi, "Index massaging done"); - return TRUE; - - /* ERRORS */ -out_of_mem: - GST_WARNING_OBJECT (avi, "Out of memory for %" G_GSIZE_FORMAT " bytes", - sizeof (gst_avi_index_entry) * avi->index_size); - return FALSE; -} - -static void -gst_avi_demux_calculate_durations_from_index (GstAviDemux * avi) -{ - gint stream; - GstClockTime total; - - total = GST_CLOCK_TIME_NONE; - - /* all streams start at a timestamp 0 */ - for (stream = 0; stream < avi->num_streams; stream++) { - GstClockTime duration, hduration; - avi_stream_context *streamc = &avi->stream[stream]; - gst_riff_strh *strh = streamc->strh; - - if (!strh) - continue; - - /* get header duration for the stream */ - hduration = streamc->hdr_duration; - - /* index duration calculated during parsing, invariant under massage */ - duration = streamc->idx_duration; - - /* now pick a good duration */ - if (GST_CLOCK_TIME_IS_VALID (duration)) { - /* index gave valid duration, use that */ - GST_INFO ("Stream %d duration according to index: %" GST_TIME_FORMAT, - stream, GST_TIME_ARGS (duration)); - } else { - /* fall back to header info to calculate a duration */ - duration = hduration; - } - /* set duration for the stream */ - streamc->duration = duration; - - /* find total duration */ - if (total == GST_CLOCK_TIME_NONE || duration > total) - total = duration; - } - - if (GST_CLOCK_TIME_IS_VALID (total) && (total > 0)) { - /* now update the duration for those streams where we had none */ - for (stream = 0; stream < avi->num_streams; stream++) { - avi_stream_context *streamc = &avi->stream[stream]; - - if (!GST_CLOCK_TIME_IS_VALID (streamc->duration) - || streamc->duration == 0) { - streamc->duration = total; - - GST_INFO ("Stream %d duration according to total: %" GST_TIME_FORMAT, - stream, GST_TIME_ARGS (total)); - } - } - } - - /* and set the total duration in the segment. */ - GST_INFO ("Setting total duration to: %" GST_TIME_FORMAT, - GST_TIME_ARGS (total)); - - gst_segment_set_duration (&avi->segment, GST_FORMAT_TIME, total); -} - -/* returns FALSE if there are no pads to deliver event to, - * otherwise TRUE (whatever the outcome of event sending) */ -static gboolean -gst_avi_demux_push_event (GstAviDemux * avi, GstEvent * event) -{ - gboolean result = FALSE; - gint i; - - GST_DEBUG_OBJECT (avi, "sending %s event to %d streams", - GST_EVENT_TYPE_NAME (event), avi->num_streams); - - if (avi->num_streams) { - for (i = 0; i < avi->num_streams; i++) { - avi_stream_context *stream = &avi->stream[i]; - - if (stream->pad) { - result = TRUE; - gst_pad_push_event (stream->pad, gst_event_ref (event)); - } - } - } - gst_event_unref (event); - return result; -} - -/* - * Read AVI headers when streaming - */ -static GstFlowReturn -gst_avi_demux_stream_header_push (GstAviDemux * avi) -{ - GstFlowReturn ret = GST_FLOW_OK; - guint32 tag = 0; - guint32 ltag = 0; - guint32 size = 0; - const guint8 *data; - GstBuffer *buf = NULL, *sub = NULL; - guint offset = 4; - gint64 stop; - - GST_DEBUG ("Reading and parsing avi headers: %d", avi->header_state); - - switch (avi->header_state) { - case GST_AVI_DEMUX_HEADER_TAG_LIST: - if (gst_avi_demux_peek_chunk (avi, &tag, &size)) { - avi->offset += 8 + ((size + 1) & ~1); - if (tag != GST_RIFF_TAG_LIST) - goto header_no_list; - - gst_adapter_flush (avi->adapter, 8); - /* Find the 'hdrl' LIST tag */ - GST_DEBUG ("Reading %d bytes", size); - buf = gst_adapter_take_buffer (avi->adapter, size); - - if (GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)) != GST_RIFF_LIST_hdrl) - goto header_no_hdrl; - - /* mind padding */ - if (size & 1) - gst_adapter_flush (avi->adapter, 1); - - GST_DEBUG ("'hdrl' LIST tag found. Parsing next chunk"); - - /* the hdrl starts with a 'avih' header */ - if (!gst_riff_parse_chunk (GST_ELEMENT (avi), buf, &offset, &tag, &sub)) - goto header_no_avih; - - if (tag != GST_RIFF_TAG_avih) - goto header_no_avih; - - if (!gst_avi_demux_parse_avih (GST_ELEMENT (avi), sub, &avi->avih)) - goto header_wrong_avih; - - GST_DEBUG_OBJECT (avi, "AVI header ok, reading elemnts from header"); - - /* now, read the elements from the header until the end */ - while (gst_riff_parse_chunk (GST_ELEMENT (avi), buf, &offset, &tag, - &sub)) { - /* sub can be NULL on empty tags */ - if (!sub) - continue; - - switch (tag) { - case GST_RIFF_TAG_LIST: - if (GST_BUFFER_SIZE (sub) < 4) - goto next; - - switch (GST_READ_UINT32_LE (GST_BUFFER_DATA (sub))) { - case GST_RIFF_LIST_strl: - if (!(gst_avi_demux_parse_stream (avi, sub))) { - sub = NULL; - GST_ELEMENT_WARNING (avi, STREAM, DEMUX, (NULL), - ("failed to parse stream, ignoring")); - goto next; - } - sub = NULL; - goto next; - case GST_RIFF_LIST_odml: - gst_avi_demux_parse_odml (avi, sub); - sub = NULL; - break; - default: - GST_WARNING_OBJECT (avi, - "Unknown list %" GST_FOURCC_FORMAT " in AVI header", - GST_FOURCC_ARGS (GST_READ_UINT32_LE (GST_BUFFER_DATA - (sub)))); - /* fall-through */ - case GST_RIFF_TAG_JUNK: - goto next; - } - break; - default: - GST_WARNING_OBJECT (avi, - "Unknown off %d tag %" GST_FOURCC_FORMAT " in AVI header", - offset, GST_FOURCC_ARGS (tag)); - /* fall-through */ - case GST_RIFF_TAG_JUNK: - next: - /* move to next chunk */ - if (sub) - gst_buffer_unref (sub); - sub = NULL; - break; - } - } - gst_buffer_unref (buf); - GST_DEBUG ("elements parsed"); - - /* check parsed streams */ - if (avi->num_streams == 0) { - goto no_streams; - } else if (avi->num_streams != avi->avih->streams) { - GST_WARNING_OBJECT (avi, - "Stream header mentioned %d streams, but %d available", - avi->avih->streams, avi->num_streams); - } - GST_DEBUG ("Get junk and info next"); - avi->header_state = GST_AVI_DEMUX_HEADER_INFO; - } else { - /* Need more data */ - return ret; - } - /* fall-though */ - case GST_AVI_DEMUX_HEADER_INFO: - GST_DEBUG_OBJECT (avi, "skipping junk between header and data ..."); - while (TRUE) { - if (gst_adapter_available (avi->adapter) < 12) - return GST_FLOW_OK; - - data = gst_adapter_peek (avi->adapter, 12); - tag = GST_READ_UINT32_LE (data); - size = GST_READ_UINT32_LE (data + 4); - ltag = GST_READ_UINT32_LE (data + 8); - - if (tag == GST_RIFF_TAG_LIST) { - switch (ltag) { - case GST_RIFF_LIST_movi: - gst_adapter_flush (avi->adapter, 12); - avi->offset += 12; - goto skipping_done; - case GST_RIFF_LIST_INFO: - GST_DEBUG ("Found INFO chunk"); - if (gst_avi_demux_peek_chunk (avi, &tag, &size)) { - GST_DEBUG ("got size %d", size); - avi->offset += 12; - gst_adapter_flush (avi->adapter, 12); - if (size > 4) { - buf = gst_adapter_take_buffer (avi->adapter, size - 4); - /* mind padding */ - if (size & 1) - gst_adapter_flush (avi->adapter, 1); - gst_riff_parse_info (GST_ELEMENT (avi), buf, - &avi->globaltags); - gst_buffer_unref (buf); - - avi->offset += ((size + 1) & ~1) - 4; - } else { - GST_DEBUG ("skipping INFO LIST prefix"); - } - } else { - /* Need more data */ - return GST_FLOW_OK; - } - break; - default: - if (gst_avi_demux_peek_chunk (avi, &tag, &size)) { - avi->offset += 8 + ((size + 1) & ~1); - gst_adapter_flush (avi->adapter, 8 + ((size + 1) & ~1)); - // ??? goto iterate; ??? - } else { - /* Need more data */ - return GST_FLOW_OK; - } - break; - } - } else { - if (gst_avi_demux_peek_chunk (avi, &tag, &size)) { - avi->offset += 8 + ((size + 1) & ~1); - gst_adapter_flush (avi->adapter, 8 + ((size + 1) & ~1)); - //goto iterate; - } else { - /* Need more data */ - return GST_FLOW_OK; - } - } - } - break; - default: - GST_WARNING ("unhandled header state: %d", avi->header_state); - break; - } -skipping_done: - - GST_DEBUG_OBJECT (avi, "skipping done ... (streams=%u, stream[0].indexes=%p)", - avi->num_streams, avi->stream[0].indexes); - - GST_DEBUG ("Found movi chunk. Starting to stream data"); - avi->state = GST_AVI_DEMUX_MOVI; - -#if 0 - /*GList *index = NULL, *alloc = NULL; */ - - /* ######################## this need to be integrated with the state */ - /* create or read stream index (for seeking) */ - if (avi->stream[0].indexes != NULL) { - gst_avi_demux_read_subindexes_push (avi, &index, &alloc); - } - if (!index) { - if (avi->avih->flags & GST_RIFF_AVIH_HASINDEX) { - gst_avi_demux_stream_index (avi, &index, &alloc); - } - /* some indexes are incomplete, continue streaming from there */ - if (!index) - gst_avi_demux_stream_scan (avi, &index, &alloc); - } - - /* this is a fatal error */ - if (!index) - goto no_index; - - if (!gst_avi_demux_massage_index (avi, index, alloc)) - goto no_index; - - gst_avi_demux_calculate_durations_from_index (avi); - /* ######################## */ -#endif - - /* create initial NEWSEGMENT event */ - if ((stop = avi->segment.stop) == GST_CLOCK_TIME_NONE) - stop = avi->segment.duration; - - GST_DEBUG_OBJECT (avi, "segment stop %" G_GINT64_FORMAT, stop); - - if (avi->seek_event) - gst_event_unref (avi->seek_event); - avi->seek_event = gst_event_new_new_segment - (FALSE, avi->segment.rate, GST_FORMAT_TIME, - avi->segment.start, stop, avi->segment.start); - - /* at this point we know all the streams and we can signal the no more - * pads signal */ - GST_DEBUG_OBJECT (avi, "signaling no more pads"); - gst_element_no_more_pads (GST_ELEMENT (avi)); - - return GST_FLOW_OK; - - /* ERRORS */ -no_streams: - { - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("No streams found")); - return GST_FLOW_ERROR; - } -header_no_list: - { - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), - ("Invalid AVI header (no LIST at start): %" - GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag))); - return GST_FLOW_ERROR; - } -header_no_hdrl: - { - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), - ("Invalid AVI header (no hdrl at start): %" - GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag))); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } -header_no_avih: - { - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), - ("Invalid AVI header (no avih at start): %" - GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag))); - if (sub) - gst_buffer_unref (sub); - - gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } -header_wrong_avih: - { - gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } -} - -/* - * Read full AVI headers. - */ -static GstFlowReturn -gst_avi_demux_stream_header_pull (GstAviDemux * avi) -{ - GstFlowReturn res; - GstBuffer *buf, *sub = NULL; - guint32 tag; - GList *index = NULL, *alloc = NULL; - guint offset = 4; - gint64 stop; - GstElement *element = GST_ELEMENT_CAST (avi); - - /* the header consists of a 'hdrl' LIST tag */ - res = gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag, &buf); - if (res != GST_FLOW_OK) - goto pull_range_failed; - else if (tag != GST_RIFF_TAG_LIST) - goto no_list; - else if (GST_BUFFER_SIZE (buf) < 4) - goto no_header; - - GST_DEBUG_OBJECT (avi, "parsing headers"); - - /* Find the 'hdrl' LIST tag */ - while (GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)) != GST_RIFF_LIST_hdrl) { - GST_LOG_OBJECT (avi, "buffer contains %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)))); - - /* Eat up */ - gst_buffer_unref (buf); - - /* read new chunk */ - res = gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag, &buf); - if (res != GST_FLOW_OK) - goto pull_range_failed; - else if (tag != GST_RIFF_TAG_LIST) - goto no_list; - else if (GST_BUFFER_SIZE (buf) < 4) - goto no_header; - } - - GST_DEBUG_OBJECT (avi, "hdrl LIST tag found"); - - /* the hdrl starts with a 'avih' header */ - if (!gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) - goto no_avih; - else if (tag != GST_RIFF_TAG_avih) - goto no_avih; - else if (!gst_avi_demux_parse_avih (element, sub, &avi->avih)) - goto invalid_avih; - - GST_DEBUG_OBJECT (avi, "AVI header ok, reading elements from header"); - - /* now, read the elements from the header until the end */ - while (gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) { - /* sub can be NULL on empty tags */ - if (!sub) - continue; - - switch (tag) { - case GST_RIFF_TAG_LIST: - { - guint8 *data; - guint32 fourcc; - - if (GST_BUFFER_SIZE (sub) < 4) - goto next; - - data = GST_BUFFER_DATA (sub); - fourcc = GST_READ_UINT32_LE (data); - - switch (fourcc) { - case GST_RIFF_LIST_strl: - if (!(gst_avi_demux_parse_stream (avi, sub))) { - GST_ELEMENT_WARNING (avi, STREAM, DEMUX, (NULL), - ("failed to parse stream, ignoring")); - sub = NULL; - } - sub = NULL; - goto next; - case GST_RIFF_LIST_odml: - gst_avi_demux_parse_odml (avi, sub); - sub = NULL; - break; - default: - GST_WARNING_OBJECT (avi, - "Unknown list %" GST_FOURCC_FORMAT " in AVI header", - GST_FOURCC_ARGS (fourcc)); - GST_MEMDUMP_OBJECT (avi, "Unknown list", GST_BUFFER_DATA (sub), - GST_BUFFER_SIZE (sub)); - /* fall-through */ - case GST_RIFF_TAG_JUNK: - goto next; - } - break; - } - default: - GST_WARNING_OBJECT (avi, - "Unknown tag %" GST_FOURCC_FORMAT " in AVI header at off %d", - GST_FOURCC_ARGS (tag), offset); - GST_MEMDUMP_OBJECT (avi, "Unknown tag", GST_BUFFER_DATA (sub), - GST_BUFFER_SIZE (sub)); - /* fall-through */ - case GST_RIFF_TAG_JUNK: - next: - if (sub) - gst_buffer_unref (sub); - sub = NULL; - break; - } - } - gst_buffer_unref (buf); - GST_DEBUG ("elements parsed"); - - /* check parsed streams */ - if (avi->num_streams == 0) - goto no_streams; - else if (avi->num_streams != avi->avih->streams) { - GST_WARNING_OBJECT (avi, - "Stream header mentioned %d streams, but %d available", - avi->avih->streams, avi->num_streams); - } - - GST_DEBUG_OBJECT (avi, "skipping junk between header and data, offset=%" - G_GUINT64_FORMAT, avi->offset); - - /* Now, find the data (i.e. skip all junk between header and data) */ - do { - guint size; - guint32 tag, ltag; - - res = gst_pad_pull_range (avi->sinkpad, avi->offset, 12, &buf); - if (res != GST_FLOW_OK) { - GST_DEBUG_OBJECT (avi, "pull_range failure while looking for tags"); - goto pull_range_failed; - } else if (GST_BUFFER_SIZE (buf) < 12) { - GST_DEBUG_OBJECT (avi, "got %d bytes which is less than 12 bytes", - GST_BUFFER_SIZE (buf)); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } - - tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); - size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4); - ltag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 8); - - GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u", - GST_FOURCC_ARGS (tag), size); - GST_MEMDUMP ("Tag content", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); - gst_buffer_unref (buf); - - switch (tag) { - case GST_RIFF_TAG_LIST:{ - switch (ltag) { - case GST_RIFF_LIST_movi: - GST_DEBUG_OBJECT (avi, - "Reached the 'movi' tag, we're done with skipping"); - goto skipping_done; - case GST_RIFF_LIST_INFO: - res = - gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag, - &buf); - if (res != GST_FLOW_OK) { - GST_DEBUG_OBJECT (avi, "couldn't read INFO chunk"); - goto pull_range_failed; - } - GST_DEBUG ("got size %u", GST_BUFFER_SIZE (buf)); - if (size < 4) { - GST_DEBUG ("skipping INFO LIST prefix"); - avi->offset += (4 - GST_ROUND_UP_2 (size)); - gst_buffer_unref (buf); - continue; - } - - sub = gst_buffer_create_sub (buf, 4, GST_BUFFER_SIZE (buf) - 4); - gst_riff_parse_info (element, sub, &avi->globaltags); - if (sub) { - gst_buffer_unref (sub); - sub = NULL; - } - gst_buffer_unref (buf); - /* gst_riff_read_chunk() has already advanced avi->offset */ - break; - default: - GST_WARNING_OBJECT (avi, - "Skipping unknown list tag %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (ltag)); - avi->offset += 8 + ((size + 1) & ~1); - break; - } - } - break; - default: - GST_WARNING_OBJECT (avi, "Skipping unknown tag %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (tag)); - /* Fall-through */ - case GST_MAKE_FOURCC ('J', 'U', 'N', 'Q'): - case GST_MAKE_FOURCC ('J', 'U', 'N', 'K'): - avi->offset += 8 + ((size + 1) & ~1); - break; - } - } while (1); -skipping_done: - - GST_DEBUG_OBJECT (avi, "skipping done ... (streams=%u, stream[0].indexes=%p)", - avi->num_streams, avi->stream[0].indexes); - - /* create or read stream index (for seeking) */ - if (avi->stream[0].indexes != NULL) { - /* we read a super index already (gst_avi_demux_parse_superindex() ) */ - gst_avi_demux_read_subindexes_pull (avi, &index, &alloc); - } - if (!index) { - if (avi->avih->flags & GST_RIFF_AVIH_HASINDEX) { - gst_avi_demux_stream_index (avi, &index, &alloc); - } - /* some indexes are incomplete, continue streaming from there */ - if (!index) - gst_avi_demux_stream_scan (avi, &index, &alloc); - } - - /* this is a fatal error */ - if (!index) - goto no_index; - - if (!gst_avi_demux_massage_index (avi, index, alloc)) - goto no_index; - - gst_avi_demux_calculate_durations_from_index (avi); - - /* create initial NEWSEGMENT event */ - if ((stop = avi->segment.stop) == GST_CLOCK_TIME_NONE) - stop = avi->segment.duration; - - GST_DEBUG_OBJECT (avi, "segment stop %" G_GINT64_FORMAT, stop); - - if (avi->seek_event) - gst_event_unref (avi->seek_event); - avi->seek_event = gst_event_new_new_segment - (FALSE, avi->segment.rate, GST_FORMAT_TIME, - avi->segment.start, stop, avi->segment.start); - - /* at this point we know all the streams and we can signal the no more - * pads signal */ - GST_DEBUG_OBJECT (avi, "signaling no more pads"); - gst_element_no_more_pads (GST_ELEMENT_CAST (avi)); - - return GST_FLOW_OK; - - /* ERRORS */ -no_list: - { - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), - ("Invalid AVI header (no LIST at start): %" - GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag))); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } -no_header: - { - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), - ("Invalid AVI header (no hdrl at start): %" - GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag))); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } -no_avih: - { - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), - ("Invalid AVI header (no avih at start): %" - GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag))); - if (sub) - gst_buffer_unref (sub); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } -invalid_avih: - { - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), - ("Invalid AVI header (cannot parse avih at start)")); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } -no_streams: - { - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("No streams found")); - return GST_FLOW_ERROR; - } -no_index: - { - GST_WARNING ("file without or too big index"); - g_list_free (index); - g_list_foreach (alloc, (GFunc) g_free, NULL); - g_list_free (alloc); - - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), - ("Could not get/create index")); - return GST_FLOW_ERROR; - } -pull_range_failed: - { - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), - ("pull_range flow reading header: %s", gst_flow_get_name (res))); - return GST_FLOW_ERROR; - } -} - -/* - * Do the actual seeking. - */ -static gboolean -gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment) -{ - GstClockTime seek_time; - gboolean keyframe; - gst_avi_index_entry *entry, *kentry; - gint old_entry; - - seek_time = segment->last_stop; - keyframe = !!(segment->flags & GST_SEEK_FLAG_KEY_UNIT); - - /* FIXME: if we seek in an openDML file, we will have multiple - * primary levels. Seeking in between those will cause havoc. */ - - /* save old position so we can see if we must mark a discont. */ - old_entry = avi->current_entry; - - /* get the entry for the requested position, which is always in last_stop. - * we search the index entry for stream 0, since all entries are sorted by - * time and stream we automagically are positioned for the other streams as - * well. FIXME, this code assumes the main stream with keyframes is stream 0, - * which is mostly correct... */ - if (!(entry = gst_avi_demux_index_entry_for_time (avi, 0, seek_time))) - goto no_entry; - - GST_DEBUG_OBJECT (avi, - "Got requested entry %d [stream:%d / ts:%" GST_TIME_FORMAT - " / duration:%" GST_TIME_FORMAT "]", entry->index_nr, - entry->stream_nr, GST_TIME_ARGS (entry->ts), GST_TIME_ARGS (entry->dur)); - - /* check if we are already on a keyframe */ - if (!(entry->flags & GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME)) { - /* now go to the previous keyframe, this is where we should start - * decoding from. */ - if (!(kentry = gst_avi_demux_index_prev (avi, 0, entry->index_nr, - GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME))) { - goto no_entry; - } - } else { - /* we were on a keyframe */ - kentry = entry; - } - - GST_DEBUG_OBJECT (avi, - "Got keyframe entry %d [stream:%d / ts:%" GST_TIME_FORMAT - " / duration:%" GST_TIME_FORMAT "]", kentry->index_nr, - entry->stream_nr, GST_TIME_ARGS (kentry->ts), - GST_TIME_ARGS (kentry->dur)); - - /* we must start decoding at the keyframe */ - avi->current_entry = kentry->index_nr; - - if (segment->rate < 0.0) { - gst_avi_index_entry *next_keyframe; - - /* Because we don't know the frame order we need to push from the prev keyframe - * to the next keyframe. If there is a smart decoder downstream he will notice - * that there are too many encoded frames send and return UNEXPECTED when there - * are enough decoded frames to fill the segment. - */ - next_keyframe = - gst_avi_demux_index_next (avi, 0, kentry->index_nr, - GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME); - if (!next_keyframe) - next_keyframe = gst_avi_demux_index_last (avi, 0); - - avi->reverse_start_index = kentry->index_nr; - avi->reverse_stop_index = next_keyframe->index_nr; - - GST_DEBUG_OBJECT (avi, "reverse seek: start idx (%d) and stop idx (%d)", - avi->reverse_start_index, avi->reverse_stop_index); - } - - if (keyframe) { - /* when seeking to a keyframe, we update the result seek time - * to the time of the keyframe. */ - seek_time = avi->index_entries[avi->current_entry].ts; - } - -next: - /* if we changed position, mark a DISCONT on all streams */ - if (avi->current_entry != old_entry) { - gint i; - - for (i = 0; i < avi->num_streams; i++) { - avi->stream[i].discont = TRUE; - } - } - - GST_DEBUG_OBJECT (avi, "seek: %" GST_TIME_FORMAT - " keyframe seeking:%d", GST_TIME_ARGS (seek_time), keyframe); - - /* the seek time is also the last_stop and stream time */ - segment->last_stop = seek_time; - segment->time = seek_time; - - return TRUE; - -no_entry: - { - /* we could not find an entry for the given time */ - GST_WARNING_OBJECT (avi, - "Couldn't find AviIndexEntry for time:%" GST_TIME_FORMAT, - GST_TIME_ARGS (seek_time)); - if (avi->current_entry >= avi->index_size && avi->index_size > 0) - avi->current_entry = avi->index_size - 1; - - goto next; - } -} - -/* - * Handle seek event. - */ -static gboolean -gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad, GstEvent * event) -{ - gdouble rate; - GstFormat format; - GstSeekFlags flags; - GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type; - gint64 cur, stop; - gboolean flush; - gboolean update; - GstSegment seeksegment = { 0, }; - - if (event) { - GST_DEBUG_OBJECT (avi, "doing seek with event"); - - gst_event_parse_seek (event, &rate, &format, &flags, - &cur_type, &cur, &stop_type, &stop); - - /* we have to have a format as the segment format. Try to convert - * if not. */ - if (format != GST_FORMAT_TIME) { - GstFormat fmt = GST_FORMAT_TIME; - gboolean res = TRUE; - - if (cur_type != GST_SEEK_TYPE_NONE) - res = gst_pad_query_convert (pad, format, cur, &fmt, &cur); - if (res && stop_type != GST_SEEK_TYPE_NONE) - res = gst_pad_query_convert (pad, format, stop, &fmt, &stop); - if (!res) - goto no_format; - - format = fmt; - } - GST_DEBUG_OBJECT (avi, - "seek requested: rate %g cur %" GST_TIME_FORMAT " stop %" - GST_TIME_FORMAT, rate, GST_TIME_ARGS (cur), GST_TIME_ARGS (stop)); - /* FIXME: can we do anything with rate!=1.0 */ - } else { - GST_DEBUG_OBJECT (avi, "doing seek without event"); - flags = 0; - rate = 1.0; - } - - /* save flush flag */ - flush = flags & GST_SEEK_FLAG_FLUSH; - - if (flush) { - GstEvent *event = gst_event_new_flush_start (); - - /* for a flushing seek, we send a flush_start on all pads. This will - * eventually stop streaming with a WRONG_STATE. We can thus eventually - * take the STREAM_LOCK. */ - GST_DEBUG_OBJECT (avi, "sending flush start"); - gst_avi_demux_push_event (avi, gst_event_ref (event)); - gst_pad_push_event (avi->sinkpad, event); - } else { - /* a non-flushing seek, we PAUSE the task so that we can take the - * STREAM_LOCK */ - GST_DEBUG_OBJECT (avi, "non flushing seek, pausing task"); - gst_pad_pause_task (avi->sinkpad); - } - - /* wait for streaming to stop */ - GST_DEBUG_OBJECT (avi, "wait for streaming to stop"); - GST_PAD_STREAM_LOCK (avi->sinkpad); - - /* copy segment, we need this because we still need the old - * segment when we close the current segment. */ - memcpy (&seeksegment, &avi->segment, sizeof (GstSegment)); - - if (event) { - GST_DEBUG_OBJECT (avi, "configuring seek"); - gst_segment_set_seek (&seeksegment, rate, format, flags, - cur_type, cur, stop_type, stop, &update); - } - - /* do the seek, seeksegment.last_stop contains the new position, this - * actually never fails. */ - gst_avi_demux_do_seek (avi, &seeksegment); - - if (flush) { - gint i; - - GST_DEBUG_OBJECT (avi, "sending flush stop"); - gst_avi_demux_push_event (avi, gst_event_new_flush_stop ()); - gst_pad_push_event (avi->sinkpad, gst_event_new_flush_stop ()); - /* reset the last flow and mark discont, FLUSH is always DISCONT */ - for (i = 0; i < avi->num_streams; i++) { - avi->stream[i].last_flow = GST_FLOW_OK; - avi->stream[i].discont = TRUE; - } - } else if (avi->segment_running) { - GstEvent *seg; - - /* we are running the current segment and doing a non-flushing seek, - * close the segment first based on the last_stop. */ - GST_DEBUG_OBJECT (avi, "closing running segment %" G_GINT64_FORMAT - " to %" G_GINT64_FORMAT, avi->segment.start, avi->segment.last_stop); - seg = gst_event_new_new_segment (TRUE, - avi->segment.rate, avi->segment.format, - avi->segment.start, avi->segment.last_stop, avi->segment.time); - gst_avi_demux_push_event (avi, seg); - } - - /* now update the real segment info */ - memcpy (&avi->segment, &seeksegment, sizeof (GstSegment)); - - /* post the SEGMENT_START message when we do segmented playback */ - if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) { - gst_element_post_message (GST_ELEMENT (avi), - gst_message_new_segment_start (GST_OBJECT (avi), - avi->segment.format, avi->segment.last_stop)); - } - - /* prepare for streaming again */ - if ((stop = avi->segment.stop) == GST_CLOCK_TIME_NONE) - stop = avi->segment.duration; - - /* queue the segment event for the streaming thread. */ - if (avi->seek_event) - gst_event_unref (avi->seek_event); - if (avi->segment.rate > 0.0) { - avi->seek_event = gst_event_new_new_segment (FALSE, - avi->segment.rate, avi->segment.format, - avi->segment.last_stop, stop, avi->segment.time); - } else { - avi->seek_event = gst_event_new_new_segment (FALSE, - avi->segment.rate, avi->segment.format, - avi->segment.start, avi->segment.last_stop, avi->segment.start); - } - - if (!avi->streaming) { - avi->segment_running = TRUE; - gst_pad_start_task (avi->sinkpad, (GstTaskFunction) gst_avi_demux_loop, - avi->sinkpad); - } - GST_PAD_STREAM_UNLOCK (avi->sinkpad); - - return TRUE; - - /* ERRORS */ -no_format: - { - GST_DEBUG_OBJECT (avi, "unsupported format given, seek aborted."); - return FALSE; - } -} - -/* - * Helper for gst_avi_demux_invert() - */ -static inline void -swap_line (guint8 * d1, guint8 * d2, guint8 * tmp, gint bytes) -{ - memcpy (tmp, d1, bytes); - memcpy (d1, d2, bytes); - memcpy (d2, tmp, bytes); -} - - -#define gst_avi_demux_is_uncompressed(fourcc) \ - (fourcc == GST_RIFF_DIB || \ - fourcc == GST_RIFF_rgb || \ - fourcc == GST_RIFF_RGB || fourcc == GST_RIFF_RAW) - -/* - * Invert DIB buffers... Takes existing buffer and - * returns either the buffer or a new one (with old - * one dereferenced). - * FIXME: can't we preallocate tmp? and remember stride, bpp? - */ -static GstBuffer * -gst_avi_demux_invert (avi_stream_context * stream, GstBuffer * buf) -{ - GstStructure *s; - gint y, w, h; - gint bpp, stride; - guint8 *tmp = NULL; - - if (stream->strh->type != GST_RIFF_FCC_vids) - return buf; - - if (!gst_avi_demux_is_uncompressed (stream->strh->fcc_handler)) { - return buf; /* Ignore non DIB buffers */ - } - - s = gst_caps_get_structure (GST_PAD_CAPS (stream->pad), 0); - if (!gst_structure_get_int (s, "bpp", &bpp)) { - GST_WARNING ("Failed to retrieve depth from caps"); - return buf; - } - - if (stream->strf.vids == NULL) { - GST_WARNING ("Failed to retrieve vids for stream"); - return buf; - } - - h = stream->strf.vids->height; - w = stream->strf.vids->width; - stride = w * (bpp / 8); - - buf = gst_buffer_make_writable (buf); - if (GST_BUFFER_SIZE (buf) < (stride * h)) { - GST_WARNING ("Buffer is smaller than reported Width x Height x Depth"); - return buf; - } - - tmp = g_malloc (stride); - - for (y = 0; y < h / 2; y++) { - swap_line (GST_BUFFER_DATA (buf) + stride * y, - GST_BUFFER_DATA (buf) + stride * (h - 1 - y), tmp, stride); - } - - g_free (tmp); - - return buf; -} - -/* - * Returns the aggregated GstFlowReturn. - */ -static GstFlowReturn -gst_avi_demux_combine_flows (GstAviDemux * avi, avi_stream_context * stream, - GstFlowReturn ret) -{ - guint i; - - /* store the value */ - stream->last_flow = ret; - - /* any other error that is not-linked can be returned right away */ - if (G_UNLIKELY (ret != GST_FLOW_NOT_LINKED)) - goto done; - - /* only return NOT_LINKED if all other pads returned NOT_LINKED */ - for (i = 0; i < avi->num_streams; i++) { - avi_stream_context *ostream = &avi->stream[i]; - - ret = ostream->last_flow; - /* some other return value (must be SUCCESS but we can return - * other values as well) */ - if (G_UNLIKELY (ret != GST_FLOW_NOT_LINKED)) - goto done; - } - /* if we get here, all other pads were unlinked and we return - * NOT_LINKED then */ -done: - GST_LOG_OBJECT (avi, "combined return %s", gst_flow_get_name (ret)); - return ret; -} - -/* - * prepare the avi element for a reverse jump to a prev keyframe - * this function will return the start entry. if the function returns - * NULL there was no prev keyframe. - */ -static gst_avi_index_entry * -gst_avi_demux_step_reverse (GstAviDemux * avi) -{ - gst_avi_index_entry *entry; - gint i; - - avi->reverse_stop_index = avi->reverse_start_index; - entry = - gst_avi_demux_index_prev (avi, 0, avi->reverse_stop_index, - GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME); - if (!entry) { - GST_DEBUG_OBJECT (avi, "no valid index entry found index %d", - avi->reverse_stop_index); - return NULL; - } - avi->current_entry = avi->reverse_start_index = entry->index_nr; - GST_DEBUG_OBJECT (avi, - "reverse playback jump: start idx (%d) and stop idx (%d)", - avi->reverse_start_index, avi->reverse_stop_index); - gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, entry->ts); - for (i = 0; i < avi->num_streams; i++) { - avi->stream[i].last_flow = GST_FLOW_OK; - avi->stream[i].discont = TRUE; - } - return entry; -} - -/* - * Read data from one index entry - */ -static GstFlowReturn -gst_avi_demux_process_next_entry (GstAviDemux * avi) -{ - GstFlowReturn res = GST_FLOW_OK; - gboolean processed = FALSE; - avi_stream_context *stream; - gst_avi_index_entry *entry; - GstBuffer *buf; - - do { - /* see if we are at the end */ - if ((avi->segment.rate > 0 && avi->current_entry >= avi->index_size)) - goto eos; - - /* get next entry, this will work as we checked for the index size above */ - entry = &avi->index_entries[avi->current_entry++]; - - /* check for reverse playback */ - if (avi->segment.rate < 0 && avi->current_entry > avi->reverse_stop_index) { - GST_LOG_OBJECT (avi, "stop_index %d reached", avi->reverse_stop_index); - - /* check if we have pushed enough data for this segment */ - if (avi->reverse_start_index == 0) - goto eos_reverse_zero; - if (avi->index_entries[avi->reverse_start_index].ts < avi->segment.start) - goto eos_reverse_segment; - - if (!(entry = gst_avi_demux_step_reverse (avi))) - goto eos; - - avi->current_entry++; - } - - /* see if we have a valid stream, ignore if not - * FIXME: can't we check this when building the index? - * we check it in _parse_index(), _stream_scan() - */ - if (entry->stream_nr >= avi->num_streams) { - GST_WARNING_OBJECT (avi, - "Entry %d has non-existing stream nr %d", - avi->current_entry - 1, entry->stream_nr); - continue; - } - - /* get stream now */ - stream = &avi->stream[entry->stream_nr]; - - if (avi->segment.rate > 0.0) { - /* only check this for fowards playback for now */ - if ((entry->flags & GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME) - && GST_CLOCK_TIME_IS_VALID (entry->ts) - && GST_CLOCK_TIME_IS_VALID (avi->segment.stop) - && (entry->ts > avi->segment.stop)) { - goto eos_stop; - } - } - - /* skip empty entries */ - if (entry->size == 0 || !stream->pad) { - GST_DEBUG_OBJECT (avi, "Skipping entry %d (%d, %p)", - avi->current_entry - 1, entry->size, stream->pad); - goto next; - } - - GST_LOG ("reading buffer (size=%d) from stream %d at current pos %" - G_GUINT64_FORMAT " (%llx)", entry->size, entry->stream_nr, - avi->index_offset + entry->offset, avi->index_offset + entry->offset); - - /* pull in the data */ - res = gst_pad_pull_range (avi->sinkpad, entry->offset + - avi->index_offset, entry->size, &buf); - if (res != GST_FLOW_OK) - goto pull_failed; - - /* check for short buffers, this is EOS as well */ - if (GST_BUFFER_SIZE (buf) < entry->size) - goto short_buffer; - - /* invert the picture if needed */ - buf = gst_avi_demux_invert (stream, buf); - - /* mark non-keyframes */ - if (!(entry->flags & GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME)) - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); - - GST_BUFFER_TIMESTAMP (buf) = entry->ts; - GST_BUFFER_DURATION (buf) = entry->dur; - if (stream->strh->type == GST_RIFF_FCC_vids) { - if (stream->current_frame >= 0) - GST_BUFFER_OFFSET (buf) = stream->current_frame; - else { - gint64 framenum; - GstFormat fmt = GST_FORMAT_DEFAULT; - - if (gst_pad_query_convert (stream->pad, GST_FORMAT_TIME, entry->ts, - &fmt, &framenum)) - GST_BUFFER_OFFSET (buf) = framenum; - else - GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE; - } - } else - GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE; - GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE; - gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad)); - - GST_DEBUG_OBJECT (avi, "Pushing buffer of size %d, offset %" - G_GUINT64_FORMAT " and time %" - GST_TIME_FORMAT " on pad %s", - GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf), - GST_TIME_ARGS (entry->ts), GST_PAD_NAME (stream->pad)); - - /* update current position in the segment */ - gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, entry->ts); - - /* mark discont when pending */ - if (stream->discont) { - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - stream->discont = FALSE; - } - - res = gst_pad_push (stream->pad, buf); - - /* mark as processed, we increment the frame and byte counters then - * leave the while loop and return the GstFlowReturn */ - processed = TRUE; - GST_DEBUG_OBJECT (avi, "Processed buffer %d: %s", entry->index_nr, - gst_flow_get_name (res)); - - if (avi->segment.rate < 0 - && entry->ts > avi->segment.stop && res == GST_FLOW_UNEXPECTED) { - /* In reverse playback we can get a GST_FLOW_UNEXPECTED when - * we are at the end of the segment, so we just need to jump - * back to the previous section. - */ - GST_DEBUG_OBJECT (avi, "downstream has reached end of segment"); - - if (!(entry = gst_avi_demux_step_reverse (avi))) - goto eos; - - res = GST_FLOW_OK; - - stream->current_frame = entry->frames_before; - stream->current_byte = entry->bytes_before; - - continue; - } - - /* combine flows */ - res = gst_avi_demux_combine_flows (avi, stream, res); - - next: - stream->current_frame = entry->frames_before + 1; - stream->current_byte = entry->bytes_before + entry->size; - } while (!processed); - -beach: - GST_DEBUG_OBJECT (avi, "returning %s", gst_flow_get_name (res)); - - return res; - - /* ERRORS */ -eos: - { - GST_LOG_OBJECT (avi, "Handled last index entry, setting EOS (%d > %d)", - avi->current_entry, avi->index_size); - /* we mark the first stream as EOS */ - res = GST_FLOW_UNEXPECTED; - goto beach; - } -eos_stop: - { - GST_LOG_OBJECT (avi, "Found keyframe after segment," - " setting EOS (%" GST_TIME_FORMAT " > %" GST_TIME_FORMAT ")", - GST_TIME_ARGS (entry->ts), GST_TIME_ARGS (avi->segment.stop)); - res = GST_FLOW_UNEXPECTED; - goto beach; - } -eos_reverse_zero: - { - GST_DEBUG_OBJECT (avi, "start_index was 0, setting EOS"); - res = GST_FLOW_UNEXPECTED; - goto beach; - } -eos_reverse_segment: - { - GST_DEBUG_OBJECT (avi, "full segment pushed, setting EOS"); - res = GST_FLOW_UNEXPECTED; - goto beach; - } -pull_failed: - { - GST_DEBUG_OBJECT (avi, - "pull range failed: pos=%" G_GUINT64_FORMAT " size=%d", - entry->offset + avi->index_offset, entry->size); - goto beach; - } -short_buffer: - { - GST_WARNING_OBJECT (avi, "Short read at offset %" G_GUINT64_FORMAT - ", only got %d/%d bytes (truncated file?)", entry->offset + - avi->index_offset, GST_BUFFER_SIZE (buf), entry->size); - gst_buffer_unref (buf); - res = GST_FLOW_UNEXPECTED; - goto beach; - } -} - -/* - * Read data. If we have an index it delegates to - * gst_avi_demux_process_next_entry(). - */ -static GstFlowReturn -gst_avi_demux_stream_data (GstAviDemux * avi) -{ - guint32 tag = 0; - guint32 size = 0; - gint stream_nr = 0; - GstFlowReturn res = GST_FLOW_OK; - GstFormat format = GST_FORMAT_TIME; - - /* if we have a avi->index_entries[], we don't want to read - * the stream linearly, but seek to the next ts/index_entry. */ - if (G_LIKELY (avi->index_entries != NULL)) - return gst_avi_demux_process_next_entry (avi); - - if (G_UNLIKELY (avi->have_eos)) { - /* Clean adapter, we're done */ - gst_adapter_clear (avi->adapter); - return res; - } - - /* - if (!gst_avi_demux_sync (avi, &tag, FALSE)) - return FALSE; - */ - - /* Iterate until need more data, so adapter won't grow too much */ - while (1) { - if (G_UNLIKELY (!gst_avi_demux_peek_chunk_info (avi, &tag, &size))) { - return GST_FLOW_OK; - } - - GST_DEBUG ("Trying chunk (%" GST_FOURCC_FORMAT "), size %d", - GST_FOURCC_ARGS (tag), size); - - if (G_LIKELY ((tag & 0xff) >= '0' && (tag & 0xff) <= '9' && - ((tag >> 8) & 0xff) >= '0' && ((tag >> 8) & 0xff) <= '9')) { - GST_LOG ("Chunk ok"); - } else if ((tag & 0xffff) == (('x' << 8) | 'i')) { - GST_DEBUG ("Found sub-index tag"); - if (gst_avi_demux_peek_chunk (avi, &tag, &size)) { - if ((size > 0) && (size != -1)) { - GST_DEBUG (" skipping %d bytes for now", size); - gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size)); - } - } - return GST_FLOW_OK; - } else if (tag == GST_RIFF_TAG_JUNK) { - GST_DEBUG ("JUNK chunk, skipping"); - } else if (tag == GST_RIFF_TAG_idx1) { - GST_DEBUG ("Found index tag, stream done"); - avi->have_eos = TRUE; - return GST_FLOW_UNEXPECTED; - } else if (tag == GST_RIFF_TAG_LIST) { - /* movi chunks might be grouped in rec list */ - if (gst_adapter_available (avi->adapter) >= 12) { - GST_DEBUG ("Found LIST tag, skipping LIST header"); - gst_adapter_flush (avi->adapter, 12); - continue; - } - return GST_FLOW_OK; - } else if (tag == GST_RIFF_TAG_JUNK) { - /* rec list might contain JUNK chunks */ - GST_DEBUG ("Found JUNK tag"); - if (gst_avi_demux_peek_chunk (avi, &tag, &size)) { - if ((size > 0) && (size != -1)) { - GST_DEBUG (" skipping %d bytes for now", size); - gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size)); - continue; - } - } - return GST_FLOW_OK; - } else { - GST_DEBUG ("No more stream chunks, send EOS"); - avi->have_eos = TRUE; - return GST_FLOW_UNEXPECTED; - } - - if (G_UNLIKELY (!gst_avi_demux_peek_chunk (avi, &tag, &size))) { - if ((size == 0) || (size == -1)) - gst_adapter_flush (avi->adapter, 8); - return GST_FLOW_OK; - } - GST_DEBUG ("chunk ID %" GST_FOURCC_FORMAT ", size %u", - GST_FOURCC_ARGS (tag), size); - - stream_nr = CHUNKID_TO_STREAMNR (tag); - - if (G_UNLIKELY (stream_nr < 0 || stream_nr >= avi->num_streams)) { - /* recoverable */ - GST_WARNING ("Invalid stream ID %d (%" GST_FOURCC_FORMAT ")", - stream_nr, GST_FOURCC_ARGS (tag)); - avi->offset += 8 + ((size + 1) & ~1); - gst_adapter_flush (avi->adapter, 8 + ((size + 1) & ~1)); - } else { - avi_stream_context *stream; - GstClockTime next_ts = 0; - GstBuffer *buf; - - gst_adapter_flush (avi->adapter, 8); - - /* get buffer */ - buf = gst_adapter_take_buffer (avi->adapter, ((size + 1) & ~1)); - /* patch the size */ - GST_BUFFER_SIZE (buf) = size; - avi->offset += 8 + ((size + 1) & ~1); - - stream = &avi->stream[stream_nr]; - - /* set delay (if any) - if (stream->strh->init_frames == stream->current_frame && - stream->delay == 0) - stream->delay = next_ts; - */ - - stream->current_frame++; - stream->current_byte += size; - - /* parsing of corresponding header may have failed */ - if (G_UNLIKELY (!stream->pad)) { - GST_WARNING_OBJECT (avi, "no pad for stream ID %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (tag)); - gst_buffer_unref (buf); - } else { - GstClockTime dur_ts = 0; - - /* get time of this buffer */ - gst_pad_query_position (stream->pad, &format, (gint64 *) & next_ts); - if (G_UNLIKELY (format != GST_FORMAT_TIME)) - goto wrong_format; - - /* invert the picture if needed */ - buf = gst_avi_demux_invert (stream, buf); - - gst_pad_query_position (stream->pad, &format, (gint64 *) & dur_ts); - if (G_UNLIKELY (format != GST_FORMAT_TIME)) - goto wrong_format; - - GST_BUFFER_TIMESTAMP (buf) = next_ts; - GST_BUFFER_DURATION (buf) = dur_ts - next_ts; - if (stream->strh->type == GST_RIFF_FCC_vids) - GST_BUFFER_OFFSET (buf) = stream->current_frame - 1; - else - GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE; - - gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad)); - GST_DEBUG_OBJECT (avi, - "Pushing buffer with time=%" GST_TIME_FORMAT - ", offset %" G_GUINT64_FORMAT " and size %d over pad %s", - GST_TIME_ARGS (next_ts), GST_BUFFER_OFFSET (buf), size, - GST_PAD_NAME (stream->pad)); - - /* update current position in the segment */ - gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, next_ts); - - /* mark discont when pending */ - if (G_UNLIKELY (stream->discont)) { - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - stream->discont = FALSE; - } - res = gst_pad_push (stream->pad, buf); - - /* combine flows */ - res = gst_avi_demux_combine_flows (avi, stream, res); - if (G_UNLIKELY (res != GST_FLOW_OK)) { - GST_DEBUG ("Push failed; %s", gst_flow_get_name (res)); - return res; - } - } - } - } - -done: - return res; - - /* ERRORS */ -wrong_format: - { - GST_DEBUG_OBJECT (avi, "format %s != GST_FORMAT_TIME", - gst_format_get_name (format)); - res = GST_FLOW_ERROR; - goto done; - } -} - -/* - * Send pending tags. - */ -static void -push_tag_lists (GstAviDemux * avi) -{ - guint i; - - if (!avi->got_tags) - return; - - GST_DEBUG_OBJECT (avi, "Pushing pending tag lists"); - - for (i = 0; i < avi->num_streams; i++) - if (avi->stream[i].pad && avi->stream[i].taglist) { - GST_DEBUG_OBJECT (avi->stream[i].pad, "Tags: %" GST_PTR_FORMAT, - avi->stream[i].taglist); - gst_element_found_tags_for_pad (GST_ELEMENT (avi), avi->stream[i].pad, - avi->stream[i].taglist); - avi->stream[i].taglist = NULL; - } - - if (avi->globaltags == NULL) - avi->globaltags = gst_tag_list_new (); - - gst_tag_list_add (avi->globaltags, GST_TAG_MERGE_REPLACE, - GST_TAG_CONTAINER_FORMAT, "AVI", NULL); - - GST_DEBUG_OBJECT (avi, "Global tags: %" GST_PTR_FORMAT, avi->globaltags); - gst_element_found_tags (GST_ELEMENT (avi), avi->globaltags); - avi->globaltags = NULL; - avi->got_tags = FALSE; -} - -static void -gst_avi_demux_loop (GstPad * pad) -{ - GstFlowReturn res; - GstAviDemux *avi = GST_AVI_DEMUX (GST_PAD_PARENT (pad)); - - switch (avi->state) { - case GST_AVI_DEMUX_START: - if (G_UNLIKELY ((res = - gst_avi_demux_stream_init_pull (avi)) != GST_FLOW_OK)) { - GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res)); - goto pause; - } - avi->state = GST_AVI_DEMUX_HEADER; - /* fall-through */ - case GST_AVI_DEMUX_HEADER: - if (G_UNLIKELY ((res = - gst_avi_demux_stream_header_pull (avi)) != GST_FLOW_OK)) { - GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res)); - goto pause; - } - avi->state = GST_AVI_DEMUX_MOVI; - break; - case GST_AVI_DEMUX_MOVI: - if (G_UNLIKELY (avi->seek_event)) { - gst_avi_demux_push_event (avi, avi->seek_event); - avi->seek_event = NULL; - } - if (G_UNLIKELY (avi->got_tags)) { - push_tag_lists (avi); - } - /* process each index entry in turn */ - res = gst_avi_demux_stream_data (avi); - - /* pause when error */ - if (G_UNLIKELY (res != GST_FLOW_OK)) { - GST_INFO ("stream_movi flow: %s", gst_flow_get_name (res)); - goto pause; - } - break; - default: - GST_ERROR_OBJECT (avi, "unknown state %d", avi->state); - res = GST_FLOW_ERROR; - goto pause; - } - - GST_LOG_OBJECT (avi, "state: %d res:%s", avi->state, gst_flow_get_name (res)); - - return; - - /* ERRORS */ -pause: - GST_LOG_OBJECT (avi, "pausing task, reason %s", gst_flow_get_name (res)); - avi->segment_running = FALSE; - gst_pad_pause_task (avi->sinkpad); - - if (GST_FLOW_IS_FATAL (res) || (res == GST_FLOW_NOT_LINKED)) { - gboolean push_eos = TRUE; - - if (res == GST_FLOW_UNEXPECTED) { - /* handle end-of-stream/segment */ - if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) { - gint64 stop; - - if ((stop = avi->segment.stop) == -1) - stop = avi->segment.duration; - - GST_INFO_OBJECT (avi, "sending segment_done"); - - gst_element_post_message - (GST_ELEMENT (avi), - gst_message_new_segment_done (GST_OBJECT (avi), GST_FORMAT_TIME, - stop)); - push_eos = FALSE; - } - } else { - /* for fatal errors we post an error message */ - GST_ELEMENT_ERROR (avi, STREAM, FAILED, - (_("Internal data stream error.")), - ("streaming stopped, reason %s", gst_flow_get_name (res))); - } - if (push_eos) { - GST_INFO_OBJECT (avi, "sending eos"); - if (!gst_avi_demux_push_event (avi, gst_event_new_eos ()) && - (res == GST_FLOW_UNEXPECTED)) { - GST_ELEMENT_ERROR (avi, STREAM, DEMUX, - (NULL), ("got eos but no streams (yet)")); - } - } - } -} - - -static GstFlowReturn -gst_avi_demux_chain (GstPad * pad, GstBuffer * buf) -{ - GstFlowReturn res; - GstAviDemux *avi = GST_AVI_DEMUX (GST_PAD_PARENT (pad)); - - GST_DEBUG ("Store %d bytes in adapter", GST_BUFFER_SIZE (buf)); - gst_adapter_push (avi->adapter, buf); - - switch (avi->state) { - case GST_AVI_DEMUX_START: - if ((res = gst_avi_demux_stream_init_push (avi)) != GST_FLOW_OK) { - GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res)); - break; - } - break; - case GST_AVI_DEMUX_HEADER: - if ((res = gst_avi_demux_stream_header_push (avi)) != GST_FLOW_OK) { - GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res)); - break; - } - break; - case GST_AVI_DEMUX_MOVI: - if (G_UNLIKELY (avi->seek_event)) { - gst_avi_demux_push_event (avi, avi->seek_event); - avi->seek_event = NULL; - } - if (G_UNLIKELY (avi->got_tags)) { - push_tag_lists (avi); - } - res = gst_avi_demux_stream_data (avi); - break; - default: - GST_ELEMENT_ERROR (avi, STREAM, FAILED, (NULL), - ("Illegal internal state")); - res = GST_FLOW_ERROR; - break; - } - - GST_DEBUG_OBJECT (avi, "state: %d res:%s", avi->state, - gst_flow_get_name (res)); - - return res; -} - -static gboolean -gst_avi_demux_sink_activate (GstPad * sinkpad) -{ - if (gst_pad_check_pull_range (sinkpad)) { - GST_DEBUG ("going to pull mode"); - return gst_pad_activate_pull (sinkpad, TRUE); - } else { - GST_DEBUG ("going to push (streaming) mode"); - return gst_pad_activate_push (sinkpad, TRUE); - } -} - -static gboolean -gst_avi_demux_sink_activate_pull (GstPad * sinkpad, gboolean active) -{ - GstAviDemux *avi = GST_AVI_DEMUX (GST_OBJECT_PARENT (sinkpad)); - - if (active) { - avi->segment_running = TRUE; - avi->streaming = FALSE; - return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_avi_demux_loop, - sinkpad); - } else { - avi->segment_running = FALSE; - return gst_pad_stop_task (sinkpad); - } -} - -static gboolean -gst_avi_demux_activate_push (GstPad * pad, gboolean active) -{ - GstAviDemux *avi = GST_AVI_DEMUX (GST_OBJECT_PARENT (pad)); - - if (active) { - GST_DEBUG ("avi: activating push/chain function"); - avi->streaming = TRUE; - } else { - GST_DEBUG ("avi: deactivating push/chain function"); - } - - return TRUE; -} - -static GstStateChangeReturn -gst_avi_demux_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret; - GstAviDemux *avi = GST_AVI_DEMUX (element); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - avi->streaming = FALSE; - gst_segment_init (&avi->segment, GST_FORMAT_TIME); - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - goto done; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_avi_demux_reset (avi); - break; - default: - break; - } - -done: - return ret; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/avi/gstavidemux.h --- a/gst_plugins_good/gst/avi/gstavidemux.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2006> Nokia Corporation (contact ) - * - * 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. - */ - -#ifndef __GST_AVI_DEMUX_H__ -#define __GST_AVI_DEMUX_H__ - -#include - -#include "avi-ids.h" -#include "gst/riff/riff-ids.h" -#include "gst/riff/riff-read.h" -#include - -G_BEGIN_DECLS - -#define GST_TYPE_AVI_DEMUX \ - (gst_avi_demux_get_type ()) -#define GST_AVI_DEMUX(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AVI_DEMUX, GstAviDemux)) -#define GST_AVI_DEMUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AVI_DEMUX, GstAviDemuxClass)) -#define GST_IS_AVI_DEMUX(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AVI_DEMUX)) -#define GST_IS_AVI_DEMUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AVI_DEMUX)) - -#define GST_AVI_DEMUX_MAX_STREAMS 16 - -#define CHUNKID_TO_STREAMNR(chunkid) \ - ((((chunkid) & 0xff) - '0') * 10 + \ - (((chunkid) >> 8) & 0xff) - '0') - -#define GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME 1 - -/* 48 bytes */ -typedef struct { - guint index_nr; /* = (entry-index_entries)/sizeof(gst_avi_index_entry); */ - guchar stream_nr; - guchar flags; - guint64 ts; - guint64 dur; /* =entry[1].ts-entry->ts */ - guint64 offset; - guint64 bytes_before; /* calculated */ - guint32 frames_before; /* calculated */ - guint32 size; /* could be read from the chunk (if we don't split) */ -} gst_avi_index_entry; - -typedef struct { - /* index of this streamcontext */ - guint num; - - /* pad*/ - GstPad *pad; - - /* stream info and headers */ - gst_riff_strh *strh; - union { - gst_riff_strf_vids *vids; - gst_riff_strf_auds *auds; - gst_riff_strf_iavs *iavs; - gpointer data; - } strf; - GstBuffer *extradata, *initdata; - gchar *name; - - /* current position (byte, frame, time) and other status vars */ - guint current_frame; - guint64 current_byte; - GstFlowReturn last_flow; - gboolean discont; - - /* stream length */ - guint64 total_bytes; - guint32 total_frames; - guint32 total_blocks; - /* stream length according to index */ - GstClockTime idx_duration; - /* stream length according to header */ - GstClockTime hdr_duration; - /* stream length based on header/index */ - GstClockTime duration; - - /* VBR indicator */ - gboolean is_vbr; - - /* openDML support (for files >4GB) */ - gboolean superindex; - guint64 *indexes; - - GstTagList *taglist; -} avi_stream_context; - -typedef enum { - GST_AVI_DEMUX_START, - GST_AVI_DEMUX_HEADER, - GST_AVI_DEMUX_MOVI, -} GstAviDemuxState; - -typedef enum { - GST_AVI_DEMUX_HEADER_TAG_LIST, - GST_AVI_DEMUX_HEADER_AVIH, - GST_AVI_DEMUX_HEADER_ELEMENTS, - GST_AVI_DEMUX_HEADER_INFO, - GST_AVI_DEMUX_HEADER_JUNK, - GST_AVI_DEMUX_HEADER_DATA -} GstAviDemuxHeaderState; - -typedef struct _GstAviDemux { - GstElement parent; - - /* pads */ - GstPad *sinkpad; - - /* AVI decoding state */ - GstAviDemuxState state; - GstAviDemuxHeaderState header_state; - guint64 offset; - - /* index */ - gst_avi_index_entry *index_entries; - guint index_size; - guint64 index_offset; - guint current_entry; - guint reverse_start_index; - guint reverse_stop_index; - - /* streams */ - guint num_streams; - guint num_v_streams; - guint num_a_streams; - guint num_t_streams; /* subtitle text streams */ - - avi_stream_context stream[GST_AVI_DEMUX_MAX_STREAMS]; - - /* for streaming mode */ - gboolean streaming; - gboolean have_eos; - GstAdapter *adapter; - - /* some stream info for length */ - gst_riff_avih *avih; - - /* segment in TIME */ - GstSegment segment; - gboolean segment_running; - - /* pending tags/events */ - GstEvent *seek_event; - GstTagList *globaltags; - gboolean got_tags; - -} GstAviDemux; - -typedef struct _GstAviDemuxClass { - GstElementClass parent_class; -} GstAviDemuxClass; - -GType gst_avi_demux_get_type (void); - -G_END_DECLS - -#endif /* __GST_AVI_DEMUX_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/avi/gstavimux.c --- a/gst_plugins_good/gst/avi/gstavimux.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1982 +0,0 @@ -/* AVI muxer plugin for GStreamer - * Copyright (C) 2002 Ronald Bultje - * (C) 2006 Mark Nauwelaerts - * - * 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. - */ - -/* based on: - * - the old avimuxer (by Wim Taymans) - * - xawtv's aviwriter (by Gerd Knorr) - * - mjpegtools' avilib (by Rainer Johanni) - * - openDML large-AVI docs - */ - -/** - * SECTION:element-avimux - * - * Muxes raw or compressed audio and/or video streams into an AVI file. - * - * - * Example launch lines - * (write everything in one line, without the backslash characters) - * |[ - * gst-launch videotestsrc num-buffers=250 \ - * ! 'video/x-raw-yuv,format=(fourcc)I420,width=320,height=240,framerate=(fraction)25/1' \ - * ! queue ! mux. \ - * audiotestsrc num-buffers=440 ! audioconvert \ - * ! 'audio/x-raw-int,rate=44100,channels=2' ! queue ! mux. \ - * avimux name=mux ! filesink location=test.avi - * ]| This will create an .AVI file containing an uncompressed video stream - * with a test picture and an uncompressed audio stream containing a - * test sound. - * |[ - * gst-launch videotestsrc num-buffers=250 \ - * ! 'video/x-raw-yuv,format=(fourcc)I420,width=320,height=240,framerate=(fraction)25/1' \ - * ! xvidenc ! queue ! mux. \ - * audiotestsrc num-buffers=440 ! audioconvert ! 'audio/x-raw-int,rate=44100,channels=2' \ - * ! lame ! queue ! mux. \ - * avimux name=mux ! filesink location=test.avi - * ]| This will create an .AVI file containing the same test video and sound - * as above, only that both streams will be compressed this time. This will - * only work if you have the necessary encoder elements installed of course. - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gst/gst-i18n-plugin.h" -#include -#include - -#include - -#include "gstavimux.h" - -GST_DEBUG_CATEGORY_STATIC (avimux_debug); -#define GST_CAT_DEFAULT avimux_debug - -enum -{ - ARG_0, - ARG_BIGFILE -}; - -#define DEFAULT_BIGFILE TRUE - -static const GstElementDetails gst_avi_mux_details = -GST_ELEMENT_DETAILS ("Avi muxer", - "Codec/Muxer", - "Muxes audio and video into an avi stream", - "Ronald Bultje "); - -static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-msvideo") - ); - -static GstStaticPadTemplate video_sink_factory = - GST_STATIC_PAD_TEMPLATE ("video_%d", - GST_PAD_SINK, - GST_PAD_REQUEST, - GST_STATIC_CAPS ("video/x-raw-yuv, " - "format = (fourcc) { YUY2, I420 }, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " - "framerate = (fraction) [ 0, MAX ]; " - "image/jpeg, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " - "framerate = (fraction) [ 0, MAX ]; " - "video/x-divx, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " - "framerate = (fraction) [ 0, MAX ], " - "divxversion = (int) [ 3, 5 ]; " - "video/x-xvid, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " - "framerate = (fraction) [ 0, MAX ]; " - "video/x-3ivx, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " - "framerate = (fraction) [ 0, MAX ]; " - "video/x-msmpeg, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " - "framerate = (fraction) [ 0, MAX ], " - "msmpegversion = (int) [ 41, 43 ]; " - "video/mpeg, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " - "framerate = (fraction) [ 0, MAX ], " - "mpegversion = (int) { 1, 2, 4}, " - "systemstream = (boolean) FALSE; " - "video/x-h263, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " - "framerate = (fraction) [ 0, MAX ]; " - "video/x-h264, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " - "framerate = (fraction) [ 0, MAX ]; " - "video/x-dv, " - "width = (int) 720, " - "height = (int) { 576, 480 }, " - "framerate = (fraction) [ 0, MAX ], " - "systemstream = (boolean) FALSE; " - "video/x-huffyuv, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0, MAX ];" - "video/x-dirac, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0, MAX ];" - "video/x-wmv, " - "width = (int) [ 16, 4096 ], " - "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0, MAX ], " - "wmvversion = (int) [ 1, 3]") - ); - -static GstStaticPadTemplate audio_sink_factory = - GST_STATIC_PAD_TEMPLATE ("audio_%d", - GST_PAD_SINK, - GST_PAD_REQUEST, - GST_STATIC_CAPS ("audio/x-raw-int, " - "endianness = (int) LITTLE_ENDIAN, " - "signed = (boolean) { TRUE, FALSE }, " - "width = (int) { 8, 16 }, " - "depth = (int) { 8, 16 }, " - "rate = (int) [ 1000, 96000 ], " - "channels = (int) [ 1, 2 ]; " - "audio/mpeg, " - "mpegversion = (int) 1, " - "layer = (int) [ 1, 3 ], " - "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]; " - "audio/mpeg, " - "mpegversion = (int) 4, " - "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]; " -/*#if 0 VC6 doesn't support #if here ... - "audio/x-vorbis, " - "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]; " -#endif*/ - "audio/x-ac3, " - "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]; " - "audio/x-alaw, " - "rate = (int) [ 1000, 48000 ], " "channels = (int) [ 1, 2 ]; " - "audio/x-mulaw, " - "rate = (int) [ 1000, 48000 ], " "channels = (int) [ 1, 2 ]; " - "audio/x-wma, " - "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ], " - "wmaversion = (int) [ 1, 2 ] ") - ); - -static void gst_avi_mux_base_init (gpointer g_class); -static void gst_avi_mux_class_init (GstAviMuxClass * klass); -static void gst_avi_mux_init (GstAviMux * avimux); -static void gst_avi_mux_pad_reset (GstAviPad * avipad, gboolean free); - -static GstFlowReturn gst_avi_mux_collect_pads (GstCollectPads * pads, - GstAviMux * avimux); -static gboolean gst_avi_mux_handle_event (GstPad * pad, GstEvent * event); -static GstPad *gst_avi_mux_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * name); -static void gst_avi_mux_release_pad (GstElement * element, GstPad * pad); -static void gst_avi_mux_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_avi_mux_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); -static GstStateChangeReturn gst_avi_mux_change_state (GstElement * element, - GstStateChange transition); - -static GstElementClass *parent_class = NULL; - -GType -gst_avi_mux_get_type (void) -{ - static GType avimux_type = 0; - - if (!avimux_type) { - static const GTypeInfo avimux_info = { - sizeof (GstAviMuxClass), - gst_avi_mux_base_init, - NULL, - (GClassInitFunc) gst_avi_mux_class_init, - NULL, - NULL, - sizeof (GstAviMux), - 0, - (GInstanceInitFunc) gst_avi_mux_init, - }; - static const GInterfaceInfo tag_setter_info = { - NULL, - NULL, - NULL - }; - - avimux_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstAviMux", &avimux_info, 0); - g_type_add_interface_static (avimux_type, GST_TYPE_TAG_SETTER, - &tag_setter_info); - } - return avimux_type; -} - -static void -gst_avi_mux_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&audio_sink_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&video_sink_factory)); - - gst_element_class_set_details (element_class, &gst_avi_mux_details); - - GST_DEBUG_CATEGORY_INIT (avimux_debug, "avimux", 0, "Muxer for AVI streams"); -} - -static void -gst_avi_mux_finalize (GObject * object) -{ - GstAviMux *mux = GST_AVI_MUX (object); - GSList *node; - - /* completely free each sinkpad */ - node = mux->sinkpads; - while (node) { - GstAviPad *avipad = (GstAviPad *) node->data; - - node = node->next; - - gst_avi_mux_pad_reset (avipad, TRUE); - g_free (avipad); - } - g_slist_free (mux->sinkpads); - mux->sinkpads = NULL; - - g_free (mux->idx); - mux->idx = NULL; - - gst_object_unref (mux->collect); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_avi_mux_class_init (GstAviMuxClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->get_property = gst_avi_mux_get_property; - gobject_class->set_property = gst_avi_mux_set_property; - gobject_class->finalize = gst_avi_mux_finalize; - - g_object_class_install_property (gobject_class, ARG_BIGFILE, - g_param_spec_boolean ("bigfile", "Bigfile Support (>2GB)", - "Support for openDML-2.0 (big) AVI files", DEFAULT_BIGFILE, - G_PARAM_READWRITE)); - - gstelement_class->request_new_pad = - GST_DEBUG_FUNCPTR (gst_avi_mux_request_new_pad); - gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_avi_mux_release_pad); - gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_avi_mux_change_state); -} - -/* reset pad to initial state - * free - if true, release all, not only stream related, data */ -static void -gst_avi_mux_pad_reset (GstAviPad * avipad, gboolean free) -{ - /* generic part */ - memset (&(avipad->hdr), 0, sizeof (gst_riff_strh)); - - memset (&(avipad->idx[0]), 0, sizeof (avipad->idx)); - - if (free) { - g_free (avipad->tag); - avipad->tag = NULL; - g_free (avipad->idx_tag); - avipad->idx_tag = NULL; - } - - if (avipad->is_video) { - GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad; - - avipad->hdr.type = GST_MAKE_FOURCC ('v', 'i', 'd', 's'); - if (vidpad->vids_codec_data) { - gst_buffer_unref (vidpad->vids_codec_data); - vidpad->vids_codec_data = NULL; - } - - memset (&(vidpad->vids), 0, sizeof (gst_riff_strf_vids)); - memset (&(vidpad->vprp), 0, sizeof (gst_riff_vprp)); - } else { - GstAviAudioPad *audpad = (GstAviAudioPad *) avipad; - - avipad->hdr.type = GST_MAKE_FOURCC ('a', 'u', 'd', 's'); - if (audpad->auds_codec_data) { - gst_buffer_unref (audpad->auds_codec_data); - audpad->auds_codec_data = NULL; - } - - memset (&(audpad->auds), 0, sizeof (gst_riff_strf_auds)); - } -} - -static void -gst_avi_mux_reset (GstAviMux * avimux) -{ - GSList *node, *newlist = NULL; - - /* free and reset each sinkpad */ - node = avimux->sinkpads; - while (node) { - GstAviPad *avipad = (GstAviPad *) node->data; - - node = node->next; - - gst_avi_mux_pad_reset (avipad, FALSE); - /* if this pad has collectdata, keep it, otherwise dump it completely */ - if (avipad->collect) - newlist = g_slist_append (newlist, avipad); - else { - gst_avi_mux_pad_reset (avipad, TRUE); - g_free (avipad); - } - } - - /* free the old list of sinkpads, only keep the real collecting ones */ - g_slist_free (avimux->sinkpads); - avimux->sinkpads = newlist; - - /* avi data */ - avimux->num_frames = 0; - memset (&(avimux->avi_hdr), 0, sizeof (gst_riff_avih)); - avimux->avi_hdr.max_bps = 10000000; - avimux->codec_data_size = 0; - - if (avimux->tags_snap) { - gst_tag_list_free (avimux->tags_snap); - avimux->tags_snap = NULL; - } - - g_free (avimux->idx); - avimux->idx = NULL; - - /* state info */ - avimux->write_header = TRUE; - - /* tags */ - gst_tag_setter_reset_tags (GST_TAG_SETTER (avimux)); -} - -static void -gst_avi_mux_init (GstAviMux * avimux) -{ - avimux->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); - gst_pad_use_fixed_caps (avimux->srcpad); - gst_element_add_pad (GST_ELEMENT (avimux), avimux->srcpad); - - /* property */ - avimux->enable_large_avi = DEFAULT_BIGFILE; - - avimux->collect = gst_collect_pads_new (); - gst_collect_pads_set_function (avimux->collect, - (GstCollectPadsFunction) (GST_DEBUG_FUNCPTR (gst_avi_mux_collect_pads)), - avimux); - - /* set to clean state */ - gst_avi_mux_reset (avimux); -} - -static gboolean -gst_avi_mux_vidsink_set_caps (GstPad * pad, GstCaps * vscaps) -{ - GstAviMux *avimux; - GstAviVideoPad *avipad; - GstAviCollectData *collect_pad; - GstStructure *structure; - const gchar *mimetype; - const GValue *fps, *par; - const GValue *codec_data; - gint width, height; - gint par_n, par_d; - - avimux = GST_AVI_MUX (gst_pad_get_parent (pad)); - - /* find stream data */ - collect_pad = (GstAviCollectData *) gst_pad_get_element_private (pad); - g_assert (collect_pad); - avipad = (GstAviVideoPad *) collect_pad->avipad; - g_assert (avipad); - g_assert (avipad->parent.is_video); - g_assert (avipad->parent.hdr.type == GST_MAKE_FOURCC ('v', 'i', 'd', 's')); - - GST_DEBUG_OBJECT (avimux, "%s:%s, caps=%" GST_PTR_FORMAT, - GST_DEBUG_PAD_NAME (pad), vscaps); - - structure = gst_caps_get_structure (vscaps, 0); - mimetype = gst_structure_get_name (structure); - - /* global */ - avipad->vids.size = sizeof (gst_riff_strf_vids); - avipad->vids.planes = 1; - if (!gst_structure_get_int (structure, "width", &width) || - !gst_structure_get_int (structure, "height", &height)) { - goto refuse_caps; - } - - avipad->vids.width = width; - avipad->vids.height = height; - - fps = gst_structure_get_value (structure, "framerate"); - if (fps == NULL || !GST_VALUE_HOLDS_FRACTION (fps)) - goto refuse_caps; - - avipad->parent.hdr.rate = gst_value_get_fraction_numerator (fps); - avipad->parent.hdr.scale = gst_value_get_fraction_denominator (fps); - - /* (pixel) aspect ratio data, if any */ - par = gst_structure_get_value (structure, "pixel-aspect-ratio"); - /* only use video properties header if there is non-trivial aspect info */ - if (par && GST_VALUE_HOLDS_FRACTION (par) && - ((par_n = gst_value_get_fraction_numerator (par)) != - (par_d = gst_value_get_fraction_denominator (par)))) { - GValue to_ratio = { 0, }; - guint ratio_n, ratio_d; - - /* some fraction voodoo to obtain simplest possible ratio */ - g_value_init (&to_ratio, GST_TYPE_FRACTION); - gst_value_set_fraction (&to_ratio, width * par_n, height * par_d); - ratio_n = gst_value_get_fraction_numerator (&to_ratio); - ratio_d = gst_value_get_fraction_denominator (&to_ratio); - GST_DEBUG_OBJECT (avimux, "generating vprp data with aspect ratio %d/%d", - ratio_n, ratio_d); - /* simply fill in */ - avipad->vprp.vert_rate = avipad->parent.hdr.rate / avipad->parent.hdr.scale; - avipad->vprp.hor_t_total = width; - avipad->vprp.vert_lines = height; - avipad->vprp.aspect = (ratio_n) << 16 | (ratio_d & 0xffff); - avipad->vprp.width = width; - avipad->vprp.height = height; - avipad->vprp.fields = 1; - avipad->vprp.field_info[0].compressed_bm_height = height; - avipad->vprp.field_info[0].compressed_bm_width = width; - avipad->vprp.field_info[0].valid_bm_height = height; - avipad->vprp.field_info[0].valid_bm_width = width; - } - - /* codec initialization data, if any */ - codec_data = gst_structure_get_value (structure, "codec_data"); - if (codec_data) { - avipad->vids_codec_data = gst_value_get_buffer (codec_data); - gst_buffer_ref (avipad->vids_codec_data); - /* keep global track of size */ - avimux->codec_data_size += GST_BUFFER_SIZE (avipad->vids_codec_data); - } - - if (!strcmp (mimetype, "video/x-raw-yuv")) { - guint32 format; - - gst_structure_get_fourcc (structure, "format", &format); - avipad->vids.compression = format; - switch (format) { - case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): - avipad->vids.bit_cnt = 16; - break; - case GST_MAKE_FOURCC ('I', '4', '2', '0'): - avipad->vids.bit_cnt = 12; - break; - } - } else { - avipad->vids.bit_cnt = 24; - avipad->vids.compression = 0; - - /* find format */ - if (!strcmp (mimetype, "video/x-huffyuv")) { - avipad->vids.compression = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U'); - } else if (!strcmp (mimetype, "image/jpeg")) { - avipad->vids.compression = GST_MAKE_FOURCC ('M', 'J', 'P', 'G'); - } else if (!strcmp (mimetype, "video/x-divx")) { - gint divxversion; - - gst_structure_get_int (structure, "divxversion", &divxversion); - switch (divxversion) { - case 3: - avipad->vids.compression = GST_MAKE_FOURCC ('D', 'I', 'V', '3'); - break; - case 4: - avipad->vids.compression = GST_MAKE_FOURCC ('D', 'I', 'V', 'X'); - break; - case 5: - avipad->vids.compression = GST_MAKE_FOURCC ('D', 'X', '5', '0'); - break; - } - } else if (!strcmp (mimetype, "video/x-xvid")) { - avipad->vids.compression = GST_MAKE_FOURCC ('X', 'V', 'I', 'D'); - } else if (!strcmp (mimetype, "video/x-3ivx")) { - avipad->vids.compression = GST_MAKE_FOURCC ('3', 'I', 'V', '2'); - } else if (gst_structure_has_name (structure, "video/x-msmpeg")) { - gint msmpegversion; - - gst_structure_get_int (structure, "msmpegversion", &msmpegversion); - switch (msmpegversion) { - case 41: - avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', 'G', '4'); - break; - case 42: - avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', '4', '2'); - break; - case 43: - avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', '4', '3'); - break; - default: - GST_INFO ("unhandled msmpegversion : %d, fall back to fourcc=MPEG", - msmpegversion); - avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', 'E', 'G'); - break; - } - } else if (!strcmp (mimetype, "video/x-dv")) { - avipad->vids.compression = GST_MAKE_FOURCC ('D', 'V', 'S', 'D'); - } else if (!strcmp (mimetype, "video/x-h263")) { - avipad->vids.compression = GST_MAKE_FOURCC ('H', '2', '6', '3'); - } else if (!strcmp (mimetype, "video/x-h264")) { - avipad->vids.compression = GST_MAKE_FOURCC ('H', '2', '6', '4'); - } else if (!strcmp (mimetype, "video/mpeg")) { - gint mpegversion; - - gst_structure_get_int (structure, "mpegversion", &mpegversion); - - switch (mpegversion) { - case 2: - avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', 'G', '2'); - break; - case 4: - /* mplayer/ffmpeg might not work with DIVX, but with FMP4 */ - avipad->vids.compression = GST_MAKE_FOURCC ('D', 'I', 'V', 'X'); - break; - default: - GST_INFO ("unhandled mpegversion : %d, fall back to fourcc=MPEG", - mpegversion); - avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', 'E', 'G'); - break; - } - } else if (!strcmp (mimetype, "video/x-dirac")) { - avipad->vids.compression = GST_MAKE_FOURCC ('d', 'r', 'a', 'c'); - } else if (!strcmp (mimetype, "video/x-wmv")) { - gint wmvversion; - - if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) { - switch (wmvversion) { - case 1: - avipad->vids.compression = GST_MAKE_FOURCC ('W', 'M', 'V', '1'); - break; - case 2: - avipad->vids.compression = GST_MAKE_FOURCC ('W', 'M', 'V', '2'); - break; - case 3: - avipad->vids.compression = GST_MAKE_FOURCC ('W', 'M', 'V', '3'); - default: - break; - } - } - } - - if (!avipad->vids.compression) - goto refuse_caps; - } - - avipad->parent.hdr.fcc_handler = avipad->vids.compression; - avipad->vids.image_size = avipad->vids.height * avipad->vids.width; - /* hm, maybe why avi only handles one stream well ... */ - avimux->avi_hdr.width = avipad->vids.width; - avimux->avi_hdr.height = avipad->vids.height; - avimux->avi_hdr.us_frame = 1000000. * avipad->parent.hdr.scale / - avipad->parent.hdr.rate; - - gst_object_unref (avimux); - return TRUE; - -refuse_caps: - { - GST_WARNING_OBJECT (avimux, "refused caps %" GST_PTR_FORMAT, vscaps); - gst_object_unref (avimux); - return FALSE; - } -} - -static gboolean -gst_avi_mux_audsink_set_caps (GstPad * pad, GstCaps * vscaps) -{ - GstAviMux *avimux; - GstAviAudioPad *avipad; - GstAviCollectData *collect_pad; - GstStructure *structure; - const gchar *mimetype; - const GValue *codec_data; - gint channels, rate; - - avimux = GST_AVI_MUX (gst_pad_get_parent (pad)); - - /* find stream data */ - collect_pad = (GstAviCollectData *) gst_pad_get_element_private (pad); - g_assert (collect_pad); - avipad = (GstAviAudioPad *) collect_pad->avipad; - g_assert (avipad); - g_assert (!avipad->parent.is_video); - g_assert (avipad->parent.hdr.type == GST_MAKE_FOURCC ('a', 'u', 'd', 's')); - - GST_DEBUG_OBJECT (avimux, "%s:%s, caps=%" GST_PTR_FORMAT, - GST_DEBUG_PAD_NAME (pad), vscaps); - - structure = gst_caps_get_structure (vscaps, 0); - mimetype = gst_structure_get_name (structure); - - /* we want these for all */ - if (!gst_structure_get_int (structure, "channels", &channels) || - !gst_structure_get_int (structure, "rate", &rate)) { - goto refuse_caps; - } - - avipad->auds.channels = channels; - avipad->auds.rate = rate; - - /* codec initialization data, if any */ - codec_data = gst_structure_get_value (structure, "codec_data"); - if (codec_data) { - avipad->auds_codec_data = gst_value_get_buffer (codec_data); - gst_buffer_ref (avipad->auds_codec_data); - /* keep global track of size */ - avimux->codec_data_size += GST_BUFFER_SIZE (avipad->auds_codec_data); - } - - if (!strcmp (mimetype, "audio/x-raw-int")) { - gint width, depth; - gboolean signedness; - - avipad->auds.format = GST_RIFF_WAVE_FORMAT_PCM; - - if (!gst_structure_get_int (structure, "width", &width) || - !gst_structure_get_int (structure, "depth", &depth) || - !gst_structure_get_boolean (structure, "signed", &signedness)) { - GST_DEBUG_OBJECT (avimux, - "broken caps, width/depth/signed field missing"); - goto refuse_caps; - } - - /* no clear place to put different values for these while keeping to spec */ - if (width != depth) { - GST_DEBUG_OBJECT (avimux, "width must be same as depth!"); - goto refuse_caps; - } - - /* because that's the way the caps will be recreated from riff data */ - if ((width == 8 && signedness) || (width == 16 && !signedness)) { - GST_DEBUG_OBJECT (avimux, - "8-bit PCM must be unsigned, 16-bit PCM signed"); - goto refuse_caps; - } - - avipad->auds.blockalign = width; - avipad->auds.size = (width == 8) ? 8 : depth; - - /* set some more info straight */ - avipad->auds.blockalign /= 8; - avipad->auds.blockalign *= avipad->auds.channels; - avipad->auds.av_bps = avipad->auds.blockalign * avipad->auds.rate; - } else { - avipad->auds.format = 0; - /* set some defaults */ - avipad->auds.blockalign = 1; - avipad->auds.av_bps = 0; - avipad->auds.size = 16; - - if (!strcmp (mimetype, "audio/mpeg")) { - gint mpegversion; - - gst_structure_get_int (structure, "mpegversion", &mpegversion); - switch (mpegversion) { - case 1:{ - gint layer = 3; - - gst_structure_get_int (structure, "layer", &layer); - switch (layer) { - case 3: - avipad->auds.format = GST_RIFF_WAVE_FORMAT_MPEGL3; - break; - case 1: - case 2: - avipad->auds.format = GST_RIFF_WAVE_FORMAT_MPEGL12; - break; - } - break; - } - case 4: - GST_WARNING ("AAC"); - avipad->auds.format = GST_RIFF_WAVE_FORMAT_AAC; - break; - } - } else if (!strcmp (mimetype, "audio/x-vorbis")) { - avipad->auds.format = GST_RIFF_WAVE_FORMAT_VORBIS3; - } else if (!strcmp (mimetype, "audio/x-ac3")) { - avipad->auds.format = GST_RIFF_WAVE_FORMAT_A52; - } else if (!strcmp (mimetype, "audio/x-alaw")) { - avipad->auds.format = GST_RIFF_WAVE_FORMAT_ALAW; - avipad->auds.size = 8; - avipad->auds.blockalign = avipad->auds.channels; - avipad->auds.av_bps = avipad->auds.blockalign * avipad->auds.rate; - } else if (!strcmp (mimetype, "audio/x-mulaw")) { - avipad->auds.format = GST_RIFF_WAVE_FORMAT_MULAW; - avipad->auds.size = 8; - avipad->auds.blockalign = avipad->auds.channels; - avipad->auds.av_bps = avipad->auds.blockalign * avipad->auds.rate; - } else if (!strcmp (mimetype, "audio/x-wma")) { - gint version; - gint bitrate; - gint block_align; - - if (gst_structure_get_int (structure, "wmaversion", &version)) { - switch (version) { - case 1: - avipad->auds.format = GST_RIFF_WAVE_FORMAT_WMAV1; - break; - case 2: - avipad->auds.format = GST_RIFF_WAVE_FORMAT_WMAV2; - break; - default: - break; - } - } - - if (avipad->auds.format != 0) { - if (gst_structure_get_int (structure, "block_align", &block_align)) { - avipad->auds.blockalign = block_align; - } - if (gst_structure_get_int (structure, "bitrate", &bitrate)) { - avipad->auds.av_bps = bitrate / 8; - } - } - } - } - - if (!avipad->auds.format) - goto refuse_caps; - - /* by spec, hdr.rate is av_bps related, is calculated that way in stop_file, - * and reduces to sample rate in PCM like cases */ - avipad->parent.hdr.rate = avipad->auds.av_bps / avipad->auds.blockalign; - avipad->parent.hdr.samplesize = avipad->auds.blockalign; - avipad->parent.hdr.scale = 1; - - gst_object_unref (avimux); - return TRUE; - -refuse_caps: - { - GST_WARNING_OBJECT (avimux, "refused caps %" GST_PTR_FORMAT, vscaps); - gst_object_unref (avimux); - return FALSE; - } -} - - -static GstPad * -gst_avi_mux_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * req_name) -{ - GstAviMux *avimux; - GstPad *newpad; - GstAviPad *avipad; - GstElementClass *klass; - - g_return_val_if_fail (templ != NULL, NULL); - - if (templ->direction != GST_PAD_SINK) - goto wrong_direction; - - g_return_val_if_fail (GST_IS_AVI_MUX (element), NULL); - avimux = GST_AVI_MUX (element); - - if (!avimux->write_header) - goto too_late; - - klass = GST_ELEMENT_GET_CLASS (element); - - if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) { - gchar *name; - - /* setup pad */ - name = g_strdup_printf ("audio_%02d", avimux->audio_pads); - GST_DEBUG_OBJECT (avimux, "adding new pad: %s", name); - newpad = gst_pad_new_from_template (templ, name); - g_free (name); - gst_pad_set_setcaps_function (newpad, - GST_DEBUG_FUNCPTR (gst_avi_mux_audsink_set_caps)); - - /* init pad specific data */ - avipad = g_malloc0 (sizeof (GstAviAudioPad)); - avipad->is_video = FALSE; - avipad->hdr.type = GST_MAKE_FOURCC ('a', 'u', 'd', 's'); - avimux->audio_pads++; - /* audio goes last */ - avimux->sinkpads = g_slist_append (avimux->sinkpads, avipad); - } else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) { - /* though streams are pretty generic and relatively self-contained, - * some video info goes in a single avi header -and therefore mux struct- - * so video restricted to one stream */ - if (avimux->video_pads > 0) - return NULL; - /* setup pad */ - GST_DEBUG_OBJECT (avimux, "adding new pad: video_00"); - newpad = gst_pad_new_from_template (templ, "video_00"); - gst_pad_set_setcaps_function (newpad, - GST_DEBUG_FUNCPTR (gst_avi_mux_vidsink_set_caps)); - avipad = g_malloc0 (sizeof (GstAviVideoPad)); - - /* init pad specific data */ - avipad->is_video = TRUE; - avipad->hdr.type = GST_MAKE_FOURCC ('v', 'i', 'd', 's'); - avimux->video_pads++; - /* video goes first */ - avimux->sinkpads = g_slist_prepend (avimux->sinkpads, avipad); - } else - goto wrong_template; - - avipad->collect = gst_collect_pads_add_pad (avimux->collect, - newpad, sizeof (GstAviCollectData)); - ((GstAviCollectData *) (avipad->collect))->avipad = avipad; - /* FIXME: hacked way to override/extend the event function of - * GstCollectPads; because it sets its own event function giving the - * element no access to events */ - avimux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad); - gst_pad_set_event_function (newpad, - GST_DEBUG_FUNCPTR (gst_avi_mux_handle_event)); - - gst_element_add_pad (element, newpad); - - return newpad; - - /* ERRORS */ -wrong_direction: - { - g_warning ("avimux: request pad that is not a SINK pad\n"); - return NULL; - } -too_late: - { - g_warning ("avimux: request pad cannot be added after streaming started\n"); - return NULL; - } -wrong_template: - { - g_warning ("avimuxx: this is not our template!\n"); - return NULL; - } -} - -static void -gst_avi_mux_release_pad (GstElement * element, GstPad * pad) -{ - GstAviMux *avimux = GST_AVI_MUX (element); - GSList *node; - - node = avimux->sinkpads; - while (node) { - GstAviPad *avipad = (GstAviPad *) node->data; - - if (avipad->collect->pad == pad) { - /* pad count should not be adjusted, - * as it also represent number of streams present */ - avipad->collect = NULL; - GST_DEBUG_OBJECT (avimux, "removed pad '%s'", GST_PAD_NAME (pad)); - gst_collect_pads_remove_pad (avimux->collect, pad); - gst_element_remove_pad (element, pad); - /* if not started yet, we can remove any sign this pad ever existed */ - /* in this case _start will take care of the real pad count */ - if (avimux->write_header) { - avimux->sinkpads = g_slist_remove (avimux->sinkpads, avipad); - gst_avi_mux_pad_reset (avipad, TRUE); - g_free (avipad); - } - return; - } - - node = node->next; - } - - g_warning ("Unknown pad %s", GST_PAD_NAME (pad)); -} - -/* maybe some of these functions should be moved to riff.h? */ - -/* DISCLAIMER: this function is fairly ugly. So be it (i.e. it makes the rest easier) - * so is this struct */ - -typedef struct _GstMarkedBuffer -{ - guint *highmark; - GstBuffer *buffer; -} GstMarkedBuffer; - -static void -gst_avi_mux_write_tag (const GstTagList * list, const gchar * tag, - gpointer data) -{ - const struct - { - guint32 fcc; - gchar *tag; - } rifftags[] = { - { - GST_RIFF_INFO_IARL, GST_TAG_LOCATION}, { - GST_RIFF_INFO_IART, GST_TAG_ARTIST}, { - GST_RIFF_INFO_ICMT, GST_TAG_COMMENT}, { - GST_RIFF_INFO_ICOP, GST_TAG_COPYRIGHT}, { - GST_RIFF_INFO_ICRD, GST_TAG_DATE}, { - GST_RIFF_INFO_IGNR, GST_TAG_GENRE}, { - GST_RIFF_INFO_IKEY, GST_TAG_KEYWORDS}, { - GST_RIFF_INFO_INAM, GST_TAG_TITLE}, { - GST_RIFF_INFO_ISFT, GST_TAG_ENCODER}, { - GST_RIFF_INFO_ISRC, GST_TAG_ISRC}, { - 0, NULL} - }; - gint n, len, plen; - GstBuffer *buf = ((GstMarkedBuffer *) data)->buffer; - guint *highmark = ((GstMarkedBuffer *) data)->highmark; - guint8 *buffdata = GST_BUFFER_DATA (buf) + *highmark; - gchar *str; - - for (n = 0; rifftags[n].fcc != 0; n++) { - if (!strcmp (rifftags[n].tag, tag) && - gst_tag_list_get_string (list, tag, &str) && str) { - len = strlen (str); - plen = len + 1; - if (plen & 1) - plen++; - if (GST_BUFFER_SIZE (buf) >= *highmark + 8 + plen) { - GST_WRITE_UINT32_LE (buffdata, rifftags[n].fcc); - GST_WRITE_UINT32_LE (buffdata + 4, len + 1); - memcpy (buffdata + 8, str, len); - buffdata[8 + len] = 0; - *highmark += 8 + plen; - GST_DEBUG ("writing tag in buffer %p, highmark at %d", buf, *highmark); - } - g_free (str); - break; - } - } -} - -#define ODML_SUPERINDEX_SIZE \ - (32 + GST_AVI_SUPERINDEX_COUNT * sizeof (gst_avi_superindex_entry)) - -static GstBuffer * -gst_avi_mux_riff_get_avi_header (GstAviMux * avimux) -{ - const GstTagList *tags; - GstBuffer *buffer; - guint8 *buffdata; - guint size = 0; - guint highmark = 0; - - /* pointer to list size field */ - guint8 *riff_size, *hdrl_size; - GSList *node; - - GST_DEBUG_OBJECT (avimux, "creating avi header, data_size %u, idx_size %u", - avimux->data_size, avimux->idx_size); - - if (avimux->tags_snap) - tags = avimux->tags_snap; - else { - /* need to make snapshot of current state of tags to ensure the same set - * is used next time around during header rewrite at the end */ - tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (avimux)); - if (tags) - tags = avimux->tags_snap = gst_tag_list_copy (tags); - } - if (tags) { - /* that should be the strlen of all tags + header sizes - * not all of tags end up in a avi, still this is a good estimate - */ - gchar *str = gst_structure_to_string (tags); - size += strlen (str) + 8 * gst_structure_n_fields (tags); - g_free (str); - } - - /* allocate the buffer, starting with some wild/safe upper bound */ - size += avimux->codec_data_size + 100 + sizeof (gst_riff_avih) - + (g_slist_length (avimux->sinkpads) * (100 + sizeof (gst_riff_strh_full) - + sizeof (gst_riff_strf_vids) - + sizeof (gst_riff_vprp) - + sizeof (gst_riff_vprp_video_field_desc) * 2 - + sizeof (gst_riff_strf_auds) + 2 + ODML_SUPERINDEX_SIZE)); - buffer = gst_buffer_new_and_alloc (size); - buffdata = GST_BUFFER_DATA (buffer); - highmark = 0; - GST_DEBUG_OBJECT (avimux, "creating buffer %p, size %d, highmark at 0", - buffer, GST_BUFFER_SIZE (buffer)); - - /* avi header metadata */ - memcpy (buffdata + 0, "RIFF", 4); - /* fill in RIFF size later */ - riff_size = buffdata + 4; - memcpy (buffdata + 8, "AVI ", 4); - memcpy (buffdata + 12, "LIST", 4); - /* fill in header size later */ - hdrl_size = buffdata + 16; - memcpy (buffdata + 20, "hdrl", 4); - memcpy (buffdata + 24, "avih", 4); - GST_WRITE_UINT32_LE (buffdata + 28, sizeof (gst_riff_avih)); - buffdata += 32; - highmark += 32; - - /* the AVI header itself */ - GST_WRITE_UINT32_LE (buffdata + 0, avimux->avi_hdr.us_frame); - GST_WRITE_UINT32_LE (buffdata + 4, avimux->avi_hdr.max_bps); - GST_WRITE_UINT32_LE (buffdata + 8, avimux->avi_hdr.pad_gran); - GST_WRITE_UINT32_LE (buffdata + 12, avimux->avi_hdr.flags); - GST_WRITE_UINT32_LE (buffdata + 16, avimux->avi_hdr.tot_frames); - GST_WRITE_UINT32_LE (buffdata + 20, avimux->avi_hdr.init_frames); - GST_WRITE_UINT32_LE (buffdata + 24, avimux->avi_hdr.streams); - GST_WRITE_UINT32_LE (buffdata + 28, avimux->avi_hdr.bufsize); - GST_WRITE_UINT32_LE (buffdata + 32, avimux->avi_hdr.width); - GST_WRITE_UINT32_LE (buffdata + 36, avimux->avi_hdr.height); - GST_WRITE_UINT32_LE (buffdata + 40, avimux->avi_hdr.scale); - GST_WRITE_UINT32_LE (buffdata + 44, avimux->avi_hdr.rate); - GST_WRITE_UINT32_LE (buffdata + 48, avimux->avi_hdr.start); - GST_WRITE_UINT32_LE (buffdata + 52, avimux->avi_hdr.length); - buffdata += 56; - highmark += 56; - - /* stream data */ - node = avimux->sinkpads; - while (node) { - GstAviPad *avipad = (GstAviPad *) node->data; - GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad; - GstAviAudioPad *audpad = (GstAviAudioPad *) avipad; - guint codec_size = 0, strl_size = 0, vprp_size = 0; - - if (avipad->is_video) { - if (vidpad->vids_codec_data) - codec_size = GST_BUFFER_SIZE (vidpad->vids_codec_data); - strl_size = sizeof (gst_riff_strh_full) + sizeof (gst_riff_strf_vids) - + GST_ROUND_UP_2 (codec_size) + 4 * 5 + ODML_SUPERINDEX_SIZE; - if (vidpad->vprp.aspect) { - /* let's be on the safe side */ - vidpad->vprp.fields = MIN (vidpad->vprp.fields, - GST_RIFF_VPRP_VIDEO_FIELDS); - vprp_size = G_STRUCT_OFFSET (gst_riff_vprp, field_info) - + (vidpad->vprp.fields * sizeof (gst_riff_vprp_video_field_desc)); - strl_size += 4 * 2 + vprp_size; - } - } else { - if (audpad->auds_codec_data) - codec_size = GST_BUFFER_SIZE (audpad->auds_codec_data); - /* +2 is codec_size field, not part of gst_riff_strf_auds */ - strl_size = sizeof (gst_riff_strh_full) + sizeof (gst_riff_strf_auds) + 2 - + GST_ROUND_UP_2 (codec_size) + 4 * 5 + ODML_SUPERINDEX_SIZE; - } - - /* stream list metadata */ - memcpy (buffdata + 0, "LIST", 4); - GST_WRITE_UINT32_LE (buffdata + 4, strl_size); - memcpy (buffdata + 8, "strl", 4); - /* generic header */ - memcpy (buffdata + 12, "strh", 4); - GST_WRITE_UINT32_LE (buffdata + 16, sizeof (gst_riff_strh_full)); - /* the actual header */ - GST_WRITE_UINT32_LE (buffdata + 20, avipad->hdr.type); - GST_WRITE_UINT32_LE (buffdata + 24, avipad->hdr.fcc_handler); - GST_WRITE_UINT32_LE (buffdata + 28, avipad->hdr.flags); - GST_WRITE_UINT32_LE (buffdata + 32, avipad->hdr.priority); - GST_WRITE_UINT32_LE (buffdata + 36, avipad->hdr.init_frames); - GST_WRITE_UINT32_LE (buffdata + 40, avipad->hdr.scale); - GST_WRITE_UINT32_LE (buffdata + 44, avipad->hdr.rate); - GST_WRITE_UINT32_LE (buffdata + 48, avipad->hdr.start); - GST_WRITE_UINT32_LE (buffdata + 52, avipad->hdr.length); - GST_WRITE_UINT32_LE (buffdata + 56, avipad->hdr.bufsize); - GST_WRITE_UINT32_LE (buffdata + 60, avipad->hdr.quality); - GST_WRITE_UINT32_LE (buffdata + 64, avipad->hdr.samplesize); - GST_WRITE_UINT16_LE (buffdata + 68, 0); - GST_WRITE_UINT16_LE (buffdata + 70, 0); - GST_WRITE_UINT16_LE (buffdata + 72, 0); - GST_WRITE_UINT16_LE (buffdata + 74, 0); - buffdata += 76; - highmark += 76; - - if (avipad->is_video) { - /* the video header */ - memcpy (buffdata + 0, "strf", 4); - GST_WRITE_UINT32_LE (buffdata + 4, - sizeof (gst_riff_strf_vids) + codec_size); - /* the actual header */ - GST_WRITE_UINT32_LE (buffdata + 8, vidpad->vids.size + codec_size); - GST_WRITE_UINT32_LE (buffdata + 12, vidpad->vids.width); - GST_WRITE_UINT32_LE (buffdata + 16, vidpad->vids.height); - GST_WRITE_UINT16_LE (buffdata + 20, vidpad->vids.planes); - GST_WRITE_UINT16_LE (buffdata + 22, vidpad->vids.bit_cnt); - GST_WRITE_UINT32_LE (buffdata + 24, vidpad->vids.compression); - GST_WRITE_UINT32_LE (buffdata + 28, vidpad->vids.image_size); - GST_WRITE_UINT32_LE (buffdata + 32, vidpad->vids.xpels_meter); - GST_WRITE_UINT32_LE (buffdata + 36, vidpad->vids.ypels_meter); - GST_WRITE_UINT32_LE (buffdata + 40, vidpad->vids.num_colors); - GST_WRITE_UINT32_LE (buffdata + 44, vidpad->vids.imp_colors); - buffdata += 48; - highmark += 48; - - /* include codec data, if any */ - if (codec_size) { - memcpy (buffdata, GST_BUFFER_DATA (vidpad->vids_codec_data), - codec_size); - - buffdata += codec_size; - highmark += codec_size; - } - /* padding */ - if (highmark & 0x1) { - highmark++; - buffdata++; - } - - /* add video property data, mainly for aspect ratio, if any */ - if (vprp_size) { - gint f; - - /* the vprp header */ - memcpy (buffdata + 0, "vprp", 4); - GST_WRITE_UINT32_LE (buffdata + 4, vprp_size); - /* the actual data */ - GST_WRITE_UINT32_LE (buffdata + 8, vidpad->vprp.format_token); - GST_WRITE_UINT32_LE (buffdata + 12, vidpad->vprp.standard); - GST_WRITE_UINT32_LE (buffdata + 16, vidpad->vprp.vert_rate); - GST_WRITE_UINT32_LE (buffdata + 20, vidpad->vprp.hor_t_total); - GST_WRITE_UINT32_LE (buffdata + 24, vidpad->vprp.vert_lines); - GST_WRITE_UINT32_LE (buffdata + 28, vidpad->vprp.aspect); - GST_WRITE_UINT32_LE (buffdata + 32, vidpad->vprp.width); - GST_WRITE_UINT32_LE (buffdata + 36, vidpad->vprp.height); - GST_WRITE_UINT32_LE (buffdata + 40, vidpad->vprp.fields); - buffdata += 44; - highmark += 44; - for (f = 0; f < vidpad->vprp.fields; ++f) { - gst_riff_vprp_video_field_desc *fd; - - fd = &(vidpad->vprp.field_info[f]); - GST_WRITE_UINT32_LE (buffdata + 0, fd->compressed_bm_height); - GST_WRITE_UINT32_LE (buffdata + 4, fd->compressed_bm_width); - GST_WRITE_UINT32_LE (buffdata + 8, fd->valid_bm_height); - GST_WRITE_UINT32_LE (buffdata + 12, fd->valid_bm_width); - GST_WRITE_UINT32_LE (buffdata + 16, fd->valid_bm_x_offset); - GST_WRITE_UINT32_LE (buffdata + 20, fd->valid_bm_y_offset); - GST_WRITE_UINT32_LE (buffdata + 24, fd->video_x_t_offset); - GST_WRITE_UINT32_LE (buffdata + 28, fd->video_y_start); - buffdata += 32; - highmark += 32; - } - } - } else { - /* the audio header */ - memcpy (buffdata + 0, "strf", 4); - GST_WRITE_UINT32_LE (buffdata + 4, - sizeof (gst_riff_strf_auds) + 2 + codec_size); - /* the actual header */ - GST_WRITE_UINT16_LE (buffdata + 8, audpad->auds.format); - GST_WRITE_UINT16_LE (buffdata + 10, audpad->auds.channels); - GST_WRITE_UINT32_LE (buffdata + 12, audpad->auds.rate); - GST_WRITE_UINT32_LE (buffdata + 16, audpad->auds.av_bps); - GST_WRITE_UINT16_LE (buffdata + 20, audpad->auds.blockalign); - GST_WRITE_UINT16_LE (buffdata + 22, audpad->auds.size); - GST_WRITE_UINT16_LE (buffdata + 24, codec_size); - buffdata += 26; - highmark += 26; - - /* include codec data, if any */ - if (codec_size) { - memcpy (buffdata, GST_BUFFER_DATA (audpad->auds_codec_data), - codec_size); - - buffdata += codec_size; - highmark += codec_size; - } - /* padding */ - if (highmark & 0x1) { - highmark++; - buffdata++; - } - } - - /* odml superindex chunk */ - if (avipad->idx_index > 0) - memcpy (buffdata, "indx", 4); - else - memcpy (buffdata, "JUNK", 4); - GST_WRITE_UINT32_LE (buffdata + 4, ODML_SUPERINDEX_SIZE - 8); /* chunk size */ - GST_WRITE_UINT16_LE (buffdata + 8, 4); /* bytes per entry */ - buffdata[10] = 0; /* index subtype */ - buffdata[11] = GST_AVI_INDEX_OF_INDEXES; /* index type */ - GST_WRITE_UINT32_LE (buffdata + 12, avipad->idx_index); /* entries in use */ - memcpy (buffdata + 16, avipad->tag, 4); /* stream id */ - GST_WRITE_UINT32_LE (buffdata + 20, 0); /* reserved */ - GST_WRITE_UINT32_LE (buffdata + 24, 0); /* reserved */ - GST_WRITE_UINT32_LE (buffdata + 28, 0); /* reserved */ - memcpy (buffdata + 32, avipad->idx, - GST_AVI_SUPERINDEX_COUNT * sizeof (gst_avi_superindex_entry)); - buffdata += ODML_SUPERINDEX_SIZE; - highmark += ODML_SUPERINDEX_SIZE; - - node = node->next; - } - - if (avimux->video_pads > 0) { - /* odml header */ - memcpy (buffdata + 0, "LIST", 4); - GST_WRITE_UINT32_LE (buffdata + 4, sizeof (guint32) + 4 * 3); - memcpy (buffdata + 8, "odml", 4); - memcpy (buffdata + 12, "dmlh", 4); - GST_WRITE_UINT32_LE (buffdata + 16, sizeof (guint32)); - GST_WRITE_UINT32_LE (buffdata + 20, avimux->total_frames); - buffdata += 24; - highmark += 24; - } - - GST_WRITE_UINT32_LE (hdrl_size, (guint32) (buffdata - hdrl_size) - 4); - - /* tags */ - if (tags) { - guint8 *ptr; - guint startsize; - GstMarkedBuffer data ; - data.highmark = &highmark; - data.buffer = buffer; - - memcpy (buffdata + 0, "LIST", 4); - ptr = buffdata + 4; /* fill in later */ - startsize = highmark + 4; - memcpy (buffdata + 8, "INFO", 4); - buffdata += 12; - highmark += 12; - - /* 12 bytes is needed for data header */ - GST_BUFFER_SIZE (buffer) -= 12; - gst_tag_list_foreach (tags, gst_avi_mux_write_tag, &data); - GST_BUFFER_SIZE (buffer) += 12; - buffdata = GST_BUFFER_DATA (buffer) + highmark; - - /* update list size */ - GST_WRITE_UINT32_LE (ptr, highmark - startsize - 4); - } - - /* avi data header */ - memcpy (buffdata + 0, "LIST", 4); - GST_WRITE_UINT32_LE (buffdata + 4, avimux->data_size); - memcpy (buffdata + 8, "movi", 4); - buffdata += 12; - highmark += 12; - - /* finally we can fill in the RIFF size */ - /* note that riff only counts the first avi chunk */ - GST_WRITE_UINT32_LE (riff_size, (guint32) (buffdata - riff_size - 4) /* header and movi tags */ - +avimux->idx_size + avimux->data_size - 4); /* movi data and index */ - - { /* only the part that is filled in actually makes up the header - * unref the parent as we only need this part from now on */ - GstBuffer *subbuffer = gst_buffer_create_sub (buffer, 0, highmark); - - gst_buffer_unref (buffer); - return subbuffer; - } -} - -static GstBuffer * -gst_avi_mux_riff_get_avix_header (guint32 datax_size) -{ - GstBuffer *buffer; - guint8 *buffdata; - - buffer = gst_buffer_new_and_alloc (24); - buffdata = GST_BUFFER_DATA (buffer); - - memcpy (buffdata + 0, "RIFF", 4); - GST_WRITE_UINT32_LE (buffdata + 4, datax_size + 3 * 4); - memcpy (buffdata + 8, "AVIX", 4); - memcpy (buffdata + 12, "LIST", 4); - GST_WRITE_UINT32_LE (buffdata + 16, datax_size); - memcpy (buffdata + 20, "movi", 4); - - return buffer; -} - -static inline GstBuffer * -gst_avi_mux_riff_get_header (GstAviPad * avipad, guint32 video_frame_size) -{ - GstBuffer *buffer; - guint8 *buffdata; - - buffer = gst_buffer_new_and_alloc (8); - buffdata = GST_BUFFER_DATA (buffer); - memcpy (buffdata + 0, avipad->tag, 4); - GST_WRITE_UINT32_LE (buffdata + 4, video_frame_size); - - return buffer; -} - -/* write an odml index chunk in the movi list */ -static GstFlowReturn -gst_avi_mux_write_avix_index (GstAviMux * avimux, gchar * code, - gchar * chunk, gst_avi_superindex_entry * super_index, - gint * super_index_count) -{ - GstFlowReturn res; - GstBuffer *buffer; - guint8 *buffdata, *data; - gst_riff_index_entry *entry; - gint i; - guint32 size, entry_count; - - /* allocate the maximum possible */ - buffer = gst_buffer_new_and_alloc (32 + 8 * avimux->idx_index); - buffdata = GST_BUFFER_DATA (buffer); - - /* general index chunk info */ - memcpy (buffdata + 0, chunk, 4); /* chunk id */ - GST_WRITE_UINT32_LE (buffdata + 4, 0); /* chunk size; fill later */ - GST_WRITE_UINT16_LE (buffdata + 8, 2); /* index entry is 2 words */ - buffdata[10] = 0; /* index subtype */ - buffdata[11] = GST_AVI_INDEX_OF_CHUNKS; /* index type: AVI_INDEX_OF_CHUNKS */ - GST_WRITE_UINT32_LE (buffdata + 12, 0); /* entries in use; fill later */ - memcpy (buffdata + 16, code, 4); /* stream to which index refers */ - GST_WRITE_UINT64_LE (buffdata + 20, avimux->avix_start); /* base offset */ - GST_WRITE_UINT32_LE (buffdata + 28, 0); /* reserved */ - buffdata += 32; - - /* now the actual index entries */ - i = avimux->idx_index; - entry = avimux->idx; - while (i > 0) { - if (memcmp (&entry->id, code, 4) == 0) { - /* enter relative offset to the data (!) */ - GST_WRITE_UINT32_LE (buffdata, GUINT32_FROM_LE (entry->offset) + 8); - /* msb is set if not (!) keyframe */ - GST_WRITE_UINT32_LE (buffdata + 4, GUINT32_FROM_LE (entry->size) - | (GUINT32_FROM_LE (entry->flags) - & GST_RIFF_IF_KEYFRAME ? 0 : 1U << 31)); - buffdata += 8; - } - i--; - entry++; - } - - /* ok, now we know the size and no of entries, fill in where needed */ - data = GST_BUFFER_DATA (buffer); - GST_BUFFER_SIZE (buffer) = size = buffdata - data; - GST_WRITE_UINT32_LE (data + 4, size - 8); - entry_count = (size - 32) / 8; - GST_WRITE_UINT32_LE (data + 12, entry_count); - - /* decorate and send */ - gst_buffer_set_caps (buffer, GST_PAD_CAPS (avimux->srcpad)); - if ((res = gst_pad_push (avimux->srcpad, buffer)) != GST_FLOW_OK) - return res; - - /* keep track of this in superindex (if room) ... */ - if (*super_index_count < GST_AVI_SUPERINDEX_COUNT) { - i = *super_index_count; - super_index[i].offset = GUINT64_TO_LE (avimux->total_data); - super_index[i].size = GUINT32_TO_LE (size); - super_index[i].duration = GUINT32_TO_LE (entry_count); - (*super_index_count)++; - } else - GST_WARNING_OBJECT (avimux, "No more room in superindex of stream %s", - code); - - /* ... and in size */ - avimux->total_data += size; - if (avimux->is_bigfile) - avimux->datax_size += size; - else - avimux->data_size += size; - - return GST_FLOW_OK; -} - -/* some other usable functions (thankyou xawtv ;-) ) */ - -static void -gst_avi_mux_add_index (GstAviMux * avimux, gchar * code, guint32 flags, - guint32 size) -{ - if (avimux->idx_index == avimux->idx_count) { - avimux->idx_count += 256; - avimux->idx = - g_realloc (avimux->idx, - avimux->idx_count * sizeof (gst_riff_index_entry)); - } - memcpy (&(avimux->idx[avimux->idx_index].id), code, 4); - avimux->idx[avimux->idx_index].flags = GUINT32_TO_LE (flags); - avimux->idx[avimux->idx_index].offset = GUINT32_TO_LE (avimux->idx_offset); - avimux->idx[avimux->idx_index].size = GUINT32_TO_LE (size); - avimux->idx_index++; -} - -static GstFlowReturn -gst_avi_mux_write_index (GstAviMux * avimux) -{ - GstFlowReturn res; - GstBuffer *buffer; - guint8 *buffdata; - - buffer = gst_buffer_new_and_alloc (8); - buffdata = GST_BUFFER_DATA (buffer); - memcpy (buffdata + 0, "idx1", 4); - GST_WRITE_UINT32_LE (buffdata + 4, - avimux->idx_index * sizeof (gst_riff_index_entry)); - - gst_buffer_set_caps (buffer, GST_PAD_CAPS (avimux->srcpad)); - res = gst_pad_push (avimux->srcpad, buffer); - if (res != GST_FLOW_OK) - return res; - - buffer = gst_buffer_new (); - GST_BUFFER_SIZE (buffer) = avimux->idx_index * sizeof (gst_riff_index_entry); - GST_BUFFER_DATA (buffer) = (guint8 *) avimux->idx; - GST_BUFFER_MALLOCDATA (buffer) = GST_BUFFER_DATA (buffer); - avimux->idx = NULL; /* will be free()'ed by gst_buffer_unref() */ - avimux->total_data += GST_BUFFER_SIZE (buffer) + 8; - - gst_buffer_set_caps (buffer, GST_PAD_CAPS (avimux->srcpad)); - res = gst_pad_push (avimux->srcpad, buffer); - if (res != GST_FLOW_OK) - return res; - - avimux->idx_size += avimux->idx_index * sizeof (gst_riff_index_entry) + 8; - - /* update header */ - avimux->avi_hdr.flags |= GST_RIFF_AVIH_HASINDEX; - return GST_FLOW_OK; -} - -static GstFlowReturn -gst_avi_mux_bigfile (GstAviMux * avimux, gboolean last) -{ - GstFlowReturn res = GST_FLOW_OK; - GstBuffer *header; - GstEvent *event; - GSList *node; - - /* first some odml standard index chunks in the movi list */ - node = avimux->sinkpads; - while (node) { - GstAviPad *avipad = (GstAviPad *) node->data; - - node = node->next; - - res = gst_avi_mux_write_avix_index (avimux, avipad->tag, - avipad->idx_tag, avipad->idx, &avipad->idx_index); - if (res != GST_FLOW_OK) - return res; - } - - if (avimux->is_bigfile) { - /* search back */ - event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, - avimux->avix_start, GST_CLOCK_TIME_NONE, avimux->avix_start); - /* if the event succeeds */ - gst_pad_push_event (avimux->srcpad, event); - - /* rewrite AVIX header */ - header = gst_avi_mux_riff_get_avix_header (avimux->datax_size); - gst_buffer_set_caps (header, GST_PAD_CAPS (avimux->srcpad)); - res = gst_pad_push (avimux->srcpad, header); - - /* go back to current location, at least try */ - event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, - avimux->total_data, GST_CLOCK_TIME_NONE, avimux->total_data); - gst_pad_push_event (avimux->srcpad, event); - - if (res != GST_FLOW_OK) - return res; - } else { /* write a standard index in the first riff chunk */ - res = gst_avi_mux_write_index (avimux); - /* the index data/buffer is freed by pushing it */ - avimux->idx_count = 0; - if (res != GST_FLOW_OK) - return res; - } - - avimux->avix_start = avimux->total_data; - - if (last) - return res; - - avimux->is_bigfile = TRUE; - avimux->numx_frames = 0; - avimux->datax_size = 4; /* movi tag */ - avimux->idx_index = 0; - - header = gst_avi_mux_riff_get_avix_header (0); - avimux->total_data += GST_BUFFER_SIZE (header); - /* avix_start is used as base offset for the odml index chunk */ - avimux->idx_offset = avimux->total_data - avimux->avix_start; - gst_buffer_set_caps (header, GST_PAD_CAPS (avimux->srcpad)); - return gst_pad_push (avimux->srcpad, header); -} - -/* enough header blabla now, let's go on to actually writing the headers */ - -static GstFlowReturn -gst_avi_mux_start_file (GstAviMux * avimux) -{ - GstFlowReturn res; - GstBuffer *header; - GSList *node; - - avimux->total_data = 0; - avimux->total_frames = 0; - avimux->data_size = 4; /* movi tag */ - avimux->datax_size = 0; - avimux->num_frames = 0; - avimux->numx_frames = 0; - avimux->avix_start = 0; - - avimux->idx_index = 0; - avimux->idx_offset = 0; /* see 10 lines below */ - avimux->idx_size = 0; - avimux->idx_count = 0; - avimux->idx = NULL; - - /* state */ - avimux->write_header = FALSE; - avimux->restart = FALSE; - - /* init streams, see what we've got */ - node = avimux->sinkpads; - avimux->audio_pads = avimux->video_pads = 0; - while (node) { - GstAviPad *avipad = (GstAviPad *) node->data; - - node = node->next; - - if (!avipad->is_video) { - /* audio stream numbers must start at 1 iff there is a video stream 0; - * request_pad inserts video pad at head of list, so this test suffices */ - if (avimux->video_pads) - avimux->audio_pads++; - avipad->tag = g_strdup_printf ("%02uwb", avimux->audio_pads); - avipad->idx_tag = g_strdup_printf ("ix%02u", avimux->audio_pads); - if (!avimux->video_pads) - avimux->audio_pads++; - } else { - avipad->tag = g_strdup_printf ("%02udb", avimux->video_pads); - avipad->idx_tag = g_strdup_printf ("ix%02u", avimux->video_pads++); - } - } - - /* let downstream know we think in BYTES and expect to do seeking later on */ - gst_pad_push_event (avimux->srcpad, - gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0)); - - /* header */ - avimux->avi_hdr.streams = g_slist_length (avimux->sinkpads); - avimux->is_bigfile = FALSE; - - header = gst_avi_mux_riff_get_avi_header (avimux); - avimux->total_data += GST_BUFFER_SIZE (header); - - gst_buffer_set_caps (header, GST_PAD_CAPS (avimux->srcpad)); - res = gst_pad_push (avimux->srcpad, header); - - avimux->idx_offset = avimux->total_data; - - return res; -} - -static GstFlowReturn -gst_avi_mux_stop_file (GstAviMux * avimux) -{ - GstFlowReturn res = GST_FLOW_OK; - GstEvent *event; - GstBuffer *header; - GSList *node; - - /* if bigfile, rewrite header, else write indexes */ - /* don't bail out at once if error, still try to re-write header */ - if (avimux->video_pads > 0) { - if (avimux->is_bigfile) { - res = gst_avi_mux_bigfile (avimux, TRUE); - } else { - res = gst_avi_mux_write_index (avimux); - } - } - - /* we do our best to make it interleaved at least ... */ - if (avimux->audio_pads > 0 && avimux->video_pads > 0) - avimux->avi_hdr.flags |= GST_RIFF_AVIH_ISINTERLEAVED; - - /* set rate and everything having to do with that */ - avimux->avi_hdr.max_bps = 0; - node = avimux->sinkpads; - while (node) { - GstAviPad *avipad = (GstAviPad *) node->data; - - node = node->next; - - if (!avipad->is_video) { - GstAviAudioPad *audpad = (GstAviAudioPad *) avipad; - - /* calculate bps if needed */ - if (!audpad->auds.av_bps) { - if (audpad->audio_time) { - audpad->auds.av_bps = - (GST_SECOND * audpad->audio_size) / audpad->audio_time; - /* round bps to nearest multiple of 8; - * which is much more likely to be the (cbr) bitrate in use; - * which in turn results in better timestamp calculation on playback */ - audpad->auds.av_bps = GST_ROUND_UP_8 (audpad->auds.av_bps - 4); - } else { - GST_ELEMENT_WARNING (avimux, STREAM, MUX, - (_("No or invalid input audio, AVI stream will be corrupt.")), - (NULL)); - audpad->auds.av_bps = 0; - } - avipad->hdr.rate = audpad->auds.av_bps * avipad->hdr.scale; - } - avimux->avi_hdr.max_bps += audpad->auds.av_bps; - avipad->hdr.length = (audpad->audio_time * avipad->hdr.rate) / GST_SECOND; - } else { - GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad; - - avimux->avi_hdr.max_bps += ((vidpad->vids.bit_cnt + 7) / 8) * - (1000000. / avimux->avi_hdr.us_frame) * vidpad->vids.image_size; - avipad->hdr.length = avimux->total_frames; - } - } - - /* statistics/total_frames/... */ - avimux->avi_hdr.tot_frames = avimux->num_frames; - - /* seek and rewrite the header */ - header = gst_avi_mux_riff_get_avi_header (avimux); - event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, - 0, GST_CLOCK_TIME_NONE, 0); - gst_pad_push_event (avimux->srcpad, event); - - gst_buffer_set_caps (header, GST_PAD_CAPS (avimux->srcpad)); - /* the first error survives */ - if (res == GST_FLOW_OK) - res = gst_pad_push (avimux->srcpad, header); - else - gst_pad_push (avimux->srcpad, header); - - event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, - avimux->total_data, GST_CLOCK_TIME_NONE, avimux->total_data); - gst_pad_push_event (avimux->srcpad, event); - - avimux->write_header = TRUE; - - return res; -} - -static GstFlowReturn -gst_avi_mux_restart_file (GstAviMux * avimux) -{ - GstFlowReturn res; - - if ((res = gst_avi_mux_stop_file (avimux)) != GST_FLOW_OK) - return res; - - gst_pad_push_event (avimux->srcpad, gst_event_new_eos ()); - - return gst_avi_mux_start_file (avimux); -} - -/* handle events (search) */ -static gboolean -gst_avi_mux_handle_event (GstPad * pad, GstEvent * event) -{ - GstAviMux *avimux; - gboolean ret; - - avimux = GST_AVI_MUX (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_TAG:{ - GstTagList *list; - GstTagSetter *setter = GST_TAG_SETTER (avimux); - const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter); - - gst_event_parse_tag (event, &list); - gst_tag_setter_merge_tags (setter, list, mode); - break; - } - default: - break; - } - - /* now GstCollectPads can take care of the rest, e.g. EOS */ - ret = avimux->collect_event (pad, event); - - gst_object_unref (avimux); - - return ret; -} - -/* send extra 'padding' data */ -static GstFlowReturn -gst_avi_mux_send_pad_data (GstAviMux * avimux, gulong num_bytes) -{ - GstBuffer *buffer; - - buffer = gst_buffer_new_and_alloc (num_bytes); - memset (GST_BUFFER_DATA (buffer), 0, num_bytes); - gst_buffer_set_caps (buffer, GST_PAD_CAPS (avimux->srcpad)); - return gst_pad_push (avimux->srcpad, buffer); -} - -/* do buffer */ -static GstFlowReturn -gst_avi_mux_do_buffer (GstAviMux * avimux, GstAviPad * avipad) -{ - GstFlowReturn res; - GstBuffer *data, *header; - gulong total_size, pad_bytes = 0; - guint flags; - - data = gst_collect_pads_pop (avimux->collect, avipad->collect); - - if (avimux->restart) { - if ((res = gst_avi_mux_restart_file (avimux)) != GST_FLOW_OK) - return res; - } - - /* need to restart or start a next avix chunk ? */ - if ((avimux->is_bigfile ? avimux->datax_size : avimux->data_size) + - GST_BUFFER_SIZE (data) > 1024 * 1024 * 2000) { - if (avimux->enable_large_avi) { - if ((res = gst_avi_mux_bigfile (avimux, FALSE)) != GST_FLOW_OK) - return res; - } else { - if ((res = gst_avi_mux_restart_file (avimux)) != GST_FLOW_OK) - return res; - } - } - - /* get header and record some stats */ - if (GST_BUFFER_SIZE (data) & 1) { - pad_bytes = 2 - (GST_BUFFER_SIZE (data) & 1); - } - header = gst_avi_mux_riff_get_header (avipad, GST_BUFFER_SIZE (data)); - total_size = GST_BUFFER_SIZE (header) + GST_BUFFER_SIZE (data) + pad_bytes; - - if (avimux->is_bigfile) { - avimux->datax_size += total_size; - } else { - avimux->data_size += total_size; - } - - if (avipad->is_video) { - avimux->total_frames++; - - if (avimux->is_bigfile) { - avimux->numx_frames++; - } else { - avimux->num_frames++; - } - - flags = 0x02; - if (!GST_BUFFER_FLAG_IS_SET (data, GST_BUFFER_FLAG_DELTA_UNIT)) - flags |= 0x10; - } else { - GstAviAudioPad *audpad = (GstAviAudioPad *) avipad; - - flags = 0; - audpad->audio_size += GST_BUFFER_SIZE (data); - audpad->audio_time += GST_BUFFER_DURATION (data); - } - - gst_avi_mux_add_index (avimux, avipad->tag, flags, GST_BUFFER_SIZE (data)); - - /* prepare buffers for sending */ - gst_buffer_set_caps (header, GST_PAD_CAPS (avimux->srcpad)); - data = gst_buffer_make_metadata_writable (data); - gst_buffer_set_caps (data, GST_PAD_CAPS (avimux->srcpad)); - - GST_LOG_OBJECT (avimux, "pushing buffers: head, data"); - - if ((res = gst_pad_push (avimux->srcpad, header)) != GST_FLOW_OK) - return res; - if ((res = gst_pad_push (avimux->srcpad, data)) != GST_FLOW_OK) - return res; - - if (pad_bytes) { - if ((res = gst_avi_mux_send_pad_data (avimux, pad_bytes)) != GST_FLOW_OK) - return res; - } - - /* if any push above fails, we're in trouble with file consistency anyway */ - avimux->total_data += total_size; - avimux->idx_offset += total_size; - - return res; -} - -/* pick the oldest buffer from the pads and push it */ -static GstFlowReturn -gst_avi_mux_do_one_buffer (GstAviMux * avimux) -{ - GstAviPad *avipad, *best_pad; - GSList *node; - GstBuffer *buffer; - GstClockTime time, best_time; - - node = avimux->sinkpads; - best_pad = NULL; - best_time = GST_CLOCK_TIME_NONE; - for (; node; node = node->next) { - avipad = (GstAviPad *) node->data; - - if (!avipad->collect) - continue; - - buffer = gst_collect_pads_peek (avimux->collect, avipad->collect); - if (!buffer) - continue; - time = GST_BUFFER_TIMESTAMP (buffer); - gst_buffer_unref (buffer); - - /* invalid timestamp buffers pass first, - * these are probably initialization buffers */ - if (best_pad == NULL || !GST_CLOCK_TIME_IS_VALID (time) - || (GST_CLOCK_TIME_IS_VALID (best_time) && time < best_time)) { - best_pad = avipad; - best_time = time; - } - } - - if (best_pad) { - GST_LOG_OBJECT (avimux, "selected pad %s with time %" GST_TIME_FORMAT, - GST_PAD_NAME (best_pad->collect->pad), GST_TIME_ARGS (best_time)); - - return gst_avi_mux_do_buffer (avimux, best_pad); - } else { - /* simply finish off the file and send EOS */ - gst_avi_mux_stop_file (avimux); - gst_pad_push_event (avimux->srcpad, gst_event_new_eos ()); - return GST_FLOW_UNEXPECTED; - } -} - -static GstFlowReturn -gst_avi_mux_collect_pads (GstCollectPads * pads, GstAviMux * avimux) -{ - GstFlowReturn res; - - if (G_UNLIKELY (avimux->write_header)) { - if ((res = gst_avi_mux_start_file (avimux)) != GST_FLOW_OK) - return res; - } - - return gst_avi_mux_do_one_buffer (avimux); -} - - -static void -gst_avi_mux_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec) -{ - GstAviMux *avimux; - - avimux = GST_AVI_MUX (object); - - switch (prop_id) { - case ARG_BIGFILE: - g_value_set_boolean (value, avimux->enable_large_avi); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_avi_mux_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec) -{ - GstAviMux *avimux; - - avimux = GST_AVI_MUX (object); - - switch (prop_id) { - case ARG_BIGFILE: - avimux->enable_large_avi = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstStateChangeReturn -gst_avi_mux_change_state (GstElement * element, GstStateChange transition) -{ - GstAviMux *avimux; - GstStateChangeReturn ret; - - avimux = GST_AVI_MUX (element); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_collect_pads_start (avimux->collect); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_collect_pads_stop (avimux->collect); - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - goto done; - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_avi_mux_reset (avimux); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - -done: - return ret; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/avi/gstavimux.h --- a/gst_plugins_good/gst/avi/gstavimux.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -/* AVI muxer plugin for GStreamer - * Copyright (C) 2002 Ronald Bultje - * - * 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. - */ - - -#ifndef __GST_AVI_MUX_H__ -#define __GST_AVI_MUX_H__ - - -#include -#include -#include -#include "avi-ids.h" - -G_BEGIN_DECLS - -#define GST_TYPE_AVI_MUX \ - (gst_avi_mux_get_type()) -#define GST_AVI_MUX(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVI_MUX,GstAviMux)) -#define GST_AVI_MUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVI_MUX,GstAviMuxClass)) -#define GST_IS_AVI_MUX(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVI_MUX)) -#define GST_IS_AVI_MUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVI_MUX)) - -#define GST_AVI_INDEX_OF_INDEXES 0 -#define GST_AVI_INDEX_OF_CHUNKS 1 - -/* this allows indexing up to 64GB avi file */ -#define GST_AVI_SUPERINDEX_COUNT 32 - -typedef struct _gst_avi_superindex_entry { - guint64 offset; - guint32 size; - guint32 duration; -} gst_avi_superindex_entry; - -typedef struct _gst_riff_strh_full { - gst_riff_strh parent; - /* rcFrame, RECT structure (struct of 4 shorts) */ - gint16 left; - gint16 top; - gint16 right; - gint16 bottom; -} gst_riff_strh_full; - -typedef struct _GstAviPad { - /* do not extend, link to it */ - /* is NULL if original sink request pad has been removed */ - GstCollectData *collect; - - /* type */ - gboolean is_video; - gboolean connected; - - /* chunk tag */ - gchar *tag; - - /* stream header */ - gst_riff_strh hdr; - - /* odml super indexes */ - gst_avi_superindex_entry idx[GST_AVI_SUPERINDEX_COUNT]; - gint idx_index; - gchar *idx_tag; -} GstAviPad; - -typedef struct _GstAviVideoPad { - GstAviPad parent; - - /* stream format */ - gst_riff_strf_vids vids; - /* extra data */ - GstBuffer *vids_codec_data; - /* ODML video properties */ - gst_riff_vprp vprp; - -} GstAviVideoPad; - -typedef struct _GstAviAudioPad { - GstAviPad parent; - - /* stream format */ - gst_riff_strf_auds auds; - /* audio info for bps calculation */ - guint32 audio_size; - guint64 audio_time; - /* extra data */ - GstBuffer *auds_codec_data; -} GstAviAudioPad; - -typedef struct _GstAviCollectData { - /* extend the CollectData */ - GstCollectData collect; - - GstAviPad *avipad; -} GstAviCollectData; - -typedef struct _GstAviMux GstAviMux; -typedef struct _GstAviMuxClass GstAviMuxClass; - -struct _GstAviMux { - GstElement element; - - /* pads */ - GstPad *srcpad; - /* sinkpads, video first */ - GSList *sinkpads; - /* video restricted to 1 pad */ - guint video_pads, audio_pads; - GstCollectPads *collect; - GstPadEventFunction collect_event; - - /* the AVI header */ - /* still some single stream video data in mux struct */ - gst_riff_avih avi_hdr; - /* total number of (video) frames */ - guint32 total_frames; - /* amount of total data (bytes) */ - guint64 total_data; - /* amount of data (bytes) in the AVI/AVIX block; - * actually the movi list, so counted from and including the movi tag */ - guint32 data_size, datax_size; - /* num (video) frames in the AVI/AVIX block */ - guint32 num_frames, numx_frames; - /* size of hdrl list, including tag as usual */ - - /* total size of extra codec data */ - guint32 codec_data_size; - /* state info */ - gboolean write_header; - gboolean restart; - - /* tags */ - GstTagList *tags_snap; - - /* information about the AVI index ('idx') */ - gst_riff_index_entry *idx; - gint idx_index, idx_count; - /* offset of *chunk* (relative to a base offset); entered in the index */ - guint32 idx_offset; - /* size of idx1 chunk (including! chunk header and size bytes) */ - guint32 idx_size; - - /* are we a big file already? */ - gboolean is_bigfile; - guint64 avix_start; - - /* whether to use "large AVI files" or just stick to small indexed files */ - gboolean enable_large_avi; -}; - -struct _GstAviMuxClass { - GstElementClass parent_class; -}; - -GType gst_avi_mux_get_type(void); - -G_END_DECLS - - -#endif /* __GST_AVI_MUX_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/avi/gstavisubtitle.c --- a/gst_plugins_good/gst/avi/gstavisubtitle.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,376 +0,0 @@ -/* GStreamer AVI GAB2 subtitle parser - * Copyright (C) <2007> Thijs Vermeir - * Copyright (C) <2007> Tim-Philipp Müller - * - * 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. - */ - -/** - * SECTION:element-avisubtitle - * - * - * - * Parses the subtitle stream from an avi file. - * - * Example launch line - * - * - * gst-launch filesrc location=subtitle.avi ! avidemux name=demux ! queue ! avisubtitle ! subparse ! textoverlay name=overlay ! ffmpegcolorspace ! autovideosink demux. ! queue ! decodebin ! overlay. - * - * This plays an avi file with a video and subtitle stream. - * - * - * - * Last reviewed on 2008-02-01 - */ - -/* example of a subtitle chunk in an avi file - * 00000000: 47 41 42 32 00 02 00 10 00 00 00 45 00 6e 00 67 GAB2.......E.n.g - * 00000010: 00 6c 00 69 00 73 00 68 00 00 00 04 00 8e 00 00 .l.i.s.h........ - * 00000020: 00 ef bb bf 31 0d 0a 30 30 3a 30 30 3a 30 30 2c ....1..00:00:00, - * 00000030: 31 30 30 20 2d 2d 3e 20 30 30 3a 30 30 3a 30 32 100 --> 00:00:02 - * 00000040: 2c 30 30 30 0d 0a 3c 62 3e 41 6e 20 55 54 46 38 ,000..An UTF8 - * 00000050: 20 53 75 62 74 69 74 6c 65 20 77 69 74 68 20 42 Subtitle with B - * 00000060: 4f 4d 3c 2f 62 3e 0d 0a 0d 0a 32 0d 0a 30 30 3a OM....2..00: - * 00000070: 30 30 3a 30 32 2c 31 30 30 20 2d 2d 3e 20 30 30 00:02,100 --> 00 - * 00000080: 3a 30 30 3a 30 34 2c 30 30 30 0d 0a 53 6f 6d 65 :00:04,000..Some - * 00000090: 74 68 69 6e 67 20 6e 6f 6e 41 53 43 49 49 20 2d thing nonASCII - - * 000000a0: 20 c2 b5 c3 b6 c3 a4 c3 bc c3 9f 0d 0a 0d 0a .............. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "gstavisubtitle.h" - -GST_DEBUG_CATEGORY_STATIC (avisubtitle_debug); -#define GST_CAT_DEFAULT avisubtitle_debug - -static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/x-subtitle-avi") - ); - -static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/x-subtitle") - ); - -static void gst_avi_subtitle_title_tag (GstAviSubtitle * sub, gchar * title); -static GstFlowReturn gst_avi_subtitle_chain (GstPad * pad, GstBuffer * buffer); -static GstStateChangeReturn gst_avi_subtitle_change_state (GstElement * element, - GstStateChange transition); -static gboolean gst_avi_subtitle_send_event (GstElement * element, - GstEvent * event); - -GST_BOILERPLATE (GstAviSubtitle, gst_avi_subtitle, GstElement, - GST_TYPE_ELEMENT); - -#define IS_BOM_UTF8(data) ((GST_READ_UINT32_BE(data) >> 8) == 0xEFBBBF) -#define IS_BOM_UTF16_BE(data) (GST_READ_UINT16_BE(data) == 0xFEFF) -#define IS_BOM_UTF16_LE(data) (GST_READ_UINT16_LE(data) == 0xFEFF) -#define IS_BOM_UTF32_BE(data) (GST_READ_UINT32_BE(data) == 0xFEFF) -#define IS_BOM_UTF32_LE(data) (GST_READ_UINT32_LE(data) == 0xFEFF) - -static GstBuffer * -gst_avi_subtitle_extract_file (GstAviSubtitle * sub, GstBuffer * buffer, - guint offset, guint len) -{ - const gchar *input_enc = NULL; - GstBuffer *ret = NULL; - gchar *data; - - data = (gchar *) GST_BUFFER_DATA (buffer) + offset; - - if (len >= (3 + 1) && IS_BOM_UTF8 (data) && - g_utf8_validate (data + 3, len - 3, NULL)) { - ret = gst_buffer_create_sub (buffer, offset + 3, len - 3); - } else if (len >= 2 && IS_BOM_UTF16_BE (data)) { - input_enc = "UTF-16BE"; - data += 2; - len -= 2; - } else if (len >= 2 && IS_BOM_UTF16_LE (data)) { - input_enc = "UTF-16LE"; - data += 2; - len -= 2; - } else if (len >= 4 && IS_BOM_UTF32_BE (data)) { - input_enc = "UTF-32BE"; - data += 4; - len -= 4; - } else if (len >= 4 && IS_BOM_UTF32_LE (data)) { - input_enc = "UTF-32LE"; - data += 4; - len -= 4; - } else if (g_utf8_validate (data, len, NULL)) { - /* not specified, check if it's UTF-8 */ - ret = gst_buffer_create_sub (buffer, offset, len); - } else { - /* we could fall back to gst_tag_freeform_to_utf8() here */ - GST_WARNING_OBJECT (sub, "unspecified encoding, and not UTF-8"); - return NULL; - } - - g_return_val_if_fail (ret != NULL || input_enc != NULL, NULL); - - if (input_enc) { - GError *err = NULL; - gchar *utf8; - - GST_DEBUG_OBJECT (sub, "converting subtitles from %s to UTF-8", input_enc); - utf8 = g_convert (data, len, "UTF-8", input_enc, NULL, NULL, &err); - - if (err != NULL) { - GST_WARNING_OBJECT (sub, "conversion to UTF-8 failed : %s", err->message); - g_error_free (err); - return NULL; - } - - ret = gst_buffer_new (); - GST_BUFFER_DATA (ret) = (guint8 *) utf8; - GST_BUFFER_MALLOCDATA (ret) = (guint8 *) utf8; - GST_BUFFER_SIZE (ret) = strlen (utf8); - GST_BUFFER_OFFSET (ret) = 0; - } - - GST_BUFFER_CAPS (ret) = gst_caps_new_simple ("application/x-subtitle", NULL); - return ret; -} - -/** - * gst_avi_subtitle_title_tag: - * @sub: subtitle element - * @title: the title of this subtitle stream - * - * Send an event to the srcpad of the @sub element with the title - * of the subtitle stream as a GST_TAG_TITLE - */ -static void -gst_avi_subtitle_title_tag (GstAviSubtitle * sub, gchar * title) -{ - GstTagList *temp_list = gst_tag_list_new (); - - gst_tag_list_add (temp_list, GST_TAG_MERGE_APPEND, GST_TAG_TITLE, title, - NULL); - gst_pad_push_event (sub->src, gst_event_new_tag (temp_list)); -} - -static GstFlowReturn -gst_avi_subtitle_parse_gab2_chunk (GstAviSubtitle * sub, GstBuffer * buf) -{ - const guint8 *data; - gchar *name_utf8; - guint name_length; - guint file_length; - guint size; - - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); - - /* check the magic word "GAB2\0", and the next word must be 2 */ - if (size < 12 || memcmp (data, "GAB2\0\2\0", 5 + 2) != 0) - goto wrong_magic_word; - - /* read 'name' of subtitle */ - name_length = GST_READ_UINT32_LE (data + 5 + 2); - GST_LOG_OBJECT (sub, "length of name: %u", name_length); - if (size <= 17 + name_length) - goto wrong_name_length; - - name_utf8 = g_convert ((gchar *) data + 11, name_length, "UTF-8", "UTF-16LE", - NULL, NULL, NULL); - - if (name_utf8) { - GST_LOG_OBJECT (sub, "subtitle name: %s", name_utf8); - gst_avi_subtitle_title_tag (sub, name_utf8); - g_free (name_utf8); - } - - /* next word must be 4 */ - if (GST_READ_UINT16_LE (data + 11 + name_length) != 0x4) - goto wrong_fixed_word_2; - - file_length = GST_READ_UINT32_LE (data + 13 + name_length); - GST_LOG_OBJECT (sub, "length srt/ssa file: %u", file_length); - - if (size < (17 + name_length + file_length)) - goto wrong_total_length; - - /* store this, so we can send it again after a seek; note that we shouldn't - * assume all the remaining data in the chunk is subtitle data, there may - * be padding at the end for some reason, so only parse file_length bytes */ - sub->subfile = - gst_avi_subtitle_extract_file (sub, buf, 17 + name_length, file_length); - - if (sub->subfile == NULL) - goto extract_failed; - - return GST_FLOW_OK; - - /* ERRORS */ -wrong_magic_word: - { - GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL), ("Wrong magic word")); - return GST_FLOW_ERROR; - } -wrong_name_length: - { - GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL), - ("name doesn't fit in buffer (%d < %d)", size, 17 + name_length)); - return GST_FLOW_ERROR; - } -wrong_fixed_word_2: - { - GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL), - ("wrong fixed word: expected %u, got %u", 4, - GST_READ_UINT16_LE (data + 11 + name_length))); - return GST_FLOW_ERROR; - } -wrong_total_length: - { - GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL), - ("buffer size is wrong: need %d bytes, have %d bytes", - 17 + name_length + file_length, size)); - return GST_FLOW_ERROR; - } -extract_failed: - { - GST_ELEMENT_ERROR (sub, STREAM, DECODE, (NULL), - ("could not extract subtitles")); - return GST_FLOW_ERROR; - } -} - -static GstFlowReturn -gst_avi_subtitle_chain (GstPad * pad, GstBuffer * buffer) -{ - GstAviSubtitle *sub = GST_AVI_SUBTITLE (GST_PAD_PARENT (pad)); - GstFlowReturn ret; - - if (sub->subfile != NULL) { - GST_WARNING_OBJECT (sub, "Got more buffers than expected, dropping"); - ret = GST_FLOW_UNEXPECTED; - goto done; - } - - /* we expect exactly one buffer with the whole srt/ssa file in it */ - ret = gst_avi_subtitle_parse_gab2_chunk (sub, buffer); - if (ret != GST_FLOW_OK) - goto done; - - /* now push the subtitle data downstream */ - ret = gst_pad_push (sub->src, gst_buffer_ref (sub->subfile)); - -done: - - gst_buffer_unref (buffer); - return ret; -} - -static gboolean -gst_avi_subtitle_send_event (GstElement * element, GstEvent * event) -{ - GstAviSubtitle *avisubtitle = GST_AVI_SUBTITLE (element); - gboolean ret = FALSE; - - if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK) { - if (avisubtitle->subfile) { - if (gst_pad_push (avisubtitle->src, - gst_buffer_ref (avisubtitle->subfile)) == GST_FLOW_OK) - ret = TRUE; - } - } - gst_event_unref (event); - return ret; -} - -static void -gst_avi_subtitle_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - GST_DEBUG_CATEGORY_INIT (avisubtitle_debug, "avisubtitle", 0, - "parse avi subtitle stream"); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_template)); - - gst_element_class_set_details_simple (element_class, - "Avi subtitle parser", "Codec/Parser/Subtitle", - "Parse avi subtitle stream", "Thijs Vermeir "); -} - -static void -gst_avi_subtitle_class_init (GstAviSubtitleClass * klass) -{ - GstElementClass *gstelement_class = (GstElementClass *) klass; - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_avi_subtitle_change_state); - gstelement_class->send_event = - GST_DEBUG_FUNCPTR (gst_avi_subtitle_send_event); -} - -static void -gst_avi_subtitle_init (GstAviSubtitle * self, GstAviSubtitleClass * klass) -{ - self->src = gst_pad_new_from_static_template (&src_template, "src"); - gst_element_add_pad (GST_ELEMENT (self), self->src); - - self->sink = gst_pad_new_from_static_template (&sink_template, "sink"); - gst_pad_set_chain_function (self->sink, - GST_DEBUG_FUNCPTR (gst_avi_subtitle_chain)); - gst_element_add_pad (GST_ELEMENT (self), self->sink); - - self->subfile = NULL; -} - -static GstStateChangeReturn -gst_avi_subtitle_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret; - GstAviSubtitle *sub = GST_AVI_SUBTITLE (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - case GST_STATE_CHANGE_READY_TO_PAUSED: - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - if (sub->subfile) { - gst_buffer_unref (sub->subfile); - sub->subfile = NULL; - } - break; - default: - break; - } - - return ret; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/avi/gstavisubtitle.h --- a/gst_plugins_good/gst/avi/gstavisubtitle.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ - -#ifndef __GSTAVISUBTITLE_H__ -#define __GSTAVISUBTITLE_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -typedef struct _GstAviSubtitle GstAviSubtitle; -typedef struct _GstAviSubtitleClass GstAviSubtitleClass; - -#define GST_TYPE_AVI_SUBTITLE (gst_avi_subtitle_get_type ()) -#define GST_AVI_SUBTITLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AVI_SUBTITLE, GstAviSubtitle)) -#define GST_AVI_SUBTITLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_AVI_SUBTITLE, GstAviSubtitleClass)) -#define GST_IS_AVI_SUBTITLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AVI_SUBTITLE)) -#define GST_IS_AVI_SUBTITLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_AVI_SUBTITLE)) -#define GST_AVI_SUBTITLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_AVI_SUBTITLE, GstAviSubtitleClass)) - -#ifdef __SYMBIAN32__ -IMPORT_C -#endif -GType gst_avi_subtitle_get_type (void); - -struct _GstAviSubtitle -{ - GstElement parent; - - GstPad *src; - GstPad *sink; - - GstBuffer *subfile; /* the complete subtitle file in one buffer */ -}; - -struct _GstAviSubtitleClass -{ - GstElementClass parent; -}; - -G_END_DECLS -#endif diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/law/alaw-decode.c --- a/gst_plugins_good/gst/law/alaw-decode.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,344 +0,0 @@ -/* GStreamer A-Law to PCM conversion - * Copyright (C) 2000 by Abramo Bagnara - * - * 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.1 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. - */ -/** - * SECTION:element-alawdec - * - * This element decodes alaw audio. Alaw coding is also known as G.711. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "alaw-decode.h" - -extern GstStaticPadTemplate alaw_dec_src_factory; -extern GstStaticPadTemplate alaw_dec_sink_factory; - -GST_DEBUG_CATEGORY_STATIC (alaw_dec_debug); -#define GST_CAT_DEFAULT alaw_dec_debug - -static GstStateChangeReturn -gst_alaw_dec_change_state (GstElement * element, GstStateChange transition); -static GstFlowReturn gst_alaw_dec_chain (GstPad * pad, GstBuffer * buffer); - -GST_BOILERPLATE (GstALawDec, gst_alaw_dec, GstElement, GST_TYPE_ELEMENT); - -/* some day we might have defines in gstconfig.h that tell us about the - * desired cpu/memory/binary size trade-offs */ -#define GST_ALAW_DEC_USE_TABLE - -#ifdef GST_ALAW_DEC_USE_TABLE - -static const gint alaw_to_s16_table[256] = { - -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, - -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, - -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, - -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, - -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, - -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, - -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, - -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, - -344, -328, -376, -360, -280, -264, -312, -296, - -472, -456, -504, -488, -408, -392, -440, -424, - -88, -72, -120, -104, -24, -8, -56, -40, - -216, -200, -248, -232, -152, -136, -184, -168, - -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, - -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, -592, - -944, -912, -1008, -976, -816, -784, -880, -848, - 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, - 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, - 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, - 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, - 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, - 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, - 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, - 344, 328, 376, 360, 280, 264, 312, 296, - 472, 456, 504, 488, 408, 392, 440, 424, - 88, 72, 120, 104, 24, 8, 56, 40, - 216, 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, - 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, - 688, 656, 752, 720, 560, 528, 624, 592, - 944, 912, 1008, 976, 816, 784, 880, 848 -}; - -static inline gint -alaw_to_s16 (guint8 a_val) -{ - return alaw_to_s16_table[a_val]; -} - -#else /* GST_ALAW_DEC_USE_TABLE */ - -static inline gint -alaw_to_s16 (guint8 a_val) -{ - gint t; - gint seg; - - a_val ^= 0x55; - t = a_val & 0x7f; - if (t < 16) - t = (t << 4) + 8; - else { - seg = (t >> 4) & 0x07; - t = ((t & 0x0f) << 4) + 0x108; - t <<= seg - 1; - } - return ((a_val & 0x80) ? t : -t); -} - -#endif /* GST_ALAW_DEC_USE_TABLE */ - -static gboolean -gst_alaw_dec_sink_setcaps (GstPad * pad, GstCaps * caps) -{ - GstALawDec *alawdec; - GstStructure *structure; - int rate, channels; - gboolean ret; - GstCaps *outcaps; - - alawdec = GST_ALAW_DEC (GST_PAD_PARENT (pad)); - - structure = gst_caps_get_structure (caps, 0); - - ret = gst_structure_get_int (structure, "rate", &rate); - ret &= gst_structure_get_int (structure, "channels", &channels); - if (!ret) - return FALSE; - - outcaps = gst_caps_new_simple ("audio/x-raw-int", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "signed", G_TYPE_BOOLEAN, TRUE, - "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL); - - ret = gst_pad_set_caps (alawdec->srcpad, outcaps); - gst_caps_unref (outcaps); - - if (ret) { - GST_DEBUG_OBJECT (alawdec, "rate=%d, channels=%d", rate, channels); - alawdec->rate = rate; - alawdec->channels = channels; - } - return ret; -} - -static GstCaps * -gst_alaw_dec_getcaps (GstPad * pad) -{ - GstALawDec *alawdec; - GstPad *otherpad; - GstCaps *othercaps, *result; - const GstCaps *templ; - gchar *name; - gint i; - - alawdec = GST_ALAW_DEC (GST_PAD_PARENT (pad)); - - /* figure out the name of the caps we are going to return */ - if (pad == alawdec->srcpad) { - name = "audio/x-raw-int"; - otherpad = alawdec->sinkpad; - } else { - name = "audio/x-alaw"; - otherpad = alawdec->srcpad; - } - /* get caps from the peer, this can return NULL when there is no peer */ - othercaps = gst_pad_peer_get_caps (otherpad); - - /* get the template caps to make sure we return something acceptable */ - templ = gst_pad_get_pad_template_caps (pad); - - if (othercaps) { - /* there was a peer */ - othercaps = gst_caps_make_writable (othercaps); - - /* go through the caps and remove the fields we don't want */ - for (i = 0; i < gst_caps_get_size (othercaps); i++) { - GstStructure *structure; - - structure = gst_caps_get_structure (othercaps, i); - - /* adjust the name */ - gst_structure_set_name (structure, name); - - if (pad == alawdec->sinkpad) { - /* remove the fields we don't want */ - gst_structure_remove_fields (structure, "width", "depth", "endianness", - "signed", NULL); - } else { - /* add fixed fields */ - gst_structure_set (structure, "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "signed", G_TYPE_BOOLEAN, TRUE, NULL); - } - } - /* filter against the allowed caps of the pad to return our result */ - result = gst_caps_intersect (othercaps, templ); - gst_caps_unref (othercaps); - } else { - /* there was no peer, return the template caps */ - result = gst_caps_copy (templ); - } - - return result; -} - -static void -gst_alaw_dec_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&alaw_dec_src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&alaw_dec_sink_factory)); - - gst_element_class_set_details_simple (element_class, "A Law audio decoder", - "Codec/Decoder/Audio", "Convert 8bit A law to 16bit PCM", - "Zaheer Abbas Merali "); - - GST_DEBUG_CATEGORY_INIT (alaw_dec_debug, "alawdec", 0, "A Law audio decoder"); -} - -static void -gst_alaw_dec_class_init (GstALawDecClass * klass) -{ - GstElementClass *element_class = (GstElementClass *) klass; - - element_class->change_state = GST_DEBUG_FUNCPTR (gst_alaw_dec_change_state); -} - -static void -gst_alaw_dec_init (GstALawDec * alawdec, GstALawDecClass * klass) -{ - alawdec->sinkpad = - gst_pad_new_from_static_template (&alaw_dec_sink_factory, "sink"); - gst_pad_set_setcaps_function (alawdec->sinkpad, - GST_DEBUG_FUNCPTR (gst_alaw_dec_sink_setcaps)); - gst_pad_set_getcaps_function (alawdec->sinkpad, - GST_DEBUG_FUNCPTR (gst_alaw_dec_getcaps)); - gst_pad_set_chain_function (alawdec->sinkpad, - GST_DEBUG_FUNCPTR (gst_alaw_dec_chain)); - gst_element_add_pad (GST_ELEMENT (alawdec), alawdec->sinkpad); - - alawdec->srcpad = - gst_pad_new_from_static_template (&alaw_dec_src_factory, "src"); - gst_pad_use_fixed_caps (alawdec->srcpad); - gst_pad_set_getcaps_function (alawdec->srcpad, - GST_DEBUG_FUNCPTR (gst_alaw_dec_getcaps)); - gst_element_add_pad (GST_ELEMENT (alawdec), alawdec->srcpad); -} - -static GstFlowReturn -gst_alaw_dec_chain (GstPad * pad, GstBuffer * buffer) -{ - GstALawDec *alawdec; - gint16 *linear_data; - guint8 *alaw_data; - guint alaw_size; - GstBuffer *outbuf; - gint i; - GstFlowReturn ret; - - alawdec = GST_ALAW_DEC (GST_PAD_PARENT (pad)); - - if (G_UNLIKELY (alawdec->rate == 0)) - goto not_negotiated; - - GST_LOG_OBJECT (alawdec, "buffer with ts=%" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); - - alaw_data = GST_BUFFER_DATA (buffer); - alaw_size = GST_BUFFER_SIZE (buffer); - - ret = - gst_pad_alloc_buffer_and_set_caps (alawdec->srcpad, - GST_BUFFER_OFFSET_NONE, alaw_size * 2, GST_PAD_CAPS (alawdec->srcpad), - &outbuf); - if (ret != GST_FLOW_OK) - goto alloc_failed; - - linear_data = (gint16 *) GST_BUFFER_DATA (outbuf); - - /* copy discont flag */ - if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - - GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer); - GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer); - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (alawdec->srcpad)); - - for (i = 0; i < alaw_size; i++) { - linear_data[i] = alaw_to_s16 (alaw_data[i]); - } - gst_buffer_unref (buffer); - - ret = gst_pad_push (alawdec->srcpad, outbuf); - - return ret; - -not_negotiated: - { - gst_buffer_unref (buffer); - GST_WARNING_OBJECT (alawdec, "no input format set: not-negotiated"); - return GST_FLOW_NOT_NEGOTIATED; - } -alloc_failed: - { - gst_buffer_unref (buffer); - GST_DEBUG_OBJECT (alawdec, "pad alloc failed, flow: %s", - gst_flow_get_name (ret)); - return ret; - } -} - -static GstStateChangeReturn -gst_alaw_dec_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret; - GstALawDec *dec = GST_ALAW_DEC (element); - - switch (transition) { - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret != GST_STATE_CHANGE_SUCCESS) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - dec->rate = 0; - dec->channels = 0; - break; - default: - break; - } - - return ret; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/law/alaw-decode.h --- a/gst_plugins_good/gst/law/alaw-decode.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* GStreamer A-Law to PCM conversion - * Copyright (C) 2000 by Abramo Bagnara - * - * 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. - */ - -#ifndef __GST_ALAW_DECODE_H__ -#define __GST_ALAW_DECODE_H__ - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_ALAW_DEC \ - (gst_alaw_dec_get_type()) -#define GST_ALAW_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALAW_DEC,GstALawDec)) -#define GST_ALAW_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALAW_DEC,GstALawDecClass)) -#define GST_IS_ALAW_DEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALAW_DEC)) -#define GST_IS_ALAW_DEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALAW_DEC)) - -typedef struct _GstALawDec GstALawDec; -typedef struct _GstALawDecClass GstALawDecClass; - -struct _GstALawDec { - GstElement element; - - GstPad *sinkpad,*srcpad; - gint rate; - gint channels; -}; - -struct _GstALawDecClass { - GstElementClass parent_class; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - - -GType gst_alaw_dec_get_type(void); - -G_END_DECLS - -#endif /* __GST_ALAW_DECODE_H__ */ - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/law/alaw-encode.c --- a/gst_plugins_good/gst/law/alaw-encode.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,524 +0,0 @@ -/* GStreamer PCM to A-Law conversion - * Copyright (C) 2000 by Abramo Bagnara - * - * 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.1 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. - */ -/** - * SECTION:element-alawenc - * - * This element encode alaw audio. Alaw coding is also known as G.711. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "alaw-encode.h" - -GST_DEBUG_CATEGORY_STATIC (alaw_enc_debug); -#define GST_CAT_DEFAULT alaw_enc_debug - -extern GstStaticPadTemplate alaw_enc_src_factory; -extern GstStaticPadTemplate alaw_enc_sink_factory; - -static GstFlowReturn gst_alaw_enc_chain (GstPad * pad, GstBuffer * buffer); - -GST_BOILERPLATE (GstALawEnc, gst_alaw_enc, GstElement, GST_TYPE_ELEMENT); - -/* some day we might have defines in gstconfig.h that tell us about the - * desired cpu/memory/binary size trade-offs */ -#define GST_ALAW_ENC_USE_TABLE - -#ifdef GST_ALAW_ENC_USE_TABLE - -static const guint8 alaw_encode[2048 + 1] = { - 0xd5, 0xd4, 0xd7, 0xd6, 0xd1, 0xd0, 0xd3, 0xd2, 0xdd, 0xdc, 0xdf, 0xde, - 0xd9, 0xd8, 0xdb, 0xda, 0xc5, 0xc4, 0xc7, 0xc6, 0xc1, 0xc0, 0xc3, 0xc2, - 0xcd, 0xcc, 0xcf, 0xce, 0xc9, 0xc8, 0xcb, 0xca, 0xf5, 0xf5, 0xf4, 0xf4, - 0xf7, 0xf7, 0xf6, 0xf6, 0xf1, 0xf1, 0xf0, 0xf0, 0xf3, 0xf3, 0xf2, 0xf2, - 0xfd, 0xfd, 0xfc, 0xfc, 0xff, 0xff, 0xfe, 0xfe, 0xf9, 0xf9, 0xf8, 0xf8, - 0xfb, 0xfb, 0xfa, 0xfa, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1, - 0xe0, 0xe0, 0xe0, 0xe0, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, - 0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xef, 0xef, 0xef, 0xef, - 0xee, 0xee, 0xee, 0xee, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, - 0xeb, 0xeb, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a -}; - -static inline guint8 -s16_to_alaw (gint16 pcm_val) -{ - if (pcm_val >= 0) - return alaw_encode[pcm_val / 16]; - else - return (0x7F & alaw_encode[pcm_val / -16]); -} - -#else /* GST_ALAW_ENC_USE_TABLE */ - -/* - * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law - * - * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data. - * - * Linear Input Code Compressed Code - * ------------------------ --------------- - * 0000000wxyza 000wxyz - * 0000001wxyza 001wxyz - * 000001wxyzab 010wxyz - * 00001wxyzabc 011wxyz - * 0001wxyzabcd 100wxyz - * 001wxyzabcde 101wxyz - * 01wxyzabcdef 110wxyz - * 1wxyzabcdefg 111wxyz - * - * For further information see John C. Bellamy's Digital Telephony, 1982, - * John Wiley & Sons, pps 98-111 and 472-476. - */ - -static inline gint -val_seg (gint val) -{ - gint r = 1; - - val >>= 8; - if (val & 0xf0) { - val >>= 4; - r += 4; - } - if (val & 0x0c) { - val >>= 2; - r += 2; - } - if (val & 0x02) - r += 1; - return r; -} - -static inline guint8 -s16_to_alaw (gint pcm_val) -{ - gint seg; - guint8 mask; - guint8 aval; - - if (pcm_val >= 0) { - mask = 0xD5; - } else { - mask = 0x55; - pcm_val = -pcm_val; - if (pcm_val > 0x7fff) - pcm_val = 0x7fff; - } - - if (pcm_val < 256) - aval = pcm_val >> 4; - else { - /* Convert the scaled magnitude to segment number. */ - seg = val_seg (pcm_val); - aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f); - } - return aval ^ mask; -} - -#endif /* GST_ALAW_ENC_USE_TABLE */ - -static GstCaps * -gst_alaw_enc_getcaps (GstPad * pad) -{ - GstALawEnc *alawenc; - GstPad *otherpad; - GstCaps *othercaps, *result; - const GstCaps *templ; - gchar *name; - gint i; - - alawenc = GST_ALAW_ENC (GST_PAD_PARENT (pad)); - - /* figure out the name of the caps we are going to return */ - if (pad == alawenc->srcpad) { - name = "audio/x-alaw"; - otherpad = alawenc->sinkpad; - } else { - name = "audio/x-raw-int"; - otherpad = alawenc->srcpad; - } - /* get caps from the peer, this can return NULL when there is no peer */ - othercaps = gst_pad_peer_get_caps (otherpad); - - /* get the template caps to make sure we return something acceptable */ - templ = gst_pad_get_pad_template_caps (pad); - - if (othercaps) { - /* there was a peer */ - othercaps = gst_caps_make_writable (othercaps); - - /* go through the caps and remove the fields we don't want */ - for (i = 0; i < gst_caps_get_size (othercaps); i++) { - GstStructure *structure; - - structure = gst_caps_get_structure (othercaps, i); - - /* adjust the name */ - gst_structure_set_name (structure, name); - - if (pad == alawenc->srcpad) { - /* remove the fields we don't want */ - gst_structure_remove_fields (structure, "width", "depth", "endianness", - "signed", NULL); - } else { - /* add fixed fields */ - gst_structure_set (structure, "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "signed", G_TYPE_BOOLEAN, TRUE, NULL); - } - } - /* filter against the allowed caps of the pad to return our result */ - result = gst_caps_intersect (othercaps, templ); - gst_caps_unref (othercaps); - } else { - /* there was no peer, return the template caps */ - result = gst_caps_copy (templ); - } - - return result; -} - -static gboolean -gst_alaw_enc_setcaps (GstPad * pad, GstCaps * caps) -{ - GstALawEnc *alawenc; - GstPad *otherpad; - GstStructure *structure; - gboolean ret; - GstCaps *base_caps; - - alawenc = GST_ALAW_ENC (GST_PAD_PARENT (pad)); - - structure = gst_caps_get_structure (caps, 0); - gst_structure_get_int (structure, "channels", &alawenc->channels); - gst_structure_get_int (structure, "rate", &alawenc->rate); - - if (pad == alawenc->sinkpad) { - otherpad = alawenc->srcpad; - } else { - otherpad = alawenc->sinkpad; - } - - base_caps = gst_caps_copy (gst_pad_get_pad_template_caps (otherpad)); - structure = gst_caps_get_structure (base_caps, 0); - gst_structure_set (structure, "rate", G_TYPE_INT, alawenc->rate, NULL); - gst_structure_set (structure, "channels", G_TYPE_INT, alawenc->channels, - NULL); - - GST_DEBUG_OBJECT (alawenc, "rate=%d, channels=%d", alawenc->rate, - alawenc->channels); - - ret = gst_pad_set_caps (otherpad, base_caps); - - gst_caps_unref (base_caps); - - return ret; -} - -static void -gst_alaw_enc_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&alaw_enc_src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&alaw_enc_sink_factory)); - - gst_element_class_set_details_simple (element_class, - "A Law audio encoder", "Codec/Encoder/Audio", - "Convert 16bit PCM to 8bit A law", - "Zaheer Abbas Merali "); - - GST_DEBUG_CATEGORY_INIT (alaw_enc_debug, "alawenc", 0, "A Law audio encoder"); -} - -static void -gst_alaw_enc_class_init (GstALawEncClass * klass) -{ - /* nothing to do here for now */ -} - -static void -gst_alaw_enc_init (GstALawEnc * alawenc, GstALawEncClass * klass) -{ - alawenc->sinkpad = - gst_pad_new_from_static_template (&alaw_enc_sink_factory, "sink"); - gst_pad_set_setcaps_function (alawenc->sinkpad, - GST_DEBUG_FUNCPTR (gst_alaw_enc_setcaps)); - gst_pad_set_getcaps_function (alawenc->sinkpad, - GST_DEBUG_FUNCPTR (gst_alaw_enc_getcaps)); - gst_pad_set_chain_function (alawenc->sinkpad, - GST_DEBUG_FUNCPTR (gst_alaw_enc_chain)); - gst_element_add_pad (GST_ELEMENT (alawenc), alawenc->sinkpad); - - alawenc->srcpad = - gst_pad_new_from_static_template (&alaw_enc_src_factory, "src"); - gst_pad_set_setcaps_function (alawenc->srcpad, - GST_DEBUG_FUNCPTR (gst_alaw_enc_setcaps)); - gst_pad_set_getcaps_function (alawenc->srcpad, - GST_DEBUG_FUNCPTR (gst_alaw_enc_getcaps)); - gst_pad_use_fixed_caps (alawenc->srcpad); - gst_element_add_pad (GST_ELEMENT (alawenc), alawenc->srcpad); - - /* init rest */ - alawenc->channels = 0; - alawenc->rate = 0; -} - -static GstFlowReturn -gst_alaw_enc_chain (GstPad * pad, GstBuffer * buffer) -{ - GstALawEnc *alawenc; - gint16 *linear_data; - guint linear_size; - guint8 *alaw_data; - guint alaw_size; - GstBuffer *outbuf; - gint i; - GstFlowReturn ret; - GstClockTime timestamp, duration; - - alawenc = GST_ALAW_ENC (GST_PAD_PARENT (pad)); - - if (G_UNLIKELY (alawenc->rate == 0 || alawenc->channels == 0)) - goto not_negotiated; - - linear_data = (gint16 *) GST_BUFFER_DATA (buffer); - linear_size = GST_BUFFER_SIZE (buffer); - - alaw_size = linear_size / 2; - - timestamp = GST_BUFFER_TIMESTAMP (buffer); - duration = GST_BUFFER_DURATION (buffer); - - GST_LOG_OBJECT (alawenc, "buffer with ts=%" GST_TIME_FORMAT, - GST_TIME_ARGS (timestamp)); - - ret = - gst_pad_alloc_buffer_and_set_caps (alawenc->srcpad, - GST_BUFFER_OFFSET_NONE, alaw_size, GST_PAD_CAPS (alawenc->srcpad), - &outbuf); - if (ret != GST_FLOW_OK) - goto done; - - if (duration == GST_CLOCK_TIME_NONE) { - duration = gst_util_uint64_scale_int (alaw_size, - GST_SECOND, alawenc->rate * alawenc->channels); - } - - if (GST_BUFFER_SIZE (outbuf) < alaw_size) { - /* pad-alloc can return a smaller buffer */ - gst_buffer_unref (outbuf); - outbuf = gst_buffer_new_and_alloc (alaw_size); - } - - alaw_data = (guint8 *) GST_BUFFER_DATA (outbuf); - - /* copy discont flag */ - if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - - GST_BUFFER_TIMESTAMP (outbuf) = timestamp; - GST_BUFFER_DURATION (outbuf) = duration; - - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (alawenc->srcpad)); - - for (i = 0; i < alaw_size; i++) { - alaw_data[i] = s16_to_alaw (linear_data[i]); - } - - ret = gst_pad_push (alawenc->srcpad, outbuf); - -done: - - gst_buffer_unref (buffer); - - return ret; - -not_negotiated: - { - ret = GST_FLOW_NOT_NEGOTIATED; - goto done; - } -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/law/alaw-encode.h --- a/gst_plugins_good/gst/law/alaw-encode.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* GStreamer PCM to A-Law conversion - * Copyright (C) 2000 by Abramo Bagnara - * - * 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. - */ - - -#ifndef __GST_ALAW_ENCODE_H__ -#define __GST_ALAW_ENCODE_H__ - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_ALAW_ENC \ - (gst_alaw_enc_get_type()) -#define GST_ALAW_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALAW_ENC,GstALawEnc)) -#define GST_ALAW_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALAW_ENC,GstALawEncClass)) -#define GST_IS_ALAW_ENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALAW_ENC)) -#define GST_IS_ALAW_ENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALAW_ENC)) - -typedef struct _GstALawEnc GstALawEnc; -typedef struct _GstALawEncClass GstALawEncClass; - -struct _GstALawEnc { - GstElement element; - - GstPad *sinkpad,*srcpad; - - gint channels; - gint rate; -}; - -struct _GstALawEncClass { - GstElementClass parent_class; -}; -#ifdef __SYMBIAN32__ -IMPORT_C -#endif - -GType gst_alaw_enc_get_type(void); - -G_END_DECLS - -#endif /* __GST_ALAW_ENCODE_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/law/alaw.c --- a/gst_plugins_good/gst/law/alaw.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* GStreamer PCM/A-Law conversions - * - * 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.1 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "alaw-encode.h" -#include "alaw-decode.h" - -GstStaticPadTemplate alaw_dec_src_factory = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "rate = (int) [ 8000, 192000 ], " - "channels = (int) [ 1, 2 ], " - "endianness = (int) BYTE_ORDER, " - "width = (int) 16, " "depth = (int) 16, " "signed = (boolean) True") - ); - -GstStaticPadTemplate alaw_dec_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-alaw, " - "rate = [ 8000 , 192000 ], " "channels = [ 1 , 2 ]") - ); - -GstStaticPadTemplate alaw_enc_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "rate = (int) [ 8000, 192000 ], " - "channels = (int) [ 1, 2 ], " - "endianness = (int) BYTE_ORDER, " - "width = (int) 16, " "depth = (int) 16, " "signed = (boolean) True") - ); - -GstStaticPadTemplate alaw_enc_src_factory = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-alaw, " - "rate = [ 8000 , 192000 ], " "channels = [ 1 , 2 ]") - ); - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "alawenc", - GST_RANK_NONE, GST_TYPE_ALAW_ENC) || - !gst_element_register (plugin, "alawdec", - GST_RANK_PRIMARY, GST_TYPE_ALAW_DEC)) - return FALSE; - - return TRUE; -} - -/* FIXME 0.11: merge alaw and mulaw into one plugin? */ -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "alaw", - "ALaw audio conversion routines", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) - - -EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC() -{ - return &gst_plugin_desc; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/law/mulaw-conversion.c --- a/gst_plugins_good/gst/law/mulaw-conversion.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -/* - * This routine converts from linear to ulaw - * 29 September 1989 - * - * Craig Reese: IDA/Supercomputing Research Center - * Joe Campbell: Department of Defense - * - * References: - * 1) CCITT Recommendation G.711 (very difficult to follow) - * 2) "A New Digital Technique for Implementation of Any - * Continuous PCM Companding Law," Villeret, Michel, - * et al. 1973 IEEE Int. Conf. on Communications, Vol 1, - * 1973, pg. 11.12-11.17 - * 3) MIL-STD-188-113,"Interoperability and Performance Standards - * for Analog-to_Digital Conversion Techniques," - * 17 February 1987 - * - * Input: Signed 16 bit linear sample - * Output: 8 bit ulaw sample - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#undef ZEROTRAP /* turn on the trap as per the MIL-STD */ -#define BIAS 0x84 /* define the add-in bias for 16 bit samples */ -#define CLIP 32635 - -void -mulaw_encode (gint16 * in, guint8 * out, gint numsamples) -{ - static gint16 exp_lut[256] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - }; - gint16 sign, exponent, mantissa, i; - gint16 sample; - guint8 ulawbyte; - - for (i = 0; i < numsamples; i++) { - sample = in[i]; - /** get the sample into sign-magnitude **/ - sign = (sample >> 8) & 0x80; /* set aside the sign */ - if (sign != 0) { - sample = -sample; /* get magnitude */ - } - /* sample can be zero because we can overflow in the inversion, - * checking against the unsigned version solves this */ - if (((guint16) sample) > CLIP) - sample = CLIP; /* clip the magnitude */ - - /** convert from 16 bit linear to ulaw **/ - sample = sample + BIAS; - exponent = exp_lut[(sample >> 7) & 0xFF]; - mantissa = (sample >> (exponent + 3)) & 0x0F; - ulawbyte = ~(sign | (exponent << 4) | mantissa); -#ifdef ZEROTRAP - if (ulawbyte == 0) - ulawbyte = 0x02; /* optional CCITT trap */ -#endif - out[i] = ulawbyte; - } -} - -/* - * This routine converts from ulaw to 16 bit linear - * 29 September 1989 - * - * Craig Reese: IDA/Supercomputing Research Center - * - * References: - * 1) CCITT Recommendation G.711 (very difficult to follow) - * 2) MIL-STD-188-113,"Interoperability and Performance Standards - * for Analog-to_Digital Conversion Techniques," - * 17 February 1987 - * - * Input: 8 bit ulaw sample - * Output: signed 16 bit linear sample - */ - -void -mulaw_decode (guint8 * in, gint16 * out, gint numsamples) -{ - static gint16 exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 }; - gint16 sign, exponent, mantissa; - guint8 ulawbyte; - gint16 linear, i; - - for (i = 0; i < numsamples; i++) { - ulawbyte = in[i]; - ulawbyte = ~ulawbyte; - sign = (ulawbyte & 0x80); - exponent = (ulawbyte >> 4) & 0x07; - mantissa = ulawbyte & 0x0F; - linear = exp_lut[exponent] + (mantissa << (exponent + 3)); - if (sign != 0) - linear = -linear; - out[i] = linear; - } -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/law/mulaw-conversion.h --- a/gst_plugins_good/gst/law/mulaw-conversion.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -#ifndef _GST_ULAW_CONVERSION_H -#define _GST_ULAW_CONVERSION_H - -#include - -void -mulaw_encode(gint16* in, guint8* out, gint numsamples); -void -mulaw_decode(guint8* in,gint16* out,gint numsamples); - -#endif /* _GST_ULAW_CONVERSION_H */ - diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/law/mulaw-decode.c --- a/gst_plugins_good/gst/law/mulaw-decode.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,309 +0,0 @@ -/* GStreamer - * 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. - */ -/** - * SECTION:element-mulawdec - * - * This element decodes mulaw audio. Mulaw coding is also known as G.711. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include "mulaw-decode.h" -#include "mulaw-conversion.h" - -extern GstStaticPadTemplate mulaw_dec_src_factory; -extern GstStaticPadTemplate mulaw_dec_sink_factory; - -/* Stereo signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - ARG_0 -}; - -static void gst_mulawdec_class_init (GstMuLawDecClass * klass); -static void gst_mulawdec_base_init (GstMuLawDecClass * klass); -static void gst_mulawdec_init (GstMuLawDec * mulawdec); -static GstStateChangeReturn -gst_mulawdec_change_state (GstElement * element, GstStateChange transition); - -static GstFlowReturn gst_mulawdec_chain (GstPad * pad, GstBuffer * buffer); - -static GstElementClass *parent_class = NULL; - -static gboolean -mulawdec_sink_setcaps (GstPad * pad, GstCaps * caps) -{ - GstMuLawDec *mulawdec; - GstStructure *structure; - int rate, channels; - gboolean ret; - GstCaps *outcaps; - - mulawdec = GST_MULAWDEC (GST_PAD_PARENT (pad)); - - structure = gst_caps_get_structure (caps, 0); - ret = gst_structure_get_int (structure, "rate", &rate); - ret = ret && gst_structure_get_int (structure, "channels", &channels); - if (!ret) - return FALSE; - - outcaps = gst_caps_new_simple ("audio/x-raw-int", - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "signed", G_TYPE_BOOLEAN, TRUE, - "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL); - ret = gst_pad_set_caps (mulawdec->srcpad, outcaps); - gst_caps_unref (outcaps); - - if (ret) { - GST_DEBUG_OBJECT (mulawdec, "rate=%d, channels=%d", rate, channels); - mulawdec->rate = rate; - mulawdec->channels = channels; - } - return ret; -} - -static GstCaps * -mulawdec_getcaps (GstPad * pad) -{ - GstMuLawDec *mulawdec; - GstPad *otherpad; - GstCaps *othercaps, *result; - const GstCaps *templ; - gchar *name; - gint i; - - mulawdec = GST_MULAWDEC (GST_PAD_PARENT (pad)); - - /* figure out the name of the caps we are going to return */ - if (pad == mulawdec->srcpad) { - name = "audio/x-raw-int"; - otherpad = mulawdec->sinkpad; - } else { - name = "audio/x-mulaw"; - otherpad = mulawdec->srcpad; - } - /* get caps from the peer, this can return NULL when there is no peer */ - othercaps = gst_pad_peer_get_caps (otherpad); - - /* get the template caps to make sure we return something acceptable */ - templ = gst_pad_get_pad_template_caps (pad); - - if (othercaps) { - /* there was a peer */ - othercaps = gst_caps_make_writable (othercaps); - - /* go through the caps and remove the fields we don't want */ - for (i = 0; i < gst_caps_get_size (othercaps); i++) { - GstStructure *structure; - - structure = gst_caps_get_structure (othercaps, i); - - /* adjust the name */ - gst_structure_set_name (structure, name); - - if (pad == mulawdec->sinkpad) { - /* remove the fields we don't want */ - gst_structure_remove_fields (structure, "width", "depth", "endianness", - "signed", NULL); - } else { - /* add fixed fields */ - gst_structure_set (structure, "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "signed", G_TYPE_BOOLEAN, TRUE, NULL); - } - } - /* filter against the allowed caps of the pad to return our result */ - result = gst_caps_intersect (othercaps, templ); - gst_caps_unref (othercaps); - } else { - /* there was no peer, return the template caps */ - result = gst_caps_copy (templ); - } - return result; -} - -GType -gst_mulawdec_get_type (void) -{ - static GType mulawdec_type = 0; - - if (!mulawdec_type) { - static const GTypeInfo mulawdec_info = { - sizeof (GstMuLawDecClass), - (GBaseInitFunc) gst_mulawdec_base_init, - NULL, - (GClassInitFunc) gst_mulawdec_class_init, - NULL, - NULL, - sizeof (GstMuLawDec), - 0, - (GInstanceInitFunc) gst_mulawdec_init, - }; - - mulawdec_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstMuLawDec", &mulawdec_info, - 0); - } - return mulawdec_type; -} - -static void -gst_mulawdec_base_init (GstMuLawDecClass * klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - const GstElementDetails mulawdec_details = - GST_ELEMENT_DETAILS ("Mu Law audio decoder", - "Codec/Decoder/Audio", - "Convert 8bit mu law to 16bit PCM", - "Zaheer Abbas Merali "); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&mulaw_dec_src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&mulaw_dec_sink_factory)); - gst_element_class_set_details (element_class, &mulawdec_details); -} - -static void -gst_mulawdec_class_init (GstMuLawDecClass * klass) -{ - GstElementClass *element_class = (GstElementClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - element_class->change_state = GST_DEBUG_FUNCPTR (gst_mulawdec_change_state); -} - -static void -gst_mulawdec_init (GstMuLawDec * mulawdec) -{ - mulawdec->sinkpad = - gst_pad_new_from_static_template (&mulaw_dec_sink_factory, "sink"); - gst_pad_set_setcaps_function (mulawdec->sinkpad, mulawdec_sink_setcaps); - gst_pad_set_getcaps_function (mulawdec->sinkpad, mulawdec_getcaps); - gst_pad_set_chain_function (mulawdec->sinkpad, gst_mulawdec_chain); - gst_element_add_pad (GST_ELEMENT (mulawdec), mulawdec->sinkpad); - - mulawdec->srcpad = - gst_pad_new_from_static_template (&mulaw_dec_src_factory, "src"); - gst_pad_use_fixed_caps (mulawdec->srcpad); - gst_pad_set_getcaps_function (mulawdec->srcpad, mulawdec_getcaps); - gst_element_add_pad (GST_ELEMENT (mulawdec), mulawdec->srcpad); -} - -static GstFlowReturn -gst_mulawdec_chain (GstPad * pad, GstBuffer * buffer) -{ - GstMuLawDec *mulawdec; - gint16 *linear_data; - guint8 *mulaw_data; - guint mulaw_size; - GstBuffer *outbuf; - GstFlowReturn ret; - - mulawdec = GST_MULAWDEC (GST_PAD_PARENT (pad)); - - if (G_UNLIKELY (mulawdec->rate == 0)) - goto not_negotiated; - - mulaw_data = (guint8 *) GST_BUFFER_DATA (buffer); - mulaw_size = GST_BUFFER_SIZE (buffer); - - ret = - gst_pad_alloc_buffer_and_set_caps (mulawdec->srcpad, - GST_BUFFER_OFFSET_NONE, mulaw_size * 2, GST_PAD_CAPS (mulawdec->srcpad), - &outbuf); - if (ret != GST_FLOW_OK) - goto alloc_failed; - - linear_data = (gint16 *) GST_BUFFER_DATA (outbuf); - - /* copy discont flag */ - if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - - GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer); - if (GST_BUFFER_DURATION (outbuf) == GST_CLOCK_TIME_NONE) - GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (GST_SECOND, - mulaw_size * 2, 2 * mulawdec->rate * mulawdec->channels); - else - GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer); - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (mulawdec->srcpad)); - - mulaw_decode (mulaw_data, linear_data, mulaw_size); - - gst_buffer_unref (buffer); - - ret = gst_pad_push (mulawdec->srcpad, outbuf); - - return ret; - - /* ERRORS */ -not_negotiated: - { - GST_WARNING_OBJECT (mulawdec, "no input format set: not-negotiated"); - gst_buffer_unref (buffer); - return GST_FLOW_NOT_NEGOTIATED; - } -alloc_failed: - { - GST_DEBUG_OBJECT (mulawdec, "pad alloc failed, flow: %s", - gst_flow_get_name (ret)); - gst_buffer_unref (buffer); - return ret; - } -} - -static GstStateChangeReturn -gst_mulawdec_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret; - GstMuLawDec *dec = GST_MULAWDEC (element); - - switch (transition) { - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret != GST_STATE_CHANGE_SUCCESS) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - dec->rate = 0; - dec->channels = 0; - break; - default: - break; - } - - return ret; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/law/mulaw-decode.h --- a/gst_plugins_good/gst/law/mulaw-decode.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* GStreamer - * 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. - */ - -#ifndef __GST_MULAWDECODE_H__ -#define __GST_MULAWDECODE_H__ - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_MULAWDEC \ - (gst_mulawdec_get_type()) -#define GST_MULAWDEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULAWDEC,GstMuLawDec)) -#define GST_MULAWDEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULAWDEC,GstMuLawDecClass)) -#define GST_IS_MULAWDEC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULAWDEC)) -#define GST_IS_MULAWDEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULAWDEC)) - -typedef struct _GstMuLawDec GstMuLawDec; -typedef struct _GstMuLawDecClass GstMuLawDecClass; - -struct _GstMuLawDec { - GstElement element; - - GstPad *sinkpad,*srcpad; - - gint rate; - gint channels; -}; - -struct _GstMuLawDecClass { - GstElementClass parent_class; -}; - -GType gst_mulawdec_get_type(void); - -G_END_DECLS - -#endif /* __GST_STEREO_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/law/mulaw-encode.c --- a/gst_plugins_good/gst/law/mulaw-encode.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,299 +0,0 @@ -/* GStreamer - * 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. - */ -/** - * SECTION:element-mulawenc - * - * This element encode mulaw audio. Mulaw coding is also known as G.711. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include -#include "mulaw-encode.h" -#include "mulaw-conversion.h" - -extern GstStaticPadTemplate mulaw_enc_src_factory; -extern GstStaticPadTemplate mulaw_enc_sink_factory; - -/* Stereo signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - ARG_0 -}; - -static void gst_mulawenc_class_init (GstMuLawEncClass * klass); -static void gst_mulawenc_base_init (GstMuLawEncClass * klass); -static void gst_mulawenc_init (GstMuLawEnc * mulawenc); - -static GstFlowReturn gst_mulawenc_chain (GstPad * pad, GstBuffer * buffer); - -static GstElementClass *parent_class = NULL; - -/*static guint gst_stereo_signals[LAST_SIGNAL] = { 0 }; */ - -static GstCaps * -mulawenc_getcaps (GstPad * pad) -{ - GstMuLawEnc *mulawenc; - GstPad *otherpad; - GstCaps *othercaps, *result; - const GstCaps *templ; - gchar *name; - gint i; - - mulawenc = GST_MULAWENC (GST_PAD_PARENT (pad)); - - /* figure out the name of the caps we are going to return */ - if (pad == mulawenc->srcpad) { - name = "audio/x-mulaw"; - otherpad = mulawenc->sinkpad; - } else { - name = "audio/x-raw-int"; - otherpad = mulawenc->srcpad; - } - /* get caps from the peer, this can return NULL when there is no peer */ - othercaps = gst_pad_peer_get_caps (otherpad); - - /* get the template caps to make sure we return something acceptable */ - templ = gst_pad_get_pad_template_caps (pad); - - if (othercaps) { - /* there was a peer */ - othercaps = gst_caps_make_writable (othercaps); - - /* go through the caps and remove the fields we don't want */ - for (i = 0; i < gst_caps_get_size (othercaps); i++) { - GstStructure *structure; - - structure = gst_caps_get_structure (othercaps, i); - - /* adjust the name */ - gst_structure_set_name (structure, name); - - if (pad == mulawenc->srcpad) { - /* remove the fields we don't want */ - gst_structure_remove_fields (structure, "width", "depth", "endianness", - "signed", NULL); - } else { - /* add fixed fields */ - gst_structure_set (structure, "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "signed", G_TYPE_BOOLEAN, TRUE, NULL); - } - } - /* filter against the allowed caps of the pad to return our result */ - result = gst_caps_intersect (othercaps, templ); - gst_caps_unref (othercaps); - } else { - /* there was no peer, return the template caps */ - result = gst_caps_copy (templ); - } - return result; -} - -static gboolean -mulawenc_setcaps (GstPad * pad, GstCaps * caps) -{ - GstMuLawEnc *mulawenc; - GstPad *otherpad; - GstStructure *structure; - GstCaps *base_caps; - - mulawenc = GST_MULAWENC (gst_pad_get_parent (pad)); - - structure = gst_caps_get_structure (caps, 0); - gst_structure_get_int (structure, "channels", &mulawenc->channels); - gst_structure_get_int (structure, "rate", &mulawenc->rate); - - if (pad == mulawenc->sinkpad) { - otherpad = mulawenc->srcpad; - } else { - otherpad = mulawenc->sinkpad; - } - base_caps = gst_caps_copy (gst_pad_get_pad_template_caps (otherpad)); - - structure = gst_caps_get_structure (base_caps, 0); - gst_structure_set (structure, "rate", G_TYPE_INT, mulawenc->rate, NULL); - gst_structure_set (structure, "channels", G_TYPE_INT, mulawenc->channels, - NULL); - - gst_pad_set_caps (otherpad, base_caps); - - gst_object_unref (mulawenc); - gst_caps_unref (base_caps); - - return TRUE; -} - -GType -gst_mulawenc_get_type (void) -{ - static GType mulawenc_type = 0; - - if (!mulawenc_type) { - static const GTypeInfo mulawenc_info = { - sizeof (GstMuLawEncClass), - (GBaseInitFunc) gst_mulawenc_base_init, - NULL, - (GClassInitFunc) gst_mulawenc_class_init, - NULL, - NULL, - sizeof (GstMuLawEnc), - 0, - (GInstanceInitFunc) gst_mulawenc_init, - }; - - mulawenc_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstMuLawEnc", &mulawenc_info, - 0); - } - return mulawenc_type; -} - -static void -gst_mulawenc_base_init (GstMuLawEncClass * klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - const GstElementDetails mulawenc_details = - GST_ELEMENT_DETAILS ("Mu Law audio encoder", - "Codec/Encoder/Audio", - "Convert 16bit PCM to 8bit mu law", - "Zaheer Abbas Merali "); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&mulaw_enc_src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&mulaw_enc_sink_factory)); - gst_element_class_set_details (element_class, &mulawenc_details); -} - -static void -gst_mulawenc_class_init (GstMuLawEncClass * klass) -{ - parent_class = g_type_class_peek_parent (klass); -} - -static void -gst_mulawenc_init (GstMuLawEnc * mulawenc) -{ - mulawenc->sinkpad = - gst_pad_new_from_static_template (&mulaw_enc_sink_factory, "sink"); - gst_pad_set_setcaps_function (mulawenc->sinkpad, mulawenc_setcaps); - gst_pad_set_getcaps_function (mulawenc->sinkpad, mulawenc_getcaps); - gst_pad_set_chain_function (mulawenc->sinkpad, gst_mulawenc_chain); - gst_element_add_pad (GST_ELEMENT (mulawenc), mulawenc->sinkpad); - - mulawenc->srcpad = - gst_pad_new_from_static_template (&mulaw_enc_src_factory, "src"); - gst_pad_set_setcaps_function (mulawenc->srcpad, mulawenc_setcaps); - gst_pad_set_getcaps_function (mulawenc->srcpad, mulawenc_getcaps); - gst_pad_use_fixed_caps (mulawenc->srcpad); - gst_element_add_pad (GST_ELEMENT (mulawenc), mulawenc->srcpad); - - /* init rest */ - mulawenc->channels = 0; - mulawenc->rate = 0; -} - -static GstFlowReturn -gst_mulawenc_chain (GstPad * pad, GstBuffer * buffer) -{ - GstMuLawEnc *mulawenc; - gint16 *linear_data; - guint linear_size; - guint8 *mulaw_data; - guint mulaw_size; - GstBuffer *outbuf; - GstFlowReturn ret; - GstClockTime timestamp, duration; - - mulawenc = GST_MULAWENC (gst_pad_get_parent (pad)); - - if (!mulawenc->rate || !mulawenc->channels) - goto not_negotiated; - - linear_data = (gint16 *) GST_BUFFER_DATA (buffer); - linear_size = GST_BUFFER_SIZE (buffer); - - mulaw_size = linear_size / 2; - - timestamp = GST_BUFFER_TIMESTAMP (buffer); - duration = GST_BUFFER_DURATION (buffer); - - ret = gst_pad_alloc_buffer_and_set_caps (mulawenc->srcpad, - GST_BUFFER_OFFSET_NONE, mulaw_size, GST_PAD_CAPS (mulawenc->srcpad), - &outbuf); - if (ret != GST_FLOW_OK) - goto alloc_failed; - - if (duration == -1) { - duration = gst_util_uint64_scale_int (mulaw_size, - GST_SECOND, mulawenc->rate * mulawenc->channels); - } - - if (GST_BUFFER_SIZE (outbuf) < mulaw_size) { - /* pad-alloc can suggest a smaller size */ - gst_buffer_unref (outbuf); - outbuf = gst_buffer_new_and_alloc (mulaw_size); - } - - mulaw_data = (guint8 *) GST_BUFFER_DATA (outbuf); - - /* copy discont flag */ - if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - - GST_BUFFER_TIMESTAMP (outbuf) = timestamp; - GST_BUFFER_DURATION (outbuf) = duration; - - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (mulawenc->srcpad)); - - mulaw_encode (linear_data, mulaw_data, mulaw_size); - - gst_buffer_unref (buffer); - - ret = gst_pad_push (mulawenc->srcpad, outbuf); - -done: - gst_object_unref (mulawenc); - - return ret; - -not_negotiated: - { - GST_DEBUG_OBJECT (mulawenc, "no format negotiated"); - ret = GST_FLOW_NOT_NEGOTIATED; - gst_buffer_unref (buffer); - goto done; - } -alloc_failed: - { - GST_DEBUG_OBJECT (mulawenc, "pad alloc failed"); - gst_buffer_unref (buffer); - goto done; - } -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/law/mulaw-encode.h --- a/gst_plugins_good/gst/law/mulaw-encode.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* GStreamer - * 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. - */ - - -#ifndef __GST_MULAWENCODE_H__ -#define __GST_MULAWENCODE_H__ - -#include - -G_BEGIN_DECLS - -#define GST_TYPE_MULAWENC \ - (gst_mulawenc_get_type()) -#define GST_MULAWENC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MULAWENC,GstMuLawEnc)) -#define GST_MULAWENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULAWENC,GstMuLawEncClass)) -#define GST_IS_MULAWENC(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULAWENC)) -#define GST_IS_MULAWENC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULAWENC)) - -typedef struct _GstMuLawEnc GstMuLawEnc; -typedef struct _GstMuLawEncClass GstMuLawEncClass; - -struct _GstMuLawEnc { - GstElement element; - - GstPad *sinkpad,*srcpad; - - gint channels; - gint rate; -}; - -struct _GstMuLawEncClass { - GstElementClass parent_class; -}; - -GType gst_mulawenc_get_type(void); - -G_END_DECLS - -#endif /* __GST_STEREO_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/law/mulaw.c --- a/gst_plugins_good/gst/law/mulaw.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/* GStreamer PCM/A-Law conversions - * - * 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.1 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "mulaw-encode.h" -#include "mulaw-decode.h" - -GstStaticPadTemplate mulaw_dec_src_factory = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "rate = (int) [ 8000, 192000 ], " - "channels = (int) [ 1, 2 ], " - "endianness = (int) BYTE_ORDER, " - "width = (int) 16, " "depth = (int) 16, " "signed = (boolean) True") - ); - -GstStaticPadTemplate mulaw_dec_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-mulaw, " - "rate = [ 8000 , 192000 ], " "channels = [ 1 , 2 ]") - ); - -GstStaticPadTemplate mulaw_enc_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "rate = (int) [ 8000, 192000 ], " - "channels = (int) [ 1, 2 ], " - "endianness = (int) BYTE_ORDER, " - "width = (int) 16, " "depth = (int) 16, " "signed = (boolean) True") - ); - -GstStaticPadTemplate mulaw_enc_src_factory = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-mulaw, " - "rate = [ 8000 , 192000 ], " "channels = [ 1 , 2 ]") - ); - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "mulawenc", - GST_RANK_NONE, GST_TYPE_MULAWENC) || - !gst_element_register (plugin, "mulawdec", - GST_RANK_PRIMARY, GST_TYPE_MULAWDEC)) - return FALSE; - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "mulaw", - "MuLaw audio conversion routines", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) - - -EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC() -{ - return &gst_plugin_desc; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/mpegaudioparse/gstmpegaudioparse.c --- a/gst_plugins_good/gst/mpegaudioparse/gstmpegaudioparse.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2199 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2006-2007> Jan Schmidt - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "../../config.h" -#endif - -#include - -#include "gstmpegaudioparse.h" - -GST_DEBUG_CATEGORY_STATIC (mp3parse_debug); -#define GST_CAT_DEFAULT mp3parse_debug - -#define MP3_CHANNEL_MODE_UNKNOWN -1 -#define MP3_CHANNEL_MODE_STEREO 0 -#define MP3_CHANNEL_MODE_JOINT_STEREO 1 -#define MP3_CHANNEL_MODE_DUAL_CHANNEL 2 -#define MP3_CHANNEL_MODE_MONO 3 - -#define CRC_UNKNOWN -1 -#define CRC_PROTECTED 0 -#define CRC_NOT_PROTECTED 1 - -#define XING_FRAMES_FLAG 0x0001 -#define XING_BYTES_FLAG 0x0002 -#define XING_TOC_FLAG 0x0004 -#define XING_VBR_SCALE_FLAG 0x0008 - -#ifndef GST_READ_UINT24_BE -#define GST_READ_UINT24_BE(p) (p[2] | (p[1] << 8) | (p[0] << 16)) -#endif - -/* Minimum number of consecutive, valid-looking frames to consider - for resyncing */ -#define MIN_RESYNC_FRAMES 3 - -static inline MPEGAudioSeekEntry * -mpeg_audio_seek_entry_new () -{ - return g_slice_new (MPEGAudioSeekEntry); -} - -static inline void -mpeg_audio_seek_entry_free (MPEGAudioSeekEntry * entry) -{ - g_slice_free (MPEGAudioSeekEntry, entry); -} - -/* elementfactory information */ -static GstElementDetails mp3parse_details = { - "MPEG1 Audio Parser", - "Codec/Parser/Audio", - "Parses and frames mpeg1 audio streams (levels 1-3), provides seek", - "Jan Schmidt \n" - "Erik Walthinsen " -}; - -static GstStaticPadTemplate mp3_src_template = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/mpeg, " - "mpegversion = (int) 1, " - "layer = (int) [ 1, 3 ], " - "rate = (int) [ 8000, 48000 ], channels = (int) [ 1, 2 ]," - "parsed=(boolean) true") - ); - -static GstStaticPadTemplate mp3_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/mpeg, mpegversion = (int) 1, parsed=(boolean)false") - ); - -/* GstMPEGAudioParse signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - ARG_0, - ARG_SKIP, - ARG_BIT_RATE - /* FILL ME */ -}; - - -static void gst_mp3parse_class_init (GstMPEGAudioParseClass * klass); -static void gst_mp3parse_base_init (gpointer klass); -static void gst_mp3parse_init (GstMPEGAudioParse * mp3parse, - GstMPEGAudioParseClass * klass); - -static gboolean gst_mp3parse_sink_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_mp3parse_chain (GstPad * pad, GstBuffer * buffer); -static gboolean mp3parse_src_query (GstPad * pad, GstQuery * query); -static const GstQueryType *mp3parse_get_query_types (GstPad * pad); -static gboolean mp3parse_src_event (GstPad * pad, GstEvent * event); - -static int head_check (GstMPEGAudioParse * mp3parse, unsigned long head); - -static void gst_mp3parse_dispose (GObject * object); -static void gst_mp3parse_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_mp3parse_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); -static GstStateChangeReturn gst_mp3parse_change_state (GstElement * element, - GstStateChange transition); -static GstFlowReturn -gst_mp3parse_handle_data (GstMPEGAudioParse * mp3parse, gboolean at_eos); - -static gboolean mp3parse_bytepos_to_time (GstMPEGAudioParse * mp3parse, - gint64 bytepos, GstClockTime * ts, gboolean from_total_time); -static gboolean -mp3parse_total_bytes (GstMPEGAudioParse * mp3parse, gint64 * total); -static gboolean -mp3parse_total_time (GstMPEGAudioParse * mp3parse, GstClockTime * total); - -GST_BOILERPLATE (GstMPEGAudioParse, gst_mp3parse, GstElement, GST_TYPE_ELEMENT); - -#define GST_TYPE_MP3_CHANNEL_MODE (gst_mp3_channel_mode_get_type()) - -static const GEnumValue mp3_channel_mode[] = { - {MP3_CHANNEL_MODE_UNKNOWN, "Unknown", "unknown"}, - {MP3_CHANNEL_MODE_MONO, "Mono", "mono"}, - {MP3_CHANNEL_MODE_DUAL_CHANNEL, "Dual Channel", "dual-channel"}, - {MP3_CHANNEL_MODE_JOINT_STEREO, "Joint Stereo", "joint-stereo"}, - {MP3_CHANNEL_MODE_STEREO, "Stereo", "stereo"}, - {0, NULL, NULL}, -}; - -static GType -gst_mp3_channel_mode_get_type (void) -{ - static GType mp3_channel_mode_type = 0; - - if (!mp3_channel_mode_type) { - mp3_channel_mode_type = - g_enum_register_static ("GstMp3ChannelMode", mp3_channel_mode); - } - return mp3_channel_mode_type; -} - -static const gchar * -gst_mp3_channel_mode_get_nick (gint mode) -{ - guint i; - for (i = 0; i < G_N_ELEMENTS (mp3_channel_mode); i++) { - if (mp3_channel_mode[i].value == mode) - return mp3_channel_mode[i].value_nick; - } - return NULL; -} - -static const guint mp3types_bitrates[2][3][16] = { - { - {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,}, - {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,}, - {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,} - }, - { - {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,}, - {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}, - {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,} - }, -}; - -static const guint mp3types_freqs[3][3] = { {44100, 48000, 32000}, -{22050, 24000, 16000}, -{11025, 12000, 8000} -}; - -static inline guint -mp3_type_frame_length_from_header (GstMPEGAudioParse * mp3parse, guint32 header, - guint * put_version, guint * put_layer, guint * put_channels, - guint * put_bitrate, guint * put_samplerate, guint * put_mode, - guint * put_crc) -{ - guint length; - gulong mode, samplerate, bitrate, layer, channels, padding, crc; - gulong version; - gint lsf, mpg25; - - if (header & (1 << 20)) { - lsf = (header & (1 << 19)) ? 0 : 1; - mpg25 = 0; - } else { - lsf = 1; - mpg25 = 1; - } - - version = 1 + lsf + mpg25; - - layer = 4 - ((header >> 17) & 0x3); - - crc = (header >> 16) & 0x1; - - bitrate = (header >> 12) & 0xF; - bitrate = mp3types_bitrates[lsf][layer - 1][bitrate] * 1000; - /* The caller has ensured we have a valid header, so bitrate can't be - zero here. */ - g_assert (bitrate != 0); - - samplerate = (header >> 10) & 0x3; - samplerate = mp3types_freqs[lsf + mpg25][samplerate]; - - padding = (header >> 9) & 0x1; - - mode = (header >> 6) & 0x3; - channels = (mode == 3) ? 1 : 2; - - switch (layer) { - case 1: - length = 4 * ((bitrate * 12) / samplerate + padding); - break; - case 2: - length = (bitrate * 144) / samplerate + padding; - break; - default: - case 3: - length = (bitrate * 144) / (samplerate << lsf) + padding; - break; - } - - GST_DEBUG_OBJECT (mp3parse, "Calculated mp3 frame length of %u bytes", - length); - GST_DEBUG_OBJECT (mp3parse, "samplerate = %lu, bitrate = %lu, version = %lu, " - "layer = %lu, channels = %lu, mode = %s", samplerate, bitrate, version, - layer, channels, gst_mp3_channel_mode_get_nick (mode)); - - if (put_version) - *put_version = version; - if (put_layer) - *put_layer = layer; - if (put_channels) - *put_channels = channels; - if (put_bitrate) - *put_bitrate = bitrate; - if (put_samplerate) - *put_samplerate = samplerate; - if (put_mode) - *put_mode = mode; - if (put_crc) - *put_crc = crc; - - return length; -} - -static GstCaps * -mp3_caps_create (guint version, guint layer, guint channels, guint samplerate) -{ - GstCaps *new; - - g_assert (version); - g_assert (layer); - g_assert (samplerate); - g_assert (channels); - - new = gst_caps_new_simple ("audio/mpeg", - "mpegversion", G_TYPE_INT, 1, - "mpegaudioversion", G_TYPE_INT, version, - "layer", G_TYPE_INT, layer, - "rate", G_TYPE_INT, samplerate, - "channels", G_TYPE_INT, channels, "parsed", G_TYPE_BOOLEAN, TRUE, NULL); - - return new; -} - -static void -gst_mp3parse_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&mp3_sink_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&mp3_src_template)); - - GST_DEBUG_CATEGORY_INIT (mp3parse_debug, "mp3parse", 0, "MPEG Audio Parser"); - - gst_element_class_set_details (element_class, &mp3parse_details); -} - -static void -gst_mp3parse_class_init (GstMPEGAudioParseClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->set_property = gst_mp3parse_set_property; - gobject_class->get_property = gst_mp3parse_get_property; - gobject_class->dispose = gst_mp3parse_dispose; - - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SKIP, - g_param_spec_int ("skip", "skip", "skip", - G_MININT, G_MAXINT, 0, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BIT_RATE, - g_param_spec_int ("bitrate", "Bitrate", "Bit Rate", - G_MININT, G_MAXINT, 0, G_PARAM_READABLE)); - - gstelement_class->change_state = gst_mp3parse_change_state; - -/* register tags */ -#define GST_TAG_CRC "has-crc" -#define GST_TAG_MODE "channel-mode" - - gst_tag_register (GST_TAG_CRC, GST_TAG_FLAG_META, G_TYPE_BOOLEAN, - "has crc", "Using CRC", NULL); - gst_tag_register (GST_TAG_MODE, GST_TAG_FLAG_ENCODED, G_TYPE_STRING, - "channel mode", "MPEG audio channel mode", NULL); - - g_type_class_ref (GST_TYPE_MP3_CHANNEL_MODE); -} - -static void -gst_mp3parse_reset (GstMPEGAudioParse * mp3parse) -{ - mp3parse->skip = 0; - mp3parse->resyncing = TRUE; - mp3parse->next_ts = GST_CLOCK_TIME_NONE; - mp3parse->cur_offset = -1; - - mp3parse->sync_offset = 0; - mp3parse->tracked_offset = 0; - mp3parse->pending_ts = GST_CLOCK_TIME_NONE; - mp3parse->pending_offset = -1; - - gst_adapter_clear (mp3parse->adapter); - - mp3parse->rate = mp3parse->channels = mp3parse->layer = -1; - mp3parse->version = 1; - mp3parse->max_bitreservoir = GST_CLOCK_TIME_NONE; - - mp3parse->avg_bitrate = 0; - mp3parse->bitrate_sum = 0; - mp3parse->last_posted_bitrate = 0; - mp3parse->frame_count = 0; - mp3parse->sent_codec_tag = FALSE; - - mp3parse->last_posted_crc = CRC_UNKNOWN; - mp3parse->last_posted_channel_mode = MP3_CHANNEL_MODE_UNKNOWN; - - mp3parse->xing_flags = 0; - mp3parse->xing_bitrate = 0; - mp3parse->xing_frames = 0; - mp3parse->xing_total_time = 0; - mp3parse->xing_bytes = 0; - mp3parse->xing_vbr_scale = 0; - memset (mp3parse->xing_seek_table, 0, 100); - memset (mp3parse->xing_seek_table_inverse, 0, 256); - - mp3parse->vbri_bitrate = 0; - mp3parse->vbri_frames = 0; - mp3parse->vbri_total_time = 0; - mp3parse->vbri_bytes = 0; - mp3parse->vbri_seek_points = 0; - g_free (mp3parse->vbri_seek_table); - mp3parse->vbri_seek_table = NULL; - - if (mp3parse->seek_table) { - g_list_foreach (mp3parse->seek_table, (GFunc) mpeg_audio_seek_entry_free, - NULL); - g_list_free (mp3parse->seek_table); - mp3parse->seek_table = NULL; - } - - g_mutex_lock (mp3parse->pending_seeks_lock); - if (mp3parse->pending_accurate_seeks) { - g_slist_foreach (mp3parse->pending_accurate_seeks, (GFunc) g_free, NULL); - g_slist_free (mp3parse->pending_accurate_seeks); - mp3parse->pending_accurate_seeks = NULL; - } - if (mp3parse->pending_nonaccurate_seeks) { - g_slist_foreach (mp3parse->pending_nonaccurate_seeks, (GFunc) g_free, NULL); - g_slist_free (mp3parse->pending_nonaccurate_seeks); - mp3parse->pending_nonaccurate_seeks = NULL; - } - g_mutex_unlock (mp3parse->pending_seeks_lock); - - if (mp3parse->pending_segment) { - GstEvent **eventp = &mp3parse->pending_segment; - - gst_event_replace (eventp, NULL); - } - - mp3parse->exact_position = FALSE; - gst_segment_init (&mp3parse->segment, GST_FORMAT_TIME); -} - -static void -gst_mp3parse_init (GstMPEGAudioParse * mp3parse, GstMPEGAudioParseClass * klass) -{ - mp3parse->sinkpad = - gst_pad_new_from_static_template (&mp3_sink_template, "sink"); - gst_pad_set_event_function (mp3parse->sinkpad, gst_mp3parse_sink_event); - gst_pad_set_chain_function (mp3parse->sinkpad, gst_mp3parse_chain); - gst_element_add_pad (GST_ELEMENT (mp3parse), mp3parse->sinkpad); - - mp3parse->srcpad = - gst_pad_new_from_static_template (&mp3_src_template, "src"); - gst_pad_use_fixed_caps (mp3parse->srcpad); - gst_pad_set_event_function (mp3parse->srcpad, mp3parse_src_event); - gst_pad_set_query_function (mp3parse->srcpad, mp3parse_src_query); - gst_pad_set_query_type_function (mp3parse->srcpad, mp3parse_get_query_types); - gst_element_add_pad (GST_ELEMENT (mp3parse), mp3parse->srcpad); - - mp3parse->adapter = gst_adapter_new (); - mp3parse->pending_seeks_lock = g_mutex_new (); - - gst_mp3parse_reset (mp3parse); -} - -static void -gst_mp3parse_dispose (GObject * object) -{ - GstMPEGAudioParse *mp3parse = GST_MP3PARSE (object); - - gst_mp3parse_reset (mp3parse); - - if (mp3parse->adapter) { - g_object_unref (mp3parse->adapter); - mp3parse->adapter = NULL; - } - g_mutex_free (mp3parse->pending_seeks_lock); - mp3parse->pending_seeks_lock = NULL; - - g_list_foreach (mp3parse->pending_events, (GFunc) gst_mini_object_unref, - NULL); - g_list_free (mp3parse->pending_events); - mp3parse->pending_events = NULL; - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static gboolean -gst_mp3parse_sink_event (GstPad * pad, GstEvent * event) -{ - gboolean res = TRUE; - GstMPEGAudioParse *mp3parse; - GstEvent **eventp; - - mp3parse = GST_MP3PARSE (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - { - gdouble rate, applied_rate; - GstFormat format; - gint64 start, stop, pos; - gboolean update; - MPEGAudioPendingAccurateSeek *seek = NULL; - GSList *node; - - gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, - &format, &start, &stop, &pos); - - g_mutex_lock (mp3parse->pending_seeks_lock); - if (format == GST_FORMAT_BYTES && mp3parse->pending_accurate_seeks) { - - for (node = mp3parse->pending_accurate_seeks; node; node = node->next) { - MPEGAudioPendingAccurateSeek *tmp = node->data; - - if (tmp->upstream_start == pos) { - seek = tmp; - break; - } - } - if (seek) { - GstSegment *s = &seek->segment; - - event = - gst_event_new_new_segment_full (FALSE, s->rate, s->applied_rate, - GST_FORMAT_TIME, s->start, s->stop, s->last_stop); - - mp3parse->segment = seek->segment; - - mp3parse->resyncing = FALSE; - mp3parse->cur_offset = pos; - mp3parse->next_ts = seek->timestamp_start; - mp3parse->pending_ts = GST_CLOCK_TIME_NONE; - mp3parse->tracked_offset = 0; - mp3parse->sync_offset = 0; - - gst_event_parse_new_segment_full (event, &update, &rate, - &applied_rate, &format, &start, &stop, &pos); - - GST_DEBUG_OBJECT (mp3parse, - "Pushing accurate newseg rate %g, applied rate %g, " - "format %d, start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT - ", pos %" G_GINT64_FORMAT, rate, applied_rate, format, start, - stop, pos); - - g_free (seek); - mp3parse->pending_accurate_seeks = - g_slist_delete_link (mp3parse->pending_accurate_seeks, node); - - g_mutex_unlock (mp3parse->pending_seeks_lock); - res = gst_pad_push_event (mp3parse->srcpad, event); - - return res; - } else { - GST_WARNING_OBJECT (mp3parse, - "Accurate seek not possible, didn't get an appropiate upstream segment"); - } - } - g_mutex_unlock (mp3parse->pending_seeks_lock); - - mp3parse->exact_position = FALSE; - - if (format == GST_FORMAT_BYTES) { - GstClockTime seg_start, seg_stop, seg_pos; - - /* stop time is allowed to be open-ended, but not start & pos */ - if (!mp3parse_bytepos_to_time (mp3parse, stop, &seg_stop, FALSE)) - seg_stop = GST_CLOCK_TIME_NONE; - if (mp3parse_bytepos_to_time (mp3parse, start, &seg_start, FALSE) && - mp3parse_bytepos_to_time (mp3parse, pos, &seg_pos, FALSE)) { - gst_event_unref (event); - - /* search the pending nonaccurate seeks */ - g_mutex_lock (mp3parse->pending_seeks_lock); - seek = NULL; - for (node = mp3parse->pending_nonaccurate_seeks; node; - node = node->next) { - MPEGAudioPendingAccurateSeek *tmp = node->data; - - if (tmp->upstream_start == pos) { - seek = tmp; - break; - } - } - - if (seek) { - if (seek->segment.stop == -1) { - /* corrent the segment end, because non-accurate seeks might make - * our streaming end earlier (see bug #603695) */ - seg_stop = -1; - } - g_free (seek); - mp3parse->pending_nonaccurate_seeks = - g_slist_delete_link (mp3parse->pending_nonaccurate_seeks, node); - } - g_mutex_unlock (mp3parse->pending_seeks_lock); - - event = gst_event_new_new_segment_full (update, rate, applied_rate, - GST_FORMAT_TIME, seg_start, seg_stop, seg_pos); - format = GST_FORMAT_TIME; - GST_DEBUG_OBJECT (mp3parse, "Converted incoming segment to TIME. " - "start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT - ", pos = %" GST_TIME_FORMAT, GST_TIME_ARGS (seg_start), - GST_TIME_ARGS (seg_stop), GST_TIME_ARGS (seg_pos)); - } - } - - if (format != GST_FORMAT_TIME) { - /* Unknown incoming segment format. Output a default open-ended - * TIME segment */ - gst_event_unref (event); - event = gst_event_new_new_segment_full (update, rate, applied_rate, - GST_FORMAT_TIME, 0, GST_CLOCK_TIME_NONE, 0); - } - - mp3parse->resyncing = TRUE; - mp3parse->cur_offset = -1; - mp3parse->next_ts = GST_CLOCK_TIME_NONE; - mp3parse->pending_ts = GST_CLOCK_TIME_NONE; - mp3parse->tracked_offset = 0; - mp3parse->sync_offset = 0; - /* also clear leftover data if clearing so much state */ - gst_adapter_clear (mp3parse->adapter); - - gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, - &format, &start, &stop, &pos); - GST_DEBUG_OBJECT (mp3parse, "Pushing newseg rate %g, applied rate %g, " - "format %d, start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT - ", pos %" G_GINT64_FORMAT, rate, applied_rate, format, start, stop, - pos); - - gst_segment_set_newsegment_full (&mp3parse->segment, update, rate, - applied_rate, format, start, stop, pos); - - /* save the segment for later, right before we push a new buffer so that - * the caps are fixed and the next linked element can receive the segment. */ - eventp = &mp3parse->pending_segment; - gst_event_replace (eventp, event); - gst_event_unref (event); - res = TRUE; - break; - } - case GST_EVENT_FLUSH_STOP: - /* Clear our adapter and set up for a new position */ - gst_adapter_clear (mp3parse->adapter); - eventp = &mp3parse->pending_segment; - gst_event_replace (eventp, NULL); - res = gst_pad_push_event (mp3parse->srcpad, event); - break; - case GST_EVENT_EOS: - /* If we haven't processed any frames yet, then make sure we process - at least whatever's in our adapter */ - if (mp3parse->frame_count == 0) { - gst_mp3parse_handle_data (mp3parse, TRUE); - - /* If we STILL have zero frames processed, fire an error */ - if (mp3parse->frame_count == 0) { - GST_ELEMENT_ERROR (mp3parse, STREAM, WRONG_TYPE, - ("No valid frames found before end of stream"), (NULL)); - } - } - /* fall through */ - default: - if (mp3parse->pending_segment && - (GST_EVENT_TYPE (event) != GST_EVENT_EOS) && - (GST_EVENT_TYPE (event) != GST_EVENT_FLUSH_START)) { - /* Cache all events except EOS and the ones above if we have - * a pending segment */ - mp3parse->pending_events = - g_list_append (mp3parse->pending_events, event); - } else { - res = gst_pad_push_event (mp3parse->srcpad, event); - } - break; - } - - gst_object_unref (mp3parse); - - return res; -} - -static void -gst_mp3parse_add_index_entry (GstMPEGAudioParse * mp3parse, guint64 offset, - GstClockTime ts) -{ - MPEGAudioSeekEntry *entry, *last; - - if (G_LIKELY (mp3parse->seek_table != NULL)) { - last = mp3parse->seek_table->data; - - if (last->byte >= offset) - return; - - if (GST_CLOCK_DIFF (last->timestamp, ts) < mp3parse->idx_interval) - return; - } - - entry = mpeg_audio_seek_entry_new (); - entry->byte = offset; - entry->timestamp = ts; - mp3parse->seek_table = g_list_prepend (mp3parse->seek_table, entry); - - GST_LOG_OBJECT (mp3parse, "Adding index entry %" GST_TIME_FORMAT " @ offset " - "0x%08" G_GINT64_MODIFIER "x", GST_TIME_ARGS (ts), offset); -} - -/* Prepare a buffer of the indicated size, timestamp it and output */ -static GstFlowReturn -gst_mp3parse_emit_frame (GstMPEGAudioParse * mp3parse, guint size, - guint mode, guint crc) -{ - GstBuffer *outbuf; - guint bitrate; - GstFlowReturn ret = GST_FLOW_OK; - GstClockTime push_start; - GstTagList *taglist; - - outbuf = gst_adapter_take_buffer (mp3parse->adapter, size); - - GST_BUFFER_DURATION (outbuf) = - gst_util_uint64_scale (GST_SECOND, mp3parse->spf, mp3parse->rate); - - GST_BUFFER_OFFSET (outbuf) = mp3parse->cur_offset; - - /* Check if we have a pending timestamp from an incoming buffer to apply - * here */ - if (GST_CLOCK_TIME_IS_VALID (mp3parse->pending_ts)) { - if (mp3parse->tracked_offset >= mp3parse->pending_offset) { - /* If the incoming timestamp differs from our expected by more than - * half a frame, then take it instead of our calculated timestamp. - * This avoids creating imperfect streams just because of - * quantization in the container timestamping */ - GstClockTimeDiff diff = mp3parse->next_ts - mp3parse->pending_ts; - GstClockTimeDiff thresh = GST_BUFFER_DURATION (outbuf) / 2; - - if (diff < -thresh || diff > thresh) { - GST_DEBUG_OBJECT (mp3parse, "Updating next_ts from %" GST_TIME_FORMAT - " to pending ts %" GST_TIME_FORMAT - " at offset %" G_GINT64_FORMAT " (pending offset was %" - G_GINT64_FORMAT ")", GST_TIME_ARGS (mp3parse->next_ts), - GST_TIME_ARGS (mp3parse->pending_ts), mp3parse->tracked_offset, - mp3parse->pending_offset); - mp3parse->next_ts = mp3parse->pending_ts; - } - mp3parse->pending_ts = GST_CLOCK_TIME_NONE; - } - } - - /* Decide what timestamp we're going to apply */ - if (GST_CLOCK_TIME_IS_VALID (mp3parse->next_ts)) { - GST_BUFFER_TIMESTAMP (outbuf) = mp3parse->next_ts; - } else { - GstClockTime ts; - - /* No timestamp yet, convert our offset to a timestamp if we can, or - * start at 0 */ - if (mp3parse_bytepos_to_time (mp3parse, mp3parse->cur_offset, &ts, FALSE) && - GST_CLOCK_TIME_IS_VALID (ts)) - GST_BUFFER_TIMESTAMP (outbuf) = ts; - else { - GST_BUFFER_TIMESTAMP (outbuf) = 0; - } - } - - if (GST_BUFFER_TIMESTAMP (outbuf) == 0) - mp3parse->exact_position = TRUE; - - if (mp3parse->seekable && - mp3parse->exact_position && GST_BUFFER_TIMESTAMP_IS_VALID (outbuf) && - mp3parse->cur_offset != GST_BUFFER_OFFSET_NONE) { - gst_mp3parse_add_index_entry (mp3parse, mp3parse->cur_offset, - GST_BUFFER_TIMESTAMP (outbuf)); - } - - /* Update our byte offset tracking */ - if (mp3parse->cur_offset != -1) { - mp3parse->cur_offset += size; - } - mp3parse->tracked_offset += size; - - if (GST_BUFFER_TIMESTAMP_IS_VALID (outbuf)) - mp3parse->next_ts = - GST_BUFFER_TIMESTAMP (outbuf) + GST_BUFFER_DURATION (outbuf); - - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (mp3parse->srcpad)); - - /* Post a bitrate tag if we need to before pushing the buffer */ - if (mp3parse->xing_bitrate != 0) - bitrate = mp3parse->xing_bitrate; - else if (mp3parse->vbri_bitrate != 0) - bitrate = mp3parse->vbri_bitrate; - else - bitrate = mp3parse->avg_bitrate; - - /* we will create a taglist (if any of the parameters has changed) - * to add the tags that changed */ - taglist = NULL; - if ((mp3parse->last_posted_bitrate / 10000) != (bitrate / 10000)) { - taglist = gst_tag_list_new (); - mp3parse->last_posted_bitrate = bitrate; - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, - mp3parse->last_posted_bitrate, NULL); - - /* Post a new duration message if the average bitrate changes that much - * so applications can update their cached values - */ - if ((mp3parse->xing_flags & XING_TOC_FLAG) == 0 - && mp3parse->vbri_total_time == 0) { - gst_element_post_message (GST_ELEMENT (mp3parse), - gst_message_new_duration (GST_OBJECT (mp3parse), GST_FORMAT_TIME, - -1)); - } - } - - if (mp3parse->last_posted_crc != crc) { - gboolean using_crc; - - if (!taglist) { - taglist = gst_tag_list_new (); - } - mp3parse->last_posted_crc = crc; - if (mp3parse->last_posted_crc == CRC_PROTECTED) { - using_crc = TRUE; - } else { - using_crc = FALSE; - } - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_CRC, - using_crc, NULL); - } - - if (mp3parse->last_posted_channel_mode != mode) { - if (!taglist) { - taglist = gst_tag_list_new (); - } - mp3parse->last_posted_channel_mode = mode; - - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_MODE, - gst_mp3_channel_mode_get_nick (mode), NULL); - } - - /* if the taglist exists, we need to send it */ - if (taglist) { - gst_element_found_tags_for_pad (GST_ELEMENT (mp3parse), - mp3parse->srcpad, taglist); - } - - /* We start pushing 9 frames earlier (29 frames for MPEG2) than - * segment start to be able to decode the first frame we want. - * 9 (29) frames are the theoretical maximum of frames that contain - * data for the current frame (bit reservoir). - */ - if (mp3parse->segment.start == 0) { - push_start = 0; - } else if (GST_CLOCK_TIME_IS_VALID (mp3parse->max_bitreservoir)) { - if (GST_CLOCK_TIME_IS_VALID (mp3parse->segment.start) && - mp3parse->segment.start > mp3parse->max_bitreservoir) - push_start = mp3parse->segment.start - mp3parse->max_bitreservoir; - else - push_start = 0; - } else { - push_start = mp3parse->segment.start; - } - - if (G_UNLIKELY ((GST_CLOCK_TIME_IS_VALID (push_start) && - GST_BUFFER_TIMESTAMP_IS_VALID (outbuf) && - GST_BUFFER_TIMESTAMP (outbuf) + GST_BUFFER_DURATION (outbuf) - < push_start))) { - GST_DEBUG_OBJECT (mp3parse, - "Buffer before configured segment range %" GST_TIME_FORMAT - " to %" GST_TIME_FORMAT ", dropping, timestamp %" - GST_TIME_FORMAT " duration %" GST_TIME_FORMAT - ", offset 0x%08" G_GINT64_MODIFIER "x", GST_TIME_ARGS (push_start), - GST_TIME_ARGS (mp3parse->segment.stop), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), - GST_BUFFER_OFFSET (outbuf)); - - gst_buffer_unref (outbuf); - ret = GST_FLOW_OK; - } else if (G_UNLIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (outbuf) && - GST_CLOCK_TIME_IS_VALID (mp3parse->segment.stop) && - GST_BUFFER_TIMESTAMP (outbuf) >= - mp3parse->segment.stop + GST_BUFFER_DURATION (outbuf))) { - /* Some mp3 streams have an offset in the timestamps, for which we have to - * push the frame *after* the end position in order for the decoder to be - * able to decode everything up until the segment.stop position. - * That is the reason of the calculated offset */ - GST_DEBUG_OBJECT (mp3parse, - "Buffer after configured segment range %" GST_TIME_FORMAT " to %" - GST_TIME_FORMAT ", returning GST_FLOW_UNEXPECTED, timestamp %" - GST_TIME_FORMAT " duration %" GST_TIME_FORMAT ", offset 0x%08" - G_GINT64_MODIFIER "x", GST_TIME_ARGS (push_start), - GST_TIME_ARGS (mp3parse->segment.stop), - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), - GST_BUFFER_OFFSET (outbuf)); - - gst_buffer_unref (outbuf); - ret = GST_FLOW_UNEXPECTED; - } else { - GST_DEBUG_OBJECT (mp3parse, - "pushing buffer of %d bytes, timestamp %" GST_TIME_FORMAT - ", offset 0x%08" G_GINT64_MODIFIER "x", size, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), - GST_BUFFER_OFFSET (outbuf)); - mp3parse->segment.last_stop = GST_BUFFER_TIMESTAMP (outbuf); - /* push any pending segment now */ - if (mp3parse->pending_segment) { - gst_pad_push_event (mp3parse->srcpad, mp3parse->pending_segment); - mp3parse->pending_segment = NULL; - } - if (mp3parse->pending_events) { - GList *l; - - for (l = mp3parse->pending_events; l != NULL; l = l->next) { - gst_pad_push_event (mp3parse->srcpad, GST_EVENT (l->data)); - } - g_list_free (mp3parse->pending_events); - mp3parse->pending_events = NULL; - } - - /* set discont if needed */ - if (mp3parse->discont) { - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - mp3parse->discont = FALSE; - } - - ret = gst_pad_push (mp3parse->srcpad, outbuf); - } - - return ret; -} - -static void -gst_mp3parse_handle_first_frame (GstMPEGAudioParse * mp3parse) -{ - GstTagList *taglist; - gchar *codec; - const guint32 xing_id = 0x58696e67; /* 'Xing' in hex */ - const guint32 info_id = 0x496e666f; /* 'Info' in hex - found in LAME CBR files */ - const guint32 vbri_id = 0x56425249; /* 'VBRI' in hex */ - - gint offset; - - guint64 avail; - gint64 upstream_total_bytes = 0; - guint32 read_id; - const guint8 *data; - - /* Output codec tag */ - if (!mp3parse->sent_codec_tag) { - if (mp3parse->layer == 3) { - codec = g_strdup_printf ("MPEG %d Audio, Layer %d (MP3)", - mp3parse->version, mp3parse->layer); - } else { - codec = g_strdup_printf ("MPEG %d Audio, Layer %d", - mp3parse->version, mp3parse->layer); - } - - taglist = gst_tag_list_new (); - gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, - GST_TAG_AUDIO_CODEC, codec, NULL); - gst_element_found_tags_for_pad (GST_ELEMENT (mp3parse), - mp3parse->srcpad, taglist); - g_free (codec); - - mp3parse->sent_codec_tag = TRUE; - } - /* end setting the tag */ - - /* Check first frame for Xing info */ - if (mp3parse->version == 1) { /* MPEG-1 file */ - if (mp3parse->channels == 1) - offset = 0x11; - else - offset = 0x20; - } else { /* MPEG-2 header */ - if (mp3parse->channels == 1) - offset = 0x09; - else - offset = 0x11; - } - /* Skip the 4 bytes of the MP3 header too */ - offset += 4; - - /* Check if we have enough data to read the Xing header */ - avail = gst_adapter_available (mp3parse->adapter); - - if (avail < offset + 8) - return; - - data = gst_adapter_peek (mp3parse->adapter, offset + 8); - if (data == NULL) - return; - /* The header starts at the provided offset */ - data += offset; - - /* obtain real upstream total bytes */ - mp3parse_total_bytes (mp3parse, &upstream_total_bytes); - - read_id = GST_READ_UINT32_BE (data); - if (read_id == xing_id || read_id == info_id) { - guint32 xing_flags; - guint bytes_needed = offset + 8; - gint64 total_bytes; - GstClockTime total_time; - - GST_DEBUG_OBJECT (mp3parse, "Found Xing header marker 0x%x", xing_id); - - /* Read 4 base bytes of flags, big-endian */ - xing_flags = GST_READ_UINT32_BE (data + 4); - if (xing_flags & XING_FRAMES_FLAG) - bytes_needed += 4; - if (xing_flags & XING_BYTES_FLAG) - bytes_needed += 4; - if (xing_flags & XING_TOC_FLAG) - bytes_needed += 100; - if (xing_flags & XING_VBR_SCALE_FLAG) - bytes_needed += 4; - if (avail < bytes_needed) { - GST_DEBUG_OBJECT (mp3parse, - "Not enough data to read Xing header (need %d)", bytes_needed); - return; - } - - GST_DEBUG_OBJECT (mp3parse, "Reading Xing header"); - mp3parse->xing_flags = xing_flags; - data = gst_adapter_peek (mp3parse->adapter, bytes_needed); - data += offset + 8; - - if (xing_flags & XING_FRAMES_FLAG) { - mp3parse->xing_frames = GST_READ_UINT32_BE (data); - if (mp3parse->xing_frames == 0) { - GST_WARNING_OBJECT (mp3parse, - "Invalid number of frames in Xing header"); - mp3parse->xing_flags &= ~XING_FRAMES_FLAG; - } else { - mp3parse->xing_total_time = gst_util_uint64_scale (GST_SECOND, - (guint64) (mp3parse->xing_frames) * (mp3parse->spf), - mp3parse->rate); - } - - data += 4; - } else { - mp3parse->xing_frames = 0; - mp3parse->xing_total_time = 0; - } - - if (xing_flags & XING_BYTES_FLAG) { - mp3parse->xing_bytes = GST_READ_UINT32_BE (data); - if (mp3parse->xing_bytes == 0) { - GST_WARNING_OBJECT (mp3parse, "Invalid number of bytes in Xing header"); - mp3parse->xing_flags &= ~XING_BYTES_FLAG; - } - - data += 4; - } else { - mp3parse->xing_bytes = 0; - } - - /* If we know the upstream size and duration, compute the - * total bitrate, rounded up to the nearest kbit/sec */ - if ((total_time = mp3parse->xing_total_time) && - (total_bytes = mp3parse->xing_bytes)) { - mp3parse->xing_bitrate = gst_util_uint64_scale (total_bytes, - 8 * GST_SECOND, total_time); - mp3parse->xing_bitrate += 500; - mp3parse->xing_bitrate -= mp3parse->xing_bitrate % 1000; - } - - if (xing_flags & XING_TOC_FLAG) { - int i, percent = 0; - guchar *table = mp3parse->xing_seek_table; - guchar old = 0, new; - guint first; - - first = data[0]; - GST_DEBUG_OBJECT (mp3parse, - "Subtracting initial offset of %d bytes from Xing TOC", first); - - /* xing seek table: percent time -> 1/256 bytepos */ - for (i = 0; i < 100; i++) { - new = data[i] - first; - if (old > new) { - GST_WARNING_OBJECT (mp3parse, "Skipping broken Xing TOC"); - mp3parse->xing_flags &= ~XING_TOC_FLAG; - goto skip_toc; - } - mp3parse->xing_seek_table[i] = old = new; - } - - /* build inverse table: 1/256 bytepos -> 1/100 percent time */ - for (i = 0; i < 256; i++) { - while (percent < 99 && table[percent + 1] <= i) - percent++; - - if (table[percent] == i) { - mp3parse->xing_seek_table_inverse[i] = percent * 100; - } else if (table[percent] < i && percent < 99) { - gdouble fa, fb, fx; - gint a = percent, b = percent + 1; - - fa = table[a]; - fb = table[b]; - fx = (b - a) / (fb - fa) * (i - fa) + a; - mp3parse->xing_seek_table_inverse[i] = (guint16) (fx * 100); - } else if (percent == 99) { - gdouble fa, fb, fx; - gint a = percent, b = 100; - - fa = table[a]; - fb = 256.0; - fx = (b - a) / (fb - fa) * (i - fa) + a; - mp3parse->xing_seek_table_inverse[i] = (guint16) (fx * 100); - } - } - skip_toc: - data += 100; - } else { - memset (mp3parse->xing_seek_table, 0, 100); - memset (mp3parse->xing_seek_table_inverse, 0, 256); - } - - if (xing_flags & XING_VBR_SCALE_FLAG) { - mp3parse->xing_vbr_scale = GST_READ_UINT32_BE (data); - } else - mp3parse->xing_vbr_scale = 0; - - GST_DEBUG_OBJECT (mp3parse, "Xing header reported %u frames, time %" - GST_TIME_FORMAT ", %u bytes, vbr scale %u", mp3parse->xing_frames, - GST_TIME_ARGS (mp3parse->xing_total_time), mp3parse->xing_bytes, - mp3parse->xing_vbr_scale); - - /* check for truncated file */ - if (upstream_total_bytes && mp3parse->xing_bytes && - mp3parse->xing_bytes * 0.8 > upstream_total_bytes) { - GST_WARNING_OBJECT (mp3parse, "File appears to have been truncated; " - "invalidating Xing header duration and size"); - mp3parse->xing_flags &= ~XING_BYTES_FLAG; - mp3parse->xing_flags &= ~XING_FRAMES_FLAG; - } - } else if (read_id == vbri_id) { - gint64 total_bytes, total_frames; - GstClockTime total_time; - guint16 nseek_points; - - GST_DEBUG_OBJECT (mp3parse, "Found VBRI header marker 0x%x", vbri_id); - if (avail < offset + 26) { - GST_DEBUG_OBJECT (mp3parse, - "Not enough data to read VBRI header (need %d)", offset + 26); - return; - } - - GST_DEBUG_OBJECT (mp3parse, "Reading VBRI header"); - data = gst_adapter_peek (mp3parse->adapter, offset + 26); - data += offset + 4; - - if (GST_READ_UINT16_BE (data) != 0x0001) { - GST_WARNING_OBJECT (mp3parse, - "Unsupported VBRI version 0x%x", GST_READ_UINT16_BE (data)); - return; - } - data += 2; - - /* Skip encoder delay */ - data += 2; - - /* Skip quality */ - data += 2; - - total_bytes = GST_READ_UINT32_BE (data); - if (total_bytes != 0) - mp3parse->vbri_bytes = total_bytes; - data += 4; - - total_frames = GST_READ_UINT32_BE (data); - if (total_frames != 0) { - mp3parse->vbri_frames = total_frames; - mp3parse->vbri_total_time = gst_util_uint64_scale (GST_SECOND, - (guint64) (mp3parse->vbri_frames) * (mp3parse->spf), mp3parse->rate); - } - data += 4; - - /* If we know the upstream size and duration, compute the - * total bitrate, rounded up to the nearest kbit/sec */ - if ((total_time = mp3parse->vbri_total_time) && - (total_bytes = mp3parse->vbri_bytes)) { - mp3parse->vbri_bitrate = gst_util_uint64_scale (total_bytes, - 8 * GST_SECOND, total_time); - mp3parse->vbri_bitrate += 500; - mp3parse->vbri_bitrate -= mp3parse->vbri_bitrate % 1000; - } - - nseek_points = GST_READ_UINT16_BE (data); - data += 2; - - if (nseek_points > 0) { - guint scale, seek_bytes, seek_frames; - gint i; - - mp3parse->vbri_seek_points = nseek_points; - - scale = GST_READ_UINT16_BE (data); - data += 2; - - seek_bytes = GST_READ_UINT16_BE (data); - data += 2; - - seek_frames = GST_READ_UINT16_BE (data); - - if (scale == 0 || seek_bytes == 0 || seek_bytes > 4 || seek_frames == 0) { - GST_WARNING_OBJECT (mp3parse, "Unsupported VBRI seek table"); - goto out_vbri; - } - - if (avail < offset + 26 + nseek_points * seek_bytes) { - GST_WARNING_OBJECT (mp3parse, - "Not enough data to read VBRI seek table (need %d)", - offset + 26 + nseek_points * seek_bytes); - goto out_vbri; - } - - if (seek_frames * nseek_points < total_frames - seek_frames || - seek_frames * nseek_points > total_frames + seek_frames) { - GST_WARNING_OBJECT (mp3parse, - "VBRI seek table doesn't cover the complete file"); - goto out_vbri; - } - - data = - gst_adapter_peek (mp3parse->adapter, - offset + 26 + nseek_points * seek_bytes); - data += offset + 26; - - - /* VBRI seek table: frame/seek_frames -> byte */ - mp3parse->vbri_seek_table = g_new (guint32, nseek_points); - if (seek_bytes == 4) - for (i = 0; i < nseek_points; i++) { - mp3parse->vbri_seek_table[i] = GST_READ_UINT32_BE (data) * scale; - data += 4; - } else if (seek_bytes == 3) - for (i = 0; i < nseek_points; i++) { - mp3parse->vbri_seek_table[i] = GST_READ_UINT24_BE (data) * scale; - data += 3; - } else if (seek_bytes == 2) - for (i = 0; i < nseek_points; i++) { - mp3parse->vbri_seek_table[i] = GST_READ_UINT16_BE (data) * scale; - data += 2; - } else /* seek_bytes == 1 */ - for (i = 0; i < nseek_points; i++) { - mp3parse->vbri_seek_table[i] = GST_READ_UINT8 (data) * scale; - data += 1; - } - } - out_vbri: - - GST_DEBUG_OBJECT (mp3parse, "VBRI header reported %u frames, time %" - GST_TIME_FORMAT ", bytes %u", mp3parse->vbri_frames, - GST_TIME_ARGS (mp3parse->vbri_total_time), mp3parse->vbri_bytes); - - /* check for truncated file */ - if (upstream_total_bytes && mp3parse->vbri_bytes && - mp3parse->vbri_bytes * 0.8 > upstream_total_bytes) { - GST_WARNING_OBJECT (mp3parse, "File appears to have been truncated; " - "invalidating VBRI header duration and size"); - mp3parse->vbri_valid = FALSE; - } else { - mp3parse->vbri_valid = TRUE; - } - } else { - GST_DEBUG_OBJECT (mp3parse, - "Xing, LAME or VBRI header not found in first frame"); - } -} - -static void -gst_mp3parse_check_seekability (GstMPEGAudioParse * mp3parse) -{ - GstQuery *query; - gboolean seekable = FALSE; - gint64 start = -1, stop = -1; - guint idx_interval = 0; - - query = gst_query_new_seeking (GST_FORMAT_BYTES); - if (!gst_pad_peer_query (mp3parse->sinkpad, query)) { - GST_DEBUG_OBJECT (mp3parse, "seeking query failed"); - goto done; - } - - gst_query_parse_seeking (query, NULL, &seekable, &start, &stop); - - /* try harder to query upstream size if we didn't get it the first time */ - if (seekable && stop == -1) { - GstFormat fmt = GST_FORMAT_BYTES; - - GST_DEBUG_OBJECT (mp3parse, "doing duration query to fix up unset stop"); - gst_pad_query_peer_duration (mp3parse->sinkpad, &fmt, &stop); - } - - /* if upstream doesn't know the size, it's likely that it's not seekable in - * practice even if it technically may be seekable */ - if (seekable && (start != 0 || stop <= start)) { - GST_DEBUG_OBJECT (mp3parse, "seekable but unknown start/stop -> disable"); - seekable = FALSE; - } - - /* let's not put every single frame into our index */ - if (seekable) { - if (stop < 10 * 1024 * 1024) - idx_interval = 100; - else if (stop < 100 * 1024 * 1024) - idx_interval = 500; - else - idx_interval = 1000; - } - -done: - - GST_INFO_OBJECT (mp3parse, "seekable: %d (%" G_GUINT64_FORMAT " - %" - G_GUINT64_FORMAT ")", seekable, start, stop); - mp3parse->seekable = seekable; - - GST_INFO_OBJECT (mp3parse, "idx_interval: %ums", idx_interval); - mp3parse->idx_interval = idx_interval * GST_MSECOND; - - gst_query_unref (query); -} - -/* Flush some number of bytes and update tracked offsets */ -static void -gst_mp3parse_flush_bytes (GstMPEGAudioParse * mp3parse, int bytes) -{ - gst_adapter_flush (mp3parse->adapter, bytes); - if (mp3parse->cur_offset != -1) - mp3parse->cur_offset += bytes; - mp3parse->tracked_offset += bytes; -} - -/* Perform extended validation to check that subsequent headers match - the first header given here in important characteristics, to avoid - false sync. We look for a minimum of MIN_RESYNC_FRAMES consecutive - frames to match their major characteristics. - - If at_eos is set to TRUE, we just check that we don't find any invalid - frames in whatever data is available, rather than requiring a full - MIN_RESYNC_FRAMES of data. - - Returns TRUE if we've seen enough data to validate or reject the frame. - If TRUE is returned, then *valid contains TRUE if it validated, or false - if we decided it was false sync. - */ -static gboolean -gst_mp3parse_validate_extended (GstMPEGAudioParse * mp3parse, guint32 header, - int bpf, gboolean at_eos, gboolean * valid) -{ - guint32 next_header; - const guint8 *data; - guint available; - int frames_found = 1; - int offset = bpf; - - while (frames_found < MIN_RESYNC_FRAMES) { - /* Check if we have enough data for all these frames, plus the next - frame header. */ - available = gst_adapter_available (mp3parse->adapter); - if (available < offset + 4) { - if (at_eos) { - /* Running out of data at EOS is fine; just accept it */ - *valid = TRUE; - return TRUE; - } else { - return FALSE; - } - } - - data = gst_adapter_peek (mp3parse->adapter, offset + 4); - next_header = GST_READ_UINT32_BE (data + offset); - GST_DEBUG_OBJECT (mp3parse, "At %d: header=%08X, header2=%08X, bpf=%d", - offset, (unsigned int) header, (unsigned int) next_header, bpf); - -/* mask the bits which are allowed to differ between frames */ -#define HDRMASK ~((0xF << 12) /* bitrate */ | \ - (0x1 << 9) /* padding */ | \ - (0xf << 4) /* mode|mode extension */ | \ - (0xf)) /* copyright|emphasis */ - - if ((next_header & HDRMASK) != (header & HDRMASK)) { - /* If any of the unmasked bits don't match, then it's not valid */ - GST_DEBUG_OBJECT (mp3parse, "next header doesn't match " - "(header=%08X (%08X), header2=%08X (%08X), bpf=%d)", - (guint) header, (guint) header & HDRMASK, (guint) next_header, - (guint) next_header & HDRMASK, bpf); - *valid = FALSE; - return TRUE; - } else if ((((next_header >> 12) & 0xf) == 0) || - (((next_header >> 12) & 0xf) == 0xf)) { - /* The essential parts were the same, but the bitrate held an - invalid value - also reject */ - GST_DEBUG_OBJECT (mp3parse, "next header invalid (bitrate)"); - *valid = FALSE; - return TRUE; - } - - bpf = mp3_type_frame_length_from_header (mp3parse, next_header, - NULL, NULL, NULL, NULL, NULL, NULL, NULL); - - offset += bpf; - frames_found++; - } - - *valid = TRUE; - return TRUE; -} - -static GstFlowReturn -gst_mp3parse_handle_data (GstMPEGAudioParse * mp3parse, gboolean at_eos) -{ - GstFlowReturn flow = GST_FLOW_OK; - const guchar *data; - guint32 header; - int bpf; - guint available; - guint bitrate, layer, rate, channels, version, mode, crc; - gboolean caps_change; - - /* while we still have at least 4 bytes (for the header) available */ - while (gst_adapter_available (mp3parse->adapter) >= 4) { - /* Get the header bytes, check if they're potentially valid */ - data = gst_adapter_peek (mp3parse->adapter, 4); - header = GST_READ_UINT32_BE (data); - - if (!head_check (mp3parse, header)) { - /* Not a valid MP3 header; we start looking forward byte-by-byte trying to - find a place to resync */ - if (!mp3parse->resyncing) - mp3parse->sync_offset = mp3parse->tracked_offset; - mp3parse->resyncing = TRUE; - gst_mp3parse_flush_bytes (mp3parse, 1); - GST_DEBUG_OBJECT (mp3parse, "wrong header, skipping byte"); - continue; - } - - /* We have a potentially valid header. - If this is just a normal 'next frame', we go ahead and output it. - - However, sometimes, we do additional validation to ensure we haven't - got false sync (common with mp3 due to the short sync word). - The additional validation requires that we find several consecutive mp3 - frames with the same major parameters, or reach EOS with a smaller - number of valid-looking frames. - - We do this if: - - This is the very first frame we've processed - - We're resyncing after a non-accurate seek, or after losing sync - due to invalid data. - - The format of the stream changes in a major way (number of channels, - sample rate, layer, or mpeg version). - */ - available = gst_adapter_available (mp3parse->adapter); - - if (G_UNLIKELY (mp3parse->resyncing && - mp3parse->tracked_offset - mp3parse->sync_offset > 2 * 1024 * 1024)) - goto sync_failure; - - bpf = mp3_type_frame_length_from_header (mp3parse, header, - &version, &layer, &channels, &bitrate, &rate, &mode, &crc); - g_assert (bpf != 0); - - if (channels != mp3parse->channels || - rate != mp3parse->rate || layer != mp3parse->layer || - version != mp3parse->version) - caps_change = TRUE; - else - caps_change = FALSE; - - if (mp3parse->resyncing || caps_change) { - gboolean valid; - if (!gst_mp3parse_validate_extended (mp3parse, header, bpf, at_eos, - &valid)) { - /* Not enough data to validate; wait for more */ - break; - } - - if (!valid) { - /* Extended validation failed; we probably got false sync. - Continue searching from the next byte in the stream */ - if (!mp3parse->resyncing) - mp3parse->sync_offset = mp3parse->tracked_offset; - mp3parse->resyncing = TRUE; - gst_mp3parse_flush_bytes (mp3parse, 1); - continue; - } - } - - /* if we don't have the whole frame... */ - if (available < bpf) { - GST_DEBUG_OBJECT (mp3parse, "insufficient data available, need " - "%d bytes, have %d", bpf, available); - break; - } - - if (caps_change) { - GstCaps *caps; - - caps = mp3_caps_create (version, layer, channels, rate); - gst_pad_set_caps (mp3parse->srcpad, caps); - gst_caps_unref (caps); - - mp3parse->channels = channels; - mp3parse->rate = rate; - - mp3parse->layer = layer; - mp3parse->version = version; - - /* see http://www.codeproject.com/audio/MPEGAudioInfo.asp */ - if (mp3parse->layer == 1) - mp3parse->spf = 384; - else if (mp3parse->layer == 2) - mp3parse->spf = 1152; - else if (mp3parse->version == 1) { - mp3parse->spf = 1152; - } else { - /* MPEG-2 or "2.5" */ - mp3parse->spf = 576; - } - - mp3parse->max_bitreservoir = gst_util_uint64_scale (GST_SECOND, - ((version == 1) ? 10 : 30) * mp3parse->spf, mp3parse->rate); - } - - mp3parse->bit_rate = bitrate; - - /* Check the first frame for a Xing header to get our total length */ - if (mp3parse->frame_count == 0) { - /* For the first frame in the file, look for a Xing frame after - * the header, and output a codec tag */ - gst_mp3parse_handle_first_frame (mp3parse); - - /* Check if we're seekable */ - gst_mp3parse_check_seekability (mp3parse); - } - - /* Update VBR stats */ - mp3parse->bitrate_sum += mp3parse->bit_rate; - mp3parse->frame_count++; - /* Compute the average bitrate, rounded up to the nearest 1000 bits */ - mp3parse->avg_bitrate = - (mp3parse->bitrate_sum / mp3parse->frame_count + 500); - mp3parse->avg_bitrate -= mp3parse->avg_bitrate % 1000; - - if (!mp3parse->skip) { - mp3parse->resyncing = FALSE; - flow = gst_mp3parse_emit_frame (mp3parse, bpf, mode, crc); - if (GST_FLOW_IS_FATAL (flow)) - break; - } else { - GST_DEBUG_OBJECT (mp3parse, "skipping buffer of %d bytes", bpf); - gst_mp3parse_flush_bytes (mp3parse, bpf); - mp3parse->skip--; - } - } - - return flow; - - /* ERRORS */ -sync_failure: - { - GST_ELEMENT_ERROR (mp3parse, STREAM, DECODE, - ("Failed to parse stream"), (NULL)); - return GST_FLOW_ERROR; - } -} - -static GstFlowReturn -gst_mp3parse_chain (GstPad * pad, GstBuffer * buf) -{ - GstMPEGAudioParse *mp3parse; - GstClockTime timestamp; - - mp3parse = GST_MP3PARSE (GST_PAD_PARENT (pad)); - - GST_LOG_OBJECT (mp3parse, "buffer of %d bytes", GST_BUFFER_SIZE (buf)); - - timestamp = GST_BUFFER_TIMESTAMP (buf); - - mp3parse->discont |= GST_BUFFER_IS_DISCONT (buf); - - /* If we don't yet have a next timestamp, save it and the incoming offset - * so we can apply it to the right outgoing buffer */ - if (GST_CLOCK_TIME_IS_VALID (timestamp)) { - gint64 avail = gst_adapter_available (mp3parse->adapter); - - mp3parse->pending_ts = timestamp; - mp3parse->pending_offset = mp3parse->tracked_offset + avail; - - /* If we have no data pending and the next timestamp is - * invalid we can use the upstream timestamp for the next frame. - * - * This will give us a timestamp if we're resyncing and upstream - * gave us -1 as offset. */ - if (avail == 0 && !GST_CLOCK_TIME_IS_VALID (mp3parse->next_ts)) - mp3parse->next_ts = timestamp; - - GST_LOG_OBJECT (mp3parse, "Have pending ts %" GST_TIME_FORMAT - " to apply in %" G_GINT64_FORMAT " bytes (@ off %" G_GINT64_FORMAT ")", - GST_TIME_ARGS (mp3parse->pending_ts), avail, mp3parse->pending_offset); - } - - /* Update the cur_offset we'll apply to outgoing buffers */ - if (mp3parse->cur_offset == -1 && GST_BUFFER_OFFSET (buf) != -1) - mp3parse->cur_offset = GST_BUFFER_OFFSET (buf); - - /* And add the data to the pool */ - gst_adapter_push (mp3parse->adapter, buf); - - return gst_mp3parse_handle_data (mp3parse, FALSE); -} - -static gboolean -head_check (GstMPEGAudioParse * mp3parse, unsigned long head) -{ - GST_DEBUG_OBJECT (mp3parse, "checking mp3 header 0x%08lx", head); - /* if it's not a valid sync */ - if ((head & 0xffe00000) != 0xffe00000) { - GST_WARNING_OBJECT (mp3parse, "invalid sync"); - return FALSE; - } - /* if it's an invalid MPEG version */ - if (((head >> 19) & 3) == 0x1) { - GST_WARNING_OBJECT (mp3parse, "invalid MPEG version: 0x%lx", - (head >> 19) & 3); - return FALSE; - } - /* if it's an invalid layer */ - if (!((head >> 17) & 3)) { - GST_WARNING_OBJECT (mp3parse, "invalid layer: 0x%lx", (head >> 17) & 3); - return FALSE; - } - /* if it's an invalid bitrate */ - if (((head >> 12) & 0xf) == 0x0) { - GST_WARNING_OBJECT (mp3parse, "invalid bitrate: 0x%lx." - "Free format files are not supported yet", (head >> 12) & 0xf); - return FALSE; - } - if (((head >> 12) & 0xf) == 0xf) { - GST_WARNING_OBJECT (mp3parse, "invalid bitrate: 0x%lx", (head >> 12) & 0xf); - return FALSE; - } - /* if it's an invalid samplerate */ - if (((head >> 10) & 0x3) == 0x3) { - GST_WARNING_OBJECT (mp3parse, "invalid samplerate: 0x%lx", - (head >> 10) & 0x3); - return FALSE; - } - - if ((head & 0x3) == 0x2) { - /* Ignore this as there are some files with emphasis 0x2 that can - * be played fine. See BGO #537235 */ - GST_WARNING_OBJECT (mp3parse, "invalid emphasis: 0x%lx", head & 0x3); - } - - return TRUE; -} - -static void -gst_mp3parse_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstMPEGAudioParse *src; - - src = GST_MP3PARSE (object); - - switch (prop_id) { - case ARG_SKIP: - src->skip = g_value_get_int (value); - break; - default: - break; - } -} - -static void -gst_mp3parse_get_property (GObject * object, guint prop_id, GValue * value, - GParamSpec * pspec) -{ - GstMPEGAudioParse *src; - - src = GST_MP3PARSE (object); - - switch (prop_id) { - case ARG_SKIP: - g_value_set_int (value, src->skip); - break; - case ARG_BIT_RATE: - g_value_set_int (value, src->bit_rate * 1000); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GstStateChangeReturn -gst_mp3parse_change_state (GstElement * element, GstStateChange transition) -{ - GstMPEGAudioParse *mp3parse; - GstStateChangeReturn result; - - mp3parse = GST_MP3PARSE (element); - - result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_mp3parse_reset (mp3parse); - break; - default: - break; - } - - return result; -} - -static gboolean -mp3parse_total_bytes (GstMPEGAudioParse * mp3parse, gint64 * total) -{ - GstFormat fmt = GST_FORMAT_BYTES; - - if (gst_pad_query_peer_duration (mp3parse->sinkpad, &fmt, total)) - return TRUE; - - if (mp3parse->xing_flags & XING_BYTES_FLAG) { - *total = mp3parse->xing_bytes; - return TRUE; - } - - if (mp3parse->vbri_bytes != 0 && mp3parse->vbri_valid) { - *total = mp3parse->vbri_bytes; - return TRUE; - } - - return FALSE; -} - -static gboolean -mp3parse_total_time (GstMPEGAudioParse * mp3parse, GstClockTime * total) -{ - gint64 total_bytes; - - *total = GST_CLOCK_TIME_NONE; - - if (mp3parse->xing_flags & XING_FRAMES_FLAG) { - *total = mp3parse->xing_total_time; - return TRUE; - } - - if (mp3parse->vbri_total_time != 0 && mp3parse->vbri_valid) { - *total = mp3parse->vbri_total_time; - return TRUE; - } - - /* Calculate time from the measured bitrate */ - if (!mp3parse_total_bytes (mp3parse, &total_bytes)) - return FALSE; - - if (total_bytes != -1 - && !mp3parse_bytepos_to_time (mp3parse, total_bytes, total, TRUE)) - return FALSE; - - return TRUE; -} - -/* Convert a timestamp to the file position required to start decoding that - * timestamp. For now, this just uses the avg bitrate. Later, use an - * incrementally accumulated seek table */ -static gboolean -mp3parse_time_to_bytepos (GstMPEGAudioParse * mp3parse, GstClockTime ts, - gint64 * bytepos) -{ - gint64 total_bytes; - GstClockTime total_time; - - /* -1 always maps to -1 */ - if (ts == -1) { - *bytepos = -1; - return TRUE; - } - - /* If XING seek table exists use this for time->byte conversion */ - if ((mp3parse->xing_flags & XING_TOC_FLAG) && - (total_bytes = mp3parse->xing_bytes) && - (total_time = mp3parse->xing_total_time)) { - gdouble fa, fb, fx; - gdouble percent = - CLAMP ((100.0 * gst_util_guint64_to_gdouble (ts)) / - gst_util_guint64_to_gdouble (total_time), 0.0, 100.0); - gint index = CLAMP (percent, 0, 99); - - fa = mp3parse->xing_seek_table[index]; - if (index < 99) - fb = mp3parse->xing_seek_table[index + 1]; - else - fb = 256.0; - - fx = fa + (fb - fa) * (percent - index); - - *bytepos = (1.0 / 256.0) * fx * total_bytes; - - return TRUE; - } - - if (mp3parse->vbri_seek_table && (total_bytes = mp3parse->vbri_bytes) && - (total_time = mp3parse->vbri_total_time)) { - gint i, j; - gdouble a, b, fa, fb; - - i = gst_util_uint64_scale (ts, mp3parse->vbri_seek_points - 1, total_time); - i = CLAMP (i, 0, mp3parse->vbri_seek_points - 1); - - a = gst_guint64_to_gdouble (gst_util_uint64_scale (i, total_time, - mp3parse->vbri_seek_points)); - fa = 0.0; - for (j = i; j >= 0; j--) - fa += mp3parse->vbri_seek_table[j]; - - if (i + 1 < mp3parse->vbri_seek_points) { - b = gst_guint64_to_gdouble (gst_util_uint64_scale (i + 1, total_time, - mp3parse->vbri_seek_points)); - fb = fa + mp3parse->vbri_seek_table[i + 1]; - } else { - b = gst_guint64_to_gdouble (total_time); - fb = total_bytes; - } - - *bytepos = fa + ((fb - fa) / (b - a)) * (gst_guint64_to_gdouble (ts) - a); - - return TRUE; - } - - if (mp3parse->avg_bitrate == 0) - goto no_bitrate; - - *bytepos = - gst_util_uint64_scale (ts, mp3parse->avg_bitrate, (8 * GST_SECOND)); - return TRUE; -no_bitrate: - GST_DEBUG_OBJECT (mp3parse, "Cannot seek yet - no average bitrate"); - return FALSE; -} - -static gboolean -mp3parse_bytepos_to_time (GstMPEGAudioParse * mp3parse, - gint64 bytepos, GstClockTime * ts, gboolean from_total_time) -{ - gint64 total_bytes; - GstClockTime total_time; - - if (bytepos == -1) { - *ts = GST_CLOCK_TIME_NONE; - return TRUE; - } - - if (bytepos == 0) { - *ts = 0; - return TRUE; - } - - /* If XING seek table exists use this for byte->time conversion */ - if (!from_total_time && (mp3parse->xing_flags & XING_TOC_FLAG) && - (total_bytes = mp3parse->xing_bytes) && - (total_time = mp3parse->xing_total_time)) { - gdouble fa, fb, fx; - gdouble pos; - gint index; - - pos = CLAMP ((bytepos * 256.0) / total_bytes, 0.0, 256.0); - index = CLAMP (pos, 0, 255); - fa = mp3parse->xing_seek_table_inverse[index]; - if (index < 255) - fb = mp3parse->xing_seek_table_inverse[index + 1]; - else - fb = 10000.0; - - fx = fa + (fb - fa) * (pos - index); - - *ts = (1.0 / 10000.0) * fx * gst_util_guint64_to_gdouble (total_time); - - return TRUE; - } - - if (!from_total_time && mp3parse->vbri_seek_table && - (total_bytes = mp3parse->vbri_bytes) && - (total_time = mp3parse->vbri_total_time)) { - gint i = 0; - guint64 sum = 0; - gdouble a, b, fa, fb; - - do { - sum += mp3parse->vbri_seek_table[i]; - i++; - } while (i + 1 < mp3parse->vbri_seek_points - && sum + mp3parse->vbri_seek_table[i] < bytepos); - i--; - - a = gst_guint64_to_gdouble (sum); - fa = gst_guint64_to_gdouble (gst_util_uint64_scale (i, total_time, - mp3parse->vbri_seek_points)); - - if (i + 1 < mp3parse->vbri_seek_points) { - b = a + mp3parse->vbri_seek_table[i + 1]; - fb = gst_guint64_to_gdouble (gst_util_uint64_scale (i + 1, total_time, - mp3parse->vbri_seek_points)); - } else { - b = total_bytes; - fb = gst_guint64_to_gdouble (total_time); - } - - *ts = gst_gdouble_to_guint64 (fa + ((fb - fa) / (b - a)) * (bytepos - a)); - - return TRUE; - } - - /* Cannot convert anything except 0 if we don't have a bitrate yet */ - if (mp3parse->avg_bitrate == 0) - return FALSE; - - *ts = (GstClockTime) gst_util_uint64_scale (GST_SECOND, bytepos * 8, - mp3parse->avg_bitrate); - return TRUE; -} - -static gboolean -mp3parse_handle_seek (GstMPEGAudioParse * mp3parse, GstEvent * event) -{ - GstFormat format; - gdouble rate; - GstSeekFlags flags; - GstSeekType cur_type, stop_type; - gint64 cur, stop; - gint64 byte_cur, byte_stop; - MPEGAudioPendingAccurateSeek *seek; - GstClockTime start; - - gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, - &stop_type, &stop); - - GST_DEBUG_OBJECT (mp3parse, "Performing seek to %" GST_TIME_FORMAT, - GST_TIME_ARGS (cur)); - - /* For any format other than TIME, see if upstream handles - * it directly or fail. For TIME, try upstream, but do it ourselves if - * it fails upstream */ - if (format != GST_FORMAT_TIME) { - gst_event_ref (event); - return gst_pad_push_event (mp3parse->sinkpad, event); - } else { - gst_event_ref (event); - if (gst_pad_push_event (mp3parse->sinkpad, event)) - return TRUE; - } - - seek = g_new0 (MPEGAudioPendingAccurateSeek, 1); - - seek->segment = mp3parse->segment; - - gst_segment_set_seek (&seek->segment, rate, GST_FORMAT_TIME, - flags, cur_type, cur, stop_type, stop, NULL); - - /* Handle TIME based seeks by converting to a BYTE position */ - - /* For accurate seeking get the frame 9 (MPEG1) or 29 (MPEG2) frames - * before the one we want to seek to and push them all to the decoder. - * - * This is necessary because of the bit reservoir. See - * http://www.mars.org/mailman/public/mad-dev/2002-May/000634.html - * - */ - - if (flags & GST_SEEK_FLAG_ACCURATE) { - if (!mp3parse->seek_table) { - byte_cur = 0; - byte_stop = -1; - start = 0; - } else { - MPEGAudioSeekEntry *entry = NULL, *start_entry = NULL, *stop_entry = NULL; - GList *start_node, *stop_node; - gint64 seek_ts = (cur > mp3parse->max_bitreservoir) ? - (cur - mp3parse->max_bitreservoir) : 0; - - for (start_node = mp3parse->seek_table; start_node; - start_node = start_node->next) { - entry = start_node->data; - - if (seek_ts >= entry->timestamp) { - start_entry = entry; - break; - } - } - - if (!start_entry) { - start_entry = mp3parse->seek_table->data; - start = start_entry->timestamp; - byte_cur = start_entry->byte; - } else { - start = start_entry->timestamp; - byte_cur = start_entry->byte; - } - - for (stop_node = mp3parse->seek_table; stop_node; - stop_node = stop_node->next) { - entry = stop_node->data; - - if (stop >= entry->timestamp) { - stop_node = stop_node->prev; - stop_entry = (stop_node) ? stop_node->data : NULL; - break; - } - } - - if (!stop_entry) { - byte_stop = -1; - } else { - byte_stop = stop_entry->byte; - } - - } - event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, - byte_cur, stop_type, byte_stop); - g_mutex_lock (mp3parse->pending_seeks_lock); - seek->upstream_start = byte_cur; - seek->timestamp_start = start; - mp3parse->pending_accurate_seeks = - g_slist_prepend (mp3parse->pending_accurate_seeks, seek); - g_mutex_unlock (mp3parse->pending_seeks_lock); - if (gst_pad_push_event (mp3parse->sinkpad, event)) { - mp3parse->exact_position = TRUE; - return TRUE; - } else { - mp3parse->exact_position = TRUE; - g_mutex_lock (mp3parse->pending_seeks_lock); - mp3parse->pending_accurate_seeks = - g_slist_remove (mp3parse->pending_accurate_seeks, seek); - g_mutex_unlock (mp3parse->pending_seeks_lock); - g_free (seek); - return FALSE; - } - } - - mp3parse->exact_position = FALSE; - - /* Convert the TIME to the appropriate BYTE position at which to resume - * decoding. */ - if (!mp3parse_time_to_bytepos (mp3parse, (GstClockTime) cur, &byte_cur)) - goto no_pos; - if (!mp3parse_time_to_bytepos (mp3parse, (GstClockTime) stop, &byte_stop)) - goto no_pos; - - GST_DEBUG_OBJECT (mp3parse, "Seeking to byte range %" G_GINT64_FORMAT - " to %" G_GINT64_FORMAT, byte_cur, byte_stop); - - /* Send BYTE based seek upstream */ - event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, - byte_cur, stop_type, byte_stop); - - GST_LOG_OBJECT (mp3parse, "Storing pending seek"); - g_mutex_lock (mp3parse->pending_seeks_lock); - seek->upstream_start = byte_cur; - seek->timestamp_start = cur; - mp3parse->pending_nonaccurate_seeks = - g_slist_prepend (mp3parse->pending_nonaccurate_seeks, seek); - g_mutex_unlock (mp3parse->pending_seeks_lock); - if (gst_pad_push_event (mp3parse->sinkpad, event)) { - return TRUE; - } else { - g_mutex_lock (mp3parse->pending_seeks_lock); - mp3parse->pending_nonaccurate_seeks = - g_slist_remove (mp3parse->pending_nonaccurate_seeks, seek); - g_mutex_unlock (mp3parse->pending_seeks_lock); - g_free (seek); - return FALSE; - } - -no_pos: - GST_DEBUG_OBJECT (mp3parse, - "Could not determine byte position for desired time"); - return FALSE; -} - -static gboolean -mp3parse_src_event (GstPad * pad, GstEvent * event) -{ - GstMPEGAudioParse *mp3parse; - gboolean res = FALSE; - - mp3parse = GST_MP3PARSE (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - res = mp3parse_handle_seek (mp3parse, event); - gst_event_unref (event); - break; - default: - res = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (mp3parse); - return res; -} - -static gboolean -mp3parse_src_query (GstPad * pad, GstQuery * query) -{ - GstFormat format; - GstClockTime total; - GstMPEGAudioParse *mp3parse; - gboolean res = FALSE; - GstPad *peer; - - mp3parse = GST_MP3PARSE (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION: - gst_query_parse_position (query, &format, NULL); - - if (format == GST_FORMAT_BYTES || format == GST_FORMAT_DEFAULT) { - if (mp3parse->cur_offset != -1) { - gst_query_set_position (query, GST_FORMAT_BYTES, - mp3parse->cur_offset); - res = TRUE; - } - } else if (format == GST_FORMAT_TIME) { - if (mp3parse->next_ts == GST_CLOCK_TIME_NONE) - goto out; - gst_query_set_position (query, GST_FORMAT_TIME, mp3parse->next_ts); - res = TRUE; - } - - /* If no answer above, see if upstream knows */ - if (!res) { - if ((peer = gst_pad_get_peer (mp3parse->sinkpad)) != NULL) { - res = gst_pad_query (peer, query); - gst_object_unref (peer); - if (res) - goto out; - } - } - break; - case GST_QUERY_DURATION: - gst_query_parse_duration (query, &format, NULL); - - /* First, see if upstream knows */ - if ((peer = gst_pad_get_peer (mp3parse->sinkpad)) != NULL) { - res = gst_pad_query (peer, query); - gst_object_unref (peer); - if (res) - goto out; - } - - if (format == GST_FORMAT_TIME) { - if (!mp3parse_total_time (mp3parse, &total) || total == -1) - goto out; - gst_query_set_duration (query, format, total); - res = TRUE; - } - break; - case GST_QUERY_SEEKING: - gst_query_parse_seeking (query, &format, NULL, NULL, NULL); - - /* does upstream handle ? */ - if ((peer = gst_pad_get_peer (mp3parse->sinkpad)) != NULL) { - res = gst_pad_query (peer, query); - gst_object_unref (peer); - } - /* we may be able to help if in TIME */ - if (format == GST_FORMAT_TIME) { - gboolean seekable; - - gst_query_parse_seeking (query, &format, &seekable, NULL, NULL); - /* already OK if upstream takes care */ - if (!(res && seekable)) { - gint64 pos; - - seekable = TRUE; - if (!mp3parse_total_time (mp3parse, &total) || total == -1) { - seekable = FALSE; - } else if (!mp3parse_time_to_bytepos (mp3parse, 0, &pos)) { - seekable = FALSE; - } else { - GstQuery *q; - - q = gst_query_new_seeking (GST_FORMAT_BYTES); - if (!gst_pad_peer_query (mp3parse->sinkpad, q)) { - seekable = FALSE; - } else { - gst_query_parse_seeking (q, &format, &seekable, NULL, NULL); - } - gst_query_unref (q); - } - gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, total); - res = TRUE; - } - } - break; - default: - res = gst_pad_query_default (pad, query); - break; - } - -out: - gst_object_unref (mp3parse); - return res; -} - -static const GstQueryType * -mp3parse_get_query_types (GstPad * pad G_GNUC_UNUSED) -{ - static const GstQueryType query_types[] = { - GST_QUERY_POSITION, - GST_QUERY_DURATION, - 0 - }; - - return query_types; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/mpegaudioparse/gstmpegaudioparse.h --- a/gst_plugins_good/gst/mpegaudioparse/gstmpegaudioparse.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* GStreamer - * 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. - */ - - -#ifndef __MP3PARSE_H__ -#define __MP3PARSE_H__ - - -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_MP3PARSE \ - (gst_mp3parse_get_type()) -#define GST_MP3PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MP3PARSE,GstMPEGAudioParse)) -#define GST_MP3PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MP3PARSE,GstMPEGAudioParseClass)) -#define GST_IS_MP3PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MP3PARSE)) -#define GST_IS_MP3PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MP3PARSE)) - -typedef struct _GstMPEGAudioParse GstMPEGAudioParse; -typedef struct _GstMPEGAudioParseClass GstMPEGAudioParseClass; -typedef struct _MPEGAudioSeekEntry MPEGAudioSeekEntry; -typedef struct _MPEGAudioPendingAccurateSeek MPEGAudioPendingAccurateSeek; - - -struct _MPEGAudioSeekEntry { - gint64 byte; - GstClockTime timestamp; -}; - -struct _MPEGAudioPendingAccurateSeek { - GstSegment segment; - gint64 upstream_start; - GstClockTime timestamp_start; -}; - -struct _GstMPEGAudioParse { - GstElement element; - - GstPad *sinkpad, *srcpad; - - GstSegment segment; - GstClockTime next_ts; - gboolean discont; - - /* Offset as supplied by incoming buffers */ - gint64 cur_offset; - - /* Upcoming timestamp given on an incoming buffer and - * the offset at which it becomes active */ - GstClockTime pending_ts; - gint64 pending_offset; - /* Offset since the last newseg */ - gint64 tracked_offset; - /* tracked_offset when resyncing started */ - gint64 sync_offset; - - GstAdapter *adapter; - - guint skip; /* number of frames to skip */ - guint bit_rate; /* in kbps */ - gint channels, rate, layer, version; - GstClockTime max_bitreservoir; - gint spf; /* Samples per frame */ - - gboolean resyncing; /* True when attempting to resync (stricter checks are - performed) */ - gboolean sent_codec_tag; - - /* VBR tracking */ - guint avg_bitrate; - guint64 bitrate_sum; - guint frame_count; - guint last_posted_bitrate; - gint last_posted_crc; - guint last_posted_channel_mode; - - /* Xing info */ - guint32 xing_flags; - guint32 xing_frames; - GstClockTime xing_total_time; - guint32 xing_bytes; - /* percent -> filepos mapping */ - guchar xing_seek_table[100]; - /* filepos -> percent mapping */ - guint16 xing_seek_table_inverse[256]; - guint32 xing_vbr_scale; - guint xing_bitrate; - - /* VBRI info */ - guint32 vbri_frames; - GstClockTime vbri_total_time; - guint32 vbri_bytes; - guint vbri_bitrate; - guint vbri_seek_points; - guint32 *vbri_seek_table; - gboolean vbri_valid; - - /* Accurate seeking */ - GList *seek_table; - GMutex *pending_seeks_lock; - GSList *pending_accurate_seeks; - gboolean exact_position; - - GSList *pending_nonaccurate_seeks; - - /* Track whether we're seekable (in BYTES format, if upstream operates in - * TIME format, we don't care about seekability and assume upstream handles - * it). The seek table for accurate seeking is not maintained if we're not - * seekable. */ - gboolean seekable; - - /* minimum distance between two index entries */ - GstClockTimeDiff idx_interval; - - /* pending segment */ - GstEvent *pending_segment; - /* pending events */ - GList *pending_events; -}; - -struct _GstMPEGAudioParseClass { - GstElementClass parent_class; -}; - -#ifdef __SYMBIAN32__ -IMPORT_C -#endif -GType gst_mp3parse_get_type(void); - -G_END_DECLS - -#endif /* __MP3PARSE_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/mpegaudioparse/gstxingmux.c --- a/gst_plugins_good/gst/mpegaudioparse/gstxingmux.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,681 +0,0 @@ -/* - * Copyright (c) 2006 Christophe Fergeau - * Copyright (c) 2008 Sebastian Dröge - * - * 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. - */ - -/* Xing SDK: http://www.mp3-tech.org/programmer/sources/vbrheadersdk.zip */ - - -/** - * SECTION:element-xingmux - * - * xingmux adds a Xing header to MP3 files. This contains information about the duration and size - * of the file and a seek table and is very useful for getting an almost correct duration and better - * seeking on VBR MP3 files. - * - * This element will remove any existing Xing, LAME or VBRI headers from the beginning of the file. - * - * - * Example launch line - * |[ - * gst-launch audiotestsrc num-buffers=1000 ! audioconvert ! lame ! xingmux ! filesink location=test.mp3 - * gst-launch filesrc location=test.mp3 ! xingmux ! filesink location=test2.mp3 - * gst-launch filesrc location=test.mp3 ! mp3parse ! xingmux ! filesink location=test2.mp3 - * ]| - * - */ - -#ifdef HAVE_CONFIG_H -#include "../../config.h" -#endif - -#include -#include "gstxingmux.h" - -GST_DEBUG_CATEGORY_STATIC (xing_mux_debug); -#define GST_CAT_DEFAULT xing_mux_debug - -GST_BOILERPLATE (GstXingMux, gst_xing_mux, GstElement, GST_TYPE_ELEMENT); - -/* Xing Header stuff */ -#define GST_XING_FRAME_FIELD (1 << 0) -#define GST_XING_BYTES_FIELD (1 << 1) -#define GST_XING_TOC_FIELD (1 << 2) -#define GST_XING_QUALITY_FIELD (1 << 3) - -typedef struct _GstXingSeekEntry -{ - gint64 timestamp; - gint byte; -} GstXingSeekEntry; - -static inline GstXingSeekEntry * -gst_xing_seek_entry_new () -{ - return g_slice_new (GstXingSeekEntry); -} - -static inline void -gst_xing_seek_entry_free (GstXingSeekEntry * entry) -{ - g_slice_free (GstXingSeekEntry, entry); -} - -static void gst_xing_mux_finalize (GObject * obj); -static GstStateChangeReturn -gst_xing_mux_change_state (GstElement * element, GstStateChange transition); -static GstFlowReturn gst_xing_mux_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_xing_mux_sink_event (GstPad * pad, GstEvent * event); - -static GstStaticPadTemplate gst_xing_mux_sink_template = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/mpeg, " - "mpegversion = (int) 1, " "layer = (int) [ 1, 3 ]")); - - -static GstStaticPadTemplate gst_xing_mux_src_template = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/mpeg, " - "mpegversion = (int) 1, " "layer = (int) [ 1, 3 ]")); -static const guint mp3types_bitrates[2][3][16] = { - { - {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,}, - {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,}, - {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,} - }, - { - {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,}, - {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}, - {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,} - }, -}; - -static const guint mp3types_freqs[3][3] = { {44100, 48000, 32000}, -{22050, 24000, 16000}, -{11025, 12000, 8000} -}; - -static gboolean -parse_header (guint32 header, guint * ret_size, guint * ret_spf, - gulong * ret_rate) -{ - guint length, spf; - gulong samplerate, bitrate, layer, padding; - gint lsf, mpg25; - - if ((header & 0xffe00000) != 0xffe00000) { - g_warning ("invalid sync"); - return FALSE; - } - - if (((header >> 19) & 3) == 0x01) { - g_warning ("invalid MPEG version"); - return FALSE; - } - - if (((header >> 17) & 3) == 0x00) { - g_warning ("invalid MPEG layer"); - return FALSE; - } - - if (((header >> 12) & 0xf) == 0xf || ((header >> 12) & 0xf) == 0x0) { - g_warning ("invalid bitrate"); - return FALSE; - } - - if (((header >> 10) & 0x3) == 0x3) { - g_warning ("invalid sampling rate"); - return FALSE; - } - - if (header & 0x00000002) { - g_warning ("invalid emphasis"); - return FALSE; - } - - if (header & (1 << 20)) { - lsf = (header & (1 << 19)) ? 0 : 1; - mpg25 = 0; - } else { - lsf = 1; - mpg25 = 1; - } - - layer = 4 - ((header >> 17) & 0x3); - - bitrate = (header >> 12) & 0xF; - bitrate = mp3types_bitrates[lsf][layer - 1][bitrate] * 1000; - if (bitrate == 0) - return 0; - - samplerate = (header >> 10) & 0x3; - samplerate = mp3types_freqs[lsf + mpg25][samplerate]; - - padding = (header >> 9) & 0x1; - - switch (layer) { - case 1: - length = 4 * ((bitrate * 12) / samplerate + padding); - break; - case 2: - length = (bitrate * 144) / samplerate + padding; - break; - default: - case 3: - length = (bitrate * 144) / (samplerate << lsf) + padding; - break; - } - - if (layer == 1) - spf = 384; - else if (layer == 2 || lsf == 0) - spf = 1152; - else - spf = 576; - - if (ret_size) - *ret_size = length; - if (ret_spf) - *ret_spf = spf; - if (ret_rate) - *ret_rate = samplerate; - - return TRUE; -} - -static guint -get_xing_offset (guint32 header) -{ - guint mpeg_version = (header >> 19) & 0x3; - guint channel_mode = (header >> 6) & 0x3; - - if (mpeg_version == 0x3) { - if (channel_mode == 0x3) { - return 0x11; - } else { - return 0x20; - } - } else { - if (channel_mode == 0x3) { - return 0x09; - } else { - return 0x11; - } - } -} - -static gboolean -has_xing_header (guint32 header, guchar * data, gsize size) -{ - data += 4; - data += get_xing_offset (header); - - if (memcmp (data, "Xing", 4) == 0 || - memcmp (data, "Info", 4) == 0 || memcmp (data, "VBRI", 4) == 0) - return TRUE; - else - return FALSE; -} - -static GstBuffer * -generate_xing_header (GstXingMux * xing) -{ - guint8 *xing_flags; - guint32 xing_flags_tmp = 0; - GstBuffer *xing_header; - guchar *data; - - guint32 header; - guint32 header_be; - guint size, spf, xing_offset; - gulong rate; - guint bitrate = 0x00; - - gint64 duration; - gint64 byte_count; - - header = xing->first_header; - - /* Set bitrate and choose lowest possible size */ - do { - bitrate++; - - header &= 0xffff0fff; - header |= bitrate << 12; - - parse_header (header, &size, &spf, &rate); - xing_offset = get_xing_offset (header); - } while (size < (4 + xing_offset + 4 + 4 + 4 + 4 + 100) && bitrate < 0xe); - - if (bitrate == 0xe) { - GST_ERROR ("No usable bitrate found!"); - return NULL; - } - - if (gst_pad_alloc_buffer_and_set_caps (xing->srcpad, 0, size, - GST_PAD_CAPS (xing->srcpad), &xing_header) != GST_FLOW_OK) { - xing_header = gst_buffer_new_and_alloc (size); - gst_buffer_set_caps (xing_header, GST_PAD_CAPS (xing->srcpad)); - } - - data = GST_BUFFER_DATA (xing_header); - memset (data, 0, size); - header_be = GUINT32_TO_BE (header); - memcpy (data, &header_be, 4); - - data += 4; - data += xing_offset; - - memcpy (data, "Xing", 4); - data += 4; - - xing_flags = data; - data += 4; - - if (xing->duration != GST_CLOCK_TIME_NONE) { - duration = xing->duration; - } else { - GstFormat fmt = GST_FORMAT_TIME; - - if (!gst_pad_query_peer_duration (xing->sinkpad, &fmt, &duration)) - duration = GST_CLOCK_TIME_NONE; - } - - if (duration != GST_CLOCK_TIME_NONE) { - guint32 number_of_frames; - - /* The Xing Header contains a NumberOfFrames field, which verifies to: - * Duration = NumberOfFrames *SamplesPerFrame/SamplingRate - * SamplesPerFrame and SamplingRate are values for the current frame. - */ - number_of_frames = gst_util_uint64_scale (duration, rate, GST_SECOND) / spf; - GST_DEBUG ("Setting number of frames to %u", number_of_frames); - number_of_frames = GUINT32_TO_BE (number_of_frames); - memcpy (data, &number_of_frames, 4); - xing_flags_tmp |= GST_XING_FRAME_FIELD; - data += 4; - } - - if (xing->byte_count != 0) { - byte_count = xing->byte_count; - } else { - GstFormat fmt = GST_FORMAT_BYTES; - - if (!gst_pad_query_peer_duration (xing->sinkpad, &fmt, &byte_count)) - byte_count = 0; - if (byte_count == -1) - byte_count = 0; - } - - if (byte_count != 0) { - guint32 nbytes; - - if (byte_count > G_MAXUINT32) { - GST_DEBUG ("Too large stream: %" G_GINT64_FORMAT " > %u bytes", - byte_count, G_MAXUINT32); - } else { - nbytes = byte_count; - GST_DEBUG ("Setting number of bytes to %u", nbytes); - nbytes = GUINT32_TO_BE (nbytes); - memcpy (data, &nbytes, 4); - xing_flags_tmp |= GST_XING_BYTES_FIELD; - data += 4; - } - } - - if (xing->seek_table != NULL && byte_count != 0 - && duration != GST_CLOCK_TIME_NONE) { - GList *it; - gint percent = 0; - - xing_flags_tmp |= GST_XING_TOC_FIELD; - - GST_DEBUG ("Writing seek table"); - for (it = xing->seek_table; it != NULL && percent < 100; it = it->next) { - GstXingSeekEntry *entry = (GstXingSeekEntry *) it->data; - gint64 pos; - guchar byte; - - while ((entry->timestamp * 100) / duration >= percent) { - pos = (entry->byte * 256) / byte_count; - GST_DEBUG (" %d %% -- %" G_GINT64_FORMAT " 1/256", percent, pos); - byte = (guchar) pos; - memcpy (data, &byte, 1); - data++; - percent++; - } - } - - if (percent < 100) { - guchar b; - gint i; - - memcpy (&b, data - 1, 1); - - for (i = percent; i < 100; i++) { - GST_DEBUG (" %d %% -- %d 1/256", i, b); - memcpy (data, &b, 1); - data++; - } - } - } - - GST_DEBUG ("Setting Xing flags to 0x%x\n", xing_flags_tmp); - xing_flags_tmp = GUINT32_TO_BE (xing_flags_tmp); - memcpy (xing_flags, &xing_flags_tmp, 4); - return xing_header; -} - -static void -gst_xing_mux_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - static const GstElementDetails gst_xing_mux_details = - GST_ELEMENT_DETAILS ("MP3 Xing muxer", - "Formatter/Metadata", - "Adds a Xing header to the beginning of a VBR MP3 file", - "Christophe Fergeau "); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_xing_mux_src_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_xing_mux_sink_template)); - - GST_DEBUG_CATEGORY_INIT (xing_mux_debug, "xingmux", 0, "Xing Header Muxer"); - - gst_element_class_set_details (element_class, &gst_xing_mux_details); -} - -static void -gst_xing_mux_class_init (GstXingMuxClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_xing_mux_finalize); - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_xing_mux_change_state); -} - -static void -gst_xing_mux_finalize (GObject * obj) -{ - GstXingMux *xing = GST_XING_MUX (obj); - - if (xing->adapter) { - g_object_unref (xing->adapter); - xing->adapter = NULL; - } - - if (xing->seek_table) { - g_list_foreach (xing->seek_table, (GFunc) gst_xing_seek_entry_free, NULL); - g_list_free (xing->seek_table); - xing->seek_table = NULL; - } - - G_OBJECT_CLASS (parent_class)->finalize (obj); -} - -static void -xing_reset (GstXingMux * xing) -{ - xing->duration = GST_CLOCK_TIME_NONE; - xing->byte_count = 0; - - gst_adapter_clear (xing->adapter); - - if (xing->seek_table) { - g_list_foreach (xing->seek_table, (GFunc) gst_xing_seek_entry_free, NULL); - g_list_free (xing->seek_table); - xing->seek_table = NULL; - } - - xing->sent_xing = FALSE; -} - - -static void -gst_xing_mux_init (GstXingMux * xing, GstXingMuxClass * xingmux_class) -{ - GstElementClass *klass = GST_ELEMENT_CLASS (xingmux_class); - - /* pad through which data comes in to the element */ - xing->sinkpad = - gst_pad_new_from_template (gst_element_class_get_pad_template (klass, - "sink"), "sink"); - gst_pad_set_setcaps_function (xing->sinkpad, - GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps)); - gst_pad_set_chain_function (xing->sinkpad, - GST_DEBUG_FUNCPTR (gst_xing_mux_chain)); - gst_pad_set_event_function (xing->sinkpad, - GST_DEBUG_FUNCPTR (gst_xing_mux_sink_event)); - gst_element_add_pad (GST_ELEMENT (xing), xing->sinkpad); - - /* pad through which data goes out of the element */ - xing->srcpad = - gst_pad_new_from_template (gst_element_class_get_pad_template (klass, - "src"), "src"); - gst_element_add_pad (GST_ELEMENT (xing), xing->srcpad); - - xing->adapter = gst_adapter_new (); - - xing_reset (xing); -} - -static GstFlowReturn -gst_xing_mux_chain (GstPad * pad, GstBuffer * buffer) -{ - GstXingMux *xing = GST_XING_MUX (GST_PAD_PARENT (pad)); - GstFlowReturn ret = GST_FLOW_OK; - - gst_adapter_push (xing->adapter, buffer); - - while (gst_adapter_available (xing->adapter) >= 4) { - const guchar *data = gst_adapter_peek (xing->adapter, 4); - guint32 header; - GstBuffer *outbuf; - GstClockTime duration; - guint size, spf; - gulong rate; - GstXingSeekEntry *seek_entry; - - header = GST_READ_UINT32_BE (data); - - if (!parse_header (header, &size, &spf, &rate)) { - GST_DEBUG ("Lost sync, resyncing"); - gst_adapter_flush (xing->adapter, 1); - continue; - } - - if (gst_adapter_available (xing->adapter) < size) - break; - - outbuf = gst_adapter_take_buffer (xing->adapter, size); - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (xing->srcpad)); - - if (!xing->sent_xing) { - if (has_xing_header (header, GST_BUFFER_DATA (outbuf), size)) { - GST_LOG_OBJECT (xing, "Dropping old Xing header"); - gst_buffer_unref (outbuf); - continue; - } else { - GstBuffer *xing_header; - guint64 xing_header_size; - - xing->first_header = header; - - xing_header = generate_xing_header (xing); - - if (xing_header == NULL) { - GST_ERROR ("Can't generate Xing header"); - gst_buffer_unref (outbuf); - return GST_FLOW_ERROR; - } - - xing_header_size = GST_BUFFER_SIZE (xing_header); - - if (GST_FLOW_IS_FATAL (ret = gst_pad_push (xing->srcpad, xing_header))) { - GST_ERROR_OBJECT (xing, "Failed to push Xing header: %s", - gst_flow_get_name (ret)); - gst_buffer_unref (xing_header); - gst_buffer_unref (outbuf); - return ret; - } - - xing->byte_count += xing_header_size; - xing->sent_xing = TRUE; - } - } - - seek_entry = gst_xing_seek_entry_new (); - seek_entry->timestamp = - (xing->duration == GST_CLOCK_TIME_NONE) ? 0 : xing->duration; - /* Workaround for parsers checking that the first seek table entry is 0 */ - seek_entry->byte = (seek_entry->timestamp == 0) ? 0 : xing->byte_count; - xing->seek_table = g_list_append (xing->seek_table, seek_entry); - - duration = gst_util_uint64_scale (spf, GST_SECOND, rate); - - GST_BUFFER_TIMESTAMP (outbuf) = - (xing->duration == GST_CLOCK_TIME_NONE) ? 0 : xing->duration; - GST_BUFFER_DURATION (outbuf) = duration; - GST_BUFFER_OFFSET (outbuf) = xing->byte_count; - GST_BUFFER_OFFSET_END (outbuf) = - xing->byte_count + GST_BUFFER_SIZE (outbuf); - - xing->byte_count += GST_BUFFER_SIZE (outbuf); - - if (xing->duration == GST_CLOCK_TIME_NONE) - xing->duration = duration; - else - xing->duration += duration; - - if (GST_FLOW_IS_FATAL (ret = gst_pad_push (xing->srcpad, outbuf))) { - GST_ERROR_OBJECT (xing, "Failed to push MP3 frame: %s", - gst_flow_get_name (ret)); - return ret; - } - } - - return ret; -} - -static gboolean -gst_xing_mux_sink_event (GstPad * pad, GstEvent * event) -{ - GstXingMux *xing; - gboolean result; - - xing = GST_XING_MUX (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - if (xing->sent_xing) { - GST_ERROR ("Already sent Xing header, dropping NEWSEGMENT event!"); - gst_event_unref (event); - result = FALSE; - } else { - GstFormat fmt; - - gst_event_parse_new_segment (event, NULL, NULL, &fmt, NULL, NULL, NULL); - - if (fmt == GST_FORMAT_BYTES) { - result = gst_pad_push_event (xing->srcpad, event); - } else { - gst_event_unref (event); - - event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, - 0, GST_CLOCK_TIME_NONE, 0); - - result = gst_pad_push_event (xing->srcpad, event); - } - } - break; - - case GST_EVENT_EOS:{ - GstEvent *n_event; - - GST_DEBUG_OBJECT (xing, "handling EOS event"); - - if (xing->sent_xing) { - - n_event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, - 0, GST_CLOCK_TIME_NONE, 0); - - if (G_UNLIKELY (!gst_pad_push_event (xing->srcpad, n_event))) { - GST_WARNING - ("Failed to seek to position 0 for pushing the Xing header"); - } else { - GstBuffer *header; - GstFlowReturn ret; - - header = generate_xing_header (xing); - - if (header == NULL) { - GST_ERROR ("Can't generate Xing header"); - } else { - - GST_INFO ("Writing real Xing header to beginning of stream"); - - if (GST_FLOW_IS_FATAL (ret = gst_pad_push (xing->srcpad, header))) - GST_WARNING ("Failed to push updated Xing header: %s\n", - gst_flow_get_name (ret)); - } - } - } - result = gst_pad_push_event (xing->srcpad, event); - break; - } - default: - result = gst_pad_event_default (pad, event); - break; - } - gst_object_unref (GST_OBJECT (xing)); - - return result; -} - - -static GstStateChangeReturn -gst_xing_mux_change_state (GstElement * element, GstStateChange transition) -{ - GstXingMux *xing; - GstStateChangeReturn result; - - xing = GST_XING_MUX (element); - - result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - xing_reset (xing); - break; - default: - break; - } - - return result; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/mpegaudioparse/gstxingmux.h --- a/gst_plugins_good/gst/mpegaudioparse/gstxingmux.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2006 Christophe Fergeau - * Copyright (c) 2008 Sebastian Dröge - * - * 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. - */ - -#include -#include - -#ifndef __GST_XINGMUX_H__ -#define __GST_XINGMUX_H__ - -G_BEGIN_DECLS - -/* Standard macros for defining types for this element. */ -#define GST_TYPE_XING_MUX \ - (gst_xing_mux_get_type()) -#define GST_XING_MUX(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XING_MUX,GstXingMux)) -#define GST_XING_MUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_XING_MUX,GstXingMuxClass)) -#define GST_IS_XING_MUX(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XING_MUX)) -#define GST_IS_XING_MUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XING_MUX)) - -typedef struct _GstXingMux GstXingMux; -typedef struct _GstXingMuxClass GstXingMuxClass; - -/* Definition of structure storing data for this element. */ - -/** - * GstXingMux: - * - * Opaque data structure. - */ -struct _GstXingMux { - GstElement element; - - GstPad *sinkpad, *srcpad; - - /* < private > */ - - GstAdapter *adapter; - GstClockTime duration; - guint64 byte_count; - guint64 frame_count; - GList *seek_table; - gboolean sent_xing; - - /* Copy of the first frame header */ - guint32 first_header; -}; - -/* Standard definition defining a class for this element. */ - -/** - * GstXingMuxClass: - * - * Opaque data structure. - */ -struct _GstXingMuxClass { - GstElementClass parent_class; -}; - -/* Standard function returning type information. */ -#ifdef __SYMBIAN32__ -IMPORT_C -#endif -GType gst_xing_mux_get_type (void); - -G_END_DECLS - -#endif /* __GST_XINGMUX_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/mpegaudioparse/plugin.c --- a/gst_plugins_good/gst/mpegaudioparse/plugin.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* GStreamer - * Copyright (C) <2008> Jan Schmidt - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "../../config.h" -#endif - -#include -#include "gstmpegaudioparse.h" -#include "gstxingmux.h" - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "xingmux", GST_RANK_NONE, - GST_TYPE_XING_MUX)) - return FALSE; - if (!gst_element_register (plugin, "mp3parse", GST_RANK_PRIMARY + 1, - GST_TYPE_MP3PARSE)) - return FALSE; - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "mpegaudioparse", - "MPEG-1 layer 1/2/3 audio stream elements", - plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); -EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC() -{ - return &gst_plugin_desc; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/qtdemux/gstrtpxqtdepay.c --- a/gst_plugins_good/gst/qtdemux/gstrtpxqtdepay.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,704 +0,0 @@ -/* GStreamer - * Copyright (C) <2006> Wim Taymans - * - * 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. - */ - -/* - * based on http://developer.apple.com/quicktime/icefloe/dispatch026.html - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include - -#include -#include "gstrtpxqtdepay.h" - -#define MAKE_TLV(a,b) (((a)<<8)|(b)) - -#define TLV_sd MAKE_TLV ('s','d') -#define TLV_qt MAKE_TLV ('q','t') -#define TLV_ti MAKE_TLV ('t','i') -#define TLV_ly MAKE_TLV ('l','y') -#define TLV_vo MAKE_TLV ('v','o') -#define TLV_mx MAKE_TLV ('m','x') -#define TLV_tr MAKE_TLV ('t','r') -#define TLV_tw MAKE_TLV ('t','w') -#define TLV_th MAKE_TLV ('t','h') -#define TLV_la MAKE_TLV ('l','a') -#define TLV_rt MAKE_TLV ('r','t') -#define TLV_gm MAKE_TLV ('g','m') -#define TLV_oc MAKE_TLV ('o','c') -#define TLV_cr MAKE_TLV ('c','r') -#define TLV_du MAKE_TLV ('d','u') -#define TLV_po MAKE_TLV ('p','o') - -#define QT_UINT32(a) (GST_READ_UINT32_BE(a)) -#define QT_UINT24(a) (GST_READ_UINT32_BE(a) >> 8) -#define QT_UINT16(a) (GST_READ_UINT16_BE(a)) -#define QT_UINT8(a) (GST_READ_UINT8(a)) -#define QT_FP32(a) ((GST_READ_UINT32_BE(a))/65536.0) -#define QT_FP16(a) ((GST_READ_UINT16_BE(a))/256.0) -#define QT_FOURCC(a) (GST_READ_UINT32_LE(a)) -#define QT_UINT64(a) ((((guint64)QT_UINT32(a))<<32)|QT_UINT32(((guint8 *)a)+4)) - -#define FOURCC_avc1 GST_MAKE_FOURCC('a','v','c','1') -#define FOURCC_avcC GST_MAKE_FOURCC('a','v','c','C') - -GST_DEBUG_CATEGORY_STATIC (rtpxqtdepay_debug); -#define GST_CAT_DEFAULT (rtpxqtdepay_debug) - -/* elementfactory information */ -static const GstElementDetails gst_rtp_xqtdepay_details = -GST_ELEMENT_DETAILS ("RTP packet depayloader", - "Codec/Depayloader/Network", - "Extracts Quicktime audio/video from RTP packets", - "Wim Taymans "); - -/* RtpXQTDepay signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - ARG_0, -}; - -static GstStaticPadTemplate gst_rtp_xqt_depay_src_template = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY); - -static GstStaticPadTemplate gst_rtp_xqt_depay_sink_template = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/x-rtp, " - "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", " - "media = (string) { \"audio\", \"video\" }, clock-rate = (int) [1, MAX], " - "encoding-name = (string) { \"X-QT\", \"X-QUICKTIME\" }") - ); - -GST_BOILERPLATE (GstRtpXQTDepay, gst_rtp_xqt_depay, GstBaseRTPDepayload, - GST_TYPE_BASE_RTP_DEPAYLOAD); - -static void gst_rtp_xqt_depay_finalize (GObject * object); - -static gboolean gst_rtp_xqt_depay_setcaps (GstBaseRTPDepayload * depayload, - GstCaps * caps); -static GstBuffer *gst_rtp_xqt_depay_process (GstBaseRTPDepayload * depayload, - GstBuffer * buf); - -static GstStateChangeReturn gst_rtp_xqt_depay_change_state (GstElement * - element, GstStateChange transition); - -static void -gst_rtp_xqt_depay_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_rtp_xqt_depay_src_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_rtp_xqt_depay_sink_template)); - - gst_element_class_set_details (element_class, &gst_rtp_xqtdepay_details); -} - -static void -gst_rtp_xqt_depay_class_init (GstRtpXQTDepayClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - GstBaseRTPDepayloadClass *gstbasertpdepayload_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->finalize = gst_rtp_xqt_depay_finalize; - - gstelement_class->change_state = gst_rtp_xqt_depay_change_state; - - gstbasertpdepayload_class->set_caps = gst_rtp_xqt_depay_setcaps; - gstbasertpdepayload_class->process = gst_rtp_xqt_depay_process; - - GST_DEBUG_CATEGORY_INIT (rtpxqtdepay_debug, "rtpxqtdepay", 0, - "QT Media RTP Depayloader"); -} - -static void -gst_rtp_xqt_depay_init (GstRtpXQTDepay * rtpxqtdepay, - GstRtpXQTDepayClass * klass) -{ - rtpxqtdepay->adapter = gst_adapter_new (); -} - -static void -gst_rtp_xqt_depay_finalize (GObject * object) -{ - GstRtpXQTDepay *rtpxqtdepay; - - rtpxqtdepay = GST_RTP_XQT_DEPAY (object); - - g_object_unref (rtpxqtdepay->adapter); - rtpxqtdepay->adapter = NULL; - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static gboolean -gst_rtp_quicktime_parse_sd (GstRtpXQTDepay * rtpxqtdepay, guint8 * data, - guint data_len) -{ - gint len; - guint32 fourcc; - - if (data_len < 8) - goto too_short; - - len = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; - if (len > data_len) - goto too_short; - - fourcc = QT_FOURCC (data + 4); - - GST_DEBUG_OBJECT (rtpxqtdepay, "parsing %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (fourcc)); - - switch (fourcc) { - case FOURCC_avc1: - { - guint32 chlen; - - if (len < 0x56) - goto too_short; - len -= 0x56; - data += 0x56; - - /* find avcC */ - while (len >= 8) { - chlen = QT_UINT32 (data); - fourcc = QT_FOURCC (data + 4); - if (fourcc == FOURCC_avcC) { - GstBuffer *buf; - gint size; - GstCaps *caps; - - GST_DEBUG_OBJECT (rtpxqtdepay, "found avcC codec_data in sd, %u", - chlen); - - /* parse, if found */ - if (chlen < len) - size = chlen - 8; - else - size = len - 8; - - buf = gst_buffer_new_and_alloc (size); - memcpy (GST_BUFFER_DATA (buf), data + 8, size); - caps = gst_caps_new_simple ("video/x-h264", - "codec_data", GST_TYPE_BUFFER, buf, NULL); - gst_buffer_unref (buf); - gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD (rtpxqtdepay)->srcpad, caps); - gst_caps_unref (caps); - break; - } - len -= chlen; - data += chlen; - } - break; - } - default: - break; - } - return TRUE; - - /* ERRORS */ -too_short: - { - return FALSE; - } -} - -static gboolean -gst_rtp_xqt_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) -{ - GstStructure *structure; - gint clock_rate = 90000; /* default */ - - structure = gst_caps_get_structure (caps, 0); - - gst_structure_get_int (structure, "clock-rate", &clock_rate); - depayload->clock_rate = clock_rate; - - return TRUE; -} - -static GstBuffer * -gst_rtp_xqt_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) -{ - GstRtpXQTDepay *rtpxqtdepay; - GstBuffer *outbuf; - gboolean m; - - rtpxqtdepay = GST_RTP_XQT_DEPAY (depayload); - - if (!gst_rtp_buffer_validate (buf)) - goto bad_packet; - - if (GST_BUFFER_IS_DISCONT (buf)) { - /* discont, clear adapter and try to find a new packet start */ - gst_adapter_clear (rtpxqtdepay->adapter); - rtpxqtdepay->need_resync = TRUE; - GST_DEBUG_OBJECT (rtpxqtdepay, "we need resync"); - } - - m = gst_rtp_buffer_get_marker (buf); - GST_LOG_OBJECT (rtpxqtdepay, "marker: %d", m); - - { - gint payload_len; - guint avail; - guint8 *payload; - guint32 timestamp; - guint8 ver, pck; - gboolean s, q, l, d; - - payload_len = gst_rtp_buffer_get_payload_len (buf); - payload = gst_rtp_buffer_get_payload (buf); - - /* 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | VER |PCK|S|Q|L| RES |D| QuickTime Payload ID | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - if (payload_len <= 4) - goto wrong_length; - - ver = (payload[0] & 0xf0) >> 4; - if (ver > 1) - goto wrong_version; - - pck = (payload[0] & 0x0c) >> 2; - if (pck == 0) - goto pck_reserved; - - s = (payload[0] & 0x02) != 0; /* contains sync sample */ - q = (payload[0] & 0x01) != 0; /* has payload description */ - l = (payload[1] & 0x80) != 0; /* has packet specific information description */ - d = (payload[2] & 0x80) != 0; /* don't cache info for payload id */ - /* id used for caching info */ - rtpxqtdepay->current_id = ((payload[2] & 0x7f) << 8) | payload[3]; - - GST_LOG_OBJECT (rtpxqtdepay, - "VER: %d, PCK: %d, S: %d, Q: %d, L: %d, D: %d, ID: %d", ver, pck, s, q, - l, d, rtpxqtdepay->current_id); - - if (rtpxqtdepay->need_resync) { - /* we need to find the boundary of a new packet after a DISCONT */ - if (pck != 3 || q) { - /* non-fragmented packet or payload description present, packet starts - * here. */ - rtpxqtdepay->need_resync = FALSE; - } else { - /* fragmented packet without description */ - if (m) { - /* marker bit set, next packet is start of new one */ - rtpxqtdepay->need_resync = FALSE; - } - goto need_resync; - } - } - - payload += 4; - payload_len -= 4; - - if (q) { - gboolean k, f, a, z; - guint pdlen, pdpadded; - gint padding; - guint32 media_type, timescale; - - /* 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |K|F|A|Z| RES | QuickTime Payload Desc Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . QuickTime Payload Desc Data ... . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - if (payload_len <= 4) - goto wrong_length; - - k = (payload[0] & 0x80) != 0; /* keyframe */ - f = (payload[0] & 0x40) != 0; /* sparse */ - a = (payload[0] & 0x20) != 0; /* start of payload */ - z = (payload[0] & 0x10) != 0; /* end of payload */ - pdlen = (payload[2] << 8) | payload[3]; - - if (pdlen < 12) - goto wrong_length; - - /* calc padding */ - pdpadded = pdlen + 3; - pdpadded -= pdpadded % 4; - if (payload_len < pdpadded) - goto wrong_length; - - padding = pdpadded - pdlen; - GST_LOG_OBJECT (rtpxqtdepay, - "K: %d, F: %d, A: %d, Z: %d, len: %d, padding %d", k, f, a, z, pdlen, - padding); - - payload += 4; - payload_len -= 4; - /* 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | QuickTime Media Type | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Timescale | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . QuickTime TLVs ... . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - media_type = - (payload[0] << 24) | (payload[1] << 16) | (payload[2] << 8) | - payload[3]; - timescale = - (payload[4] << 24) | (payload[5] << 16) | (payload[6] << 8) | - payload[7]; - - GST_LOG_OBJECT (rtpxqtdepay, "media_type: %c%c%c%c, timescale %u", - payload[0], payload[1], payload[2], payload[3], timescale); - - payload += 8; - payload_len -= 8; - pdlen -= 12; - - /* parse TLV (type-length-value triplets */ - while (pdlen > 3) { - guint16 tlv_len, tlv_type; - - /* 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | QuickTime TLV Length | QuickTime TLV Type | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . QuickTime TLV Value ... . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - tlv_len = (payload[0] << 8) | payload[1]; - tlv_type = (payload[2] << 8) | payload[3]; - pdlen -= 4; - if (tlv_len > pdlen) - goto wrong_length; - - GST_LOG_OBJECT (rtpxqtdepay, "TLV '%c%c', len %d", payload[2], - payload[3], tlv_len); - - payload += 4; - payload_len -= 4; - - switch (tlv_type) { - case TLV_sd: - /* Session description */ - if (!gst_rtp_quicktime_parse_sd (rtpxqtdepay, payload, tlv_len)) - goto unknown_format; - rtpxqtdepay->have_sd = TRUE; - break; - case TLV_qt: - case TLV_ti: - case TLV_ly: - case TLV_vo: - case TLV_mx: - case TLV_tr: - case TLV_tw: - case TLV_th: - case TLV_la: - case TLV_rt: - case TLV_gm: - case TLV_oc: - case TLV_cr: - case TLV_du: - case TLV_po: - default: - break; - } - - pdlen -= tlv_len; - payload += tlv_len; - payload_len -= tlv_len; - } - payload += padding; - payload_len -= padding; - } - - if (l) { - guint ssilen, ssipadded; - gint padding; - - /* 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | RES | Sample-Specific Info Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . QuickTime TLVs ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - if (payload_len <= 4) - goto wrong_length; - - ssilen = (payload[2] << 8) | payload[3]; - if (ssilen < 4) - goto wrong_length; - - /* calc padding */ - ssipadded = ssilen + 3; - ssipadded -= ssipadded % 4; - if (payload_len < ssipadded) - goto wrong_length; - - padding = ssipadded - ssilen; - GST_LOG_OBJECT (rtpxqtdepay, "len: %d, padding %d", ssilen, padding); - - payload += 4; - payload_len -= 4; - ssilen -= 4; - - /* parse TLV (type-length-value triplets */ - while (ssilen > 3) { - guint16 tlv_len, tlv_type; - - /* 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | QuickTime TLV Length | QuickTime TLV Type | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . QuickTime TLV Value ... . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - tlv_len = (payload[0] << 8) | payload[1]; - tlv_type = (payload[2] << 8) | payload[3]; - ssilen -= 4; - if (tlv_len > ssilen) - goto wrong_length; - - GST_LOG_OBJECT (rtpxqtdepay, "TLV '%c%c', len %d", payload[2], - payload[3], tlv_len); - - payload += 4; - payload_len -= 4; - - switch (tlv_type) { - case TLV_sd: - case TLV_qt: - case TLV_ti: - case TLV_ly: - case TLV_vo: - case TLV_mx: - case TLV_tr: - case TLV_tw: - case TLV_th: - case TLV_la: - case TLV_rt: - case TLV_gm: - case TLV_oc: - case TLV_cr: - case TLV_du: - case TLV_po: - default: - break; - } - - ssilen -= tlv_len; - payload += tlv_len; - payload_len -= tlv_len; - } - payload += padding; - payload_len -= padding; - } - - timestamp = gst_rtp_buffer_get_timestamp (buf); - rtpxqtdepay->previous_id = rtpxqtdepay->current_id; - - switch (pck) { - case 1: - { - /* multiple samples per packet. */ - outbuf = gst_buffer_new_and_alloc (payload_len); - memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len); - return outbuf; - } - case 2: - { - guint slen, timestamp; - - /* multiple samples per packet. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |S| Reserved | Sample Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Sample Timestamp | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . Sample Data ... . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |S| Reserved | Sample Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Sample Timestamp | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . Sample Data ... . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . ...... . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - while (payload_len > 8) { - s = (payload[0] & 0x80) != 0; /* contains sync sample */ - slen = (payload[2] << 8) | payload[3]; - timestamp = - (payload[4] << 24) | (payload[5] << 16) | (payload[6] << 8) | - payload[7]; - - payload += 8; - payload_len -= 8; - - if (slen > payload_len) - slen = payload_len; - - outbuf = gst_buffer_new_and_alloc (slen); - memcpy (GST_BUFFER_DATA (outbuf), payload, slen); - if (!s) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); - - gst_base_rtp_depayload_push (depayload, outbuf); - - /* aligned on 32 bit boundary */ - slen = GST_ROUND_UP_4 (slen); - - payload += slen; - payload_len -= slen; - } - break; - } - case 3: - { - /* one sample per packet, use adapter to combine based on marker bit. */ - outbuf = gst_buffer_new_and_alloc (payload_len); - memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len); - - gst_adapter_push (rtpxqtdepay->adapter, outbuf); - - if (!m) - goto done; - - avail = gst_adapter_available (rtpxqtdepay->adapter); - outbuf = gst_adapter_take_buffer (rtpxqtdepay->adapter, avail); - - GST_DEBUG_OBJECT (rtpxqtdepay, - "gst_rtp_xqt_depay_chain: pushing buffer of size %u", avail); - - return outbuf; - } - } - } - -done: - return NULL; - -bad_packet: - { - GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, - ("Packet did not validate."), (NULL)); - return NULL; - } -need_resync: - { - GST_DEBUG_OBJECT (rtpxqtdepay, "waiting for marker"); - return NULL; - } -wrong_version: - { - GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, - ("Unknown payload version."), (NULL)); - return NULL; - } -pck_reserved: - { - GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, - ("PCK reserved 0."), (NULL)); - return NULL; - } -wrong_length: - { - GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, - ("Wrong payload length."), (NULL)); - return NULL; - } -unknown_format: - { - GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, - ("Unknown payload format."), (NULL)); - return NULL; - } -} - -static GstStateChangeReturn -gst_rtp_xqt_depay_change_state (GstElement * element, GstStateChange transition) -{ - GstRtpXQTDepay *rtpxqtdepay; - GstStateChangeReturn ret; - - rtpxqtdepay = GST_RTP_XQT_DEPAY (element); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_adapter_clear (rtpxqtdepay->adapter); - rtpxqtdepay->previous_id = -1; - rtpxqtdepay->current_id = -1; - rtpxqtdepay->need_resync = TRUE; - rtpxqtdepay->have_sd = FALSE; - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_adapter_clear (rtpxqtdepay->adapter); - default: - break; - } - return ret; -} - -gboolean -gst_rtp_xqt_depay_plugin_init (GstPlugin * plugin) -{ - return gst_element_register (plugin, "rtpxqtdepay", - GST_RANK_MARGINAL, GST_TYPE_RTP_XQT_DEPAY); -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/qtdemux/gstrtpxqtdepay.h --- a/gst_plugins_good/gst/qtdemux/gstrtpxqtdepay.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/* GStreamer - * Copyright (C) <2005> Wim Taymans - * - * 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. - */ - -#ifndef __GST_RTP_XQT_DEPAY_H__ -#define __GST_RTP_XQT_DEPAY_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -#define GST_TYPE_RTP_XQT_DEPAY \ - (gst_rtp_xqt_depay_get_type()) -#define GST_RTP_XQT_DEPAY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_XQT_DEPAY,GstRtpXQTDepay)) -#define GST_RTP_XQT_DEPAY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_XQT_DEPAY,GstRtpXQTDepayClass)) -#define GST_IS_RTP_XQT_DEPAY(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_XQT_DEPAY)) -#define GST_IS_RTP_XQT_DEPAY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_XQT_DEPAY)) - -typedef struct _GstRtpXQTDepay GstRtpXQTDepay; -typedef struct _GstRtpXQTDepayClass GstRtpXQTDepayClass; - -struct _GstRtpXQTDepay -{ - GstBaseRTPDepayload depayload; - - GstAdapter *adapter; - - gboolean need_resync; - guint16 previous_id; - guint16 current_id; - gboolean have_sd; -}; - -struct _GstRtpXQTDepayClass -{ - GstBaseRTPDepayloadClass parent_class; -}; - -#ifdef __SYMBIAN32__ -IMPORT_C -#endif -GType gst_rtp_xqt_depay_get_type (void); - -G_END_DECLS - -#endif /* __GST_RTP_XQT_DEPAY_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/qtdemux/qtdemux.c --- a/gst_plugins_good/gst/qtdemux/qtdemux.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6153 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2003> David A. Schleef - * Copyright (C) <2006> Wim Taymans - * Copyright (C) <2007> Julien Moutte - * - * 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. - */ - -/** - * SECTION:element-qtdemux - * - * Demuxes a .mov file into raw or compressed audio and/or video streams. - * - * This element supports both push and pull-based scheduling, depending on the - * capabilities of the upstream elements. - * - * - * Example launch line - * |[ - * gst-launch filesrc location=test.mov ! qtdemux name=demux demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink - * ]| Play (parse and decode) a .mov file and try to output it to - * an automatically detected soundcard and videosink. If the MOV file contains - * compressed audio or video data, this will only work if you have the - * right decoder elements/plugins installed. - * - * - * Last reviewed on 2006-12-29 (0.10.5) - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gst/gst-i18n-plugin.h" - -#include - -#include "qtdemux_types.h" -#include "qtdemux_dump.h" -#include "qtdemux_fourcc.h" -#include "qtdemux.h" -#include "qtpalette.h" - -#include -#include - -#ifdef HAVE_ZLIB -# include -#endif - -/* max. size considered 'sane' for non-mdat atoms */ -#define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024) - -GST_DEBUG_CATEGORY (qtdemux_debug); - -/*typedef struct _QtNode QtNode; */ -typedef struct _QtDemuxSegment QtDemuxSegment; -typedef struct _QtDemuxSample QtDemuxSample; - -/*struct _QtNode -{ - guint32 type; - guint8 *data; - gint len; -};*/ - -struct _QtDemuxSample -{ - guint32 size; - guint64 offset; - GstClockTimeDiff pts_offset; /* Add this value to timestamp to get the pts */ - guint64 timestamp; /* In GstClockTime */ - guint64 duration; /* in GstClockTime */ - gboolean keyframe; /* TRUE when this packet is a keyframe */ -}; - -/* - * Quicktime has tracks and segments. A track is a continuous piece of - * multimedia content. The track is not always played from start to finish but - * instead, pieces of the track are 'cut out' and played in sequence. This is - * what the segments do. - * - * Inside the track we have keyframes (K) and delta frames. The track has its - * own timing, which starts from 0 and extends to end. The position in the track - * is called the media_time. - * - * The segments now describe the pieces that should be played from this track - * and are basically tupples of media_time/duration/rate entries. We can have - * multiple segments and they are all played after one another. An example: - * - * segment 1: media_time: 1 second, duration: 1 second, rate 1 - * segment 2: media_time: 3 second, duration: 2 second, rate 2 - * - * To correctly play back this track, one must play: 1 second of media starting - * from media_time 1 followed by 2 seconds of media starting from media_time 3 - * at a rate of 2. - * - * Each of the segments will be played at a specific time, the first segment at - * time 0, the second one after the duration of the first one, etc.. Note that - * the time in resulting playback is not identical to the media_time of the - * track anymore. - * - * Visually, assuming the track has 4 second of media_time: - * - * (a) (b) (c) (d) - * .-----------------------------------------------------------. - * track: | K.....K.........K........K.......K.......K...........K... | - * '-----------------------------------------------------------' - * 0 1 2 3 4 - * .------------^ ^ .----------^ ^ - * / .-------------' / .------------------' - * / / .-----' / - * .--------------. .--------------. - * | segment 1 | | segment 2 | - * '--------------' '--------------' - * - * The challenge here is to cut out the right pieces of the track for each of - * the playback segments. This fortunatly can easily be done with the SEGMENT - * events of gstreamer. - * - * For playback of segment 1, we need to provide the decoder with the keyframe - * (a), in the above figure, but we must instruct it only to output the decoded - * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time - * position set to the time of the segment: 0. - * - * We then proceed to push data from keyframe (a) to frame (b). The decoder - * decodes but clips all before media_time 1. - * - * After finishing a segment, we push out a new SEGMENT event with the clipping - * boundaries of the new data. - * - * This is a good usecase for the GStreamer accumulated SEGMENT events. - */ - -struct _QtDemuxSegment -{ - /* global time and duration, all gst time */ - guint64 time; - guint64 stop_time; - guint64 duration; - /* media time of trak, all gst time */ - guint64 media_start; - guint64 media_stop; - gdouble rate; -}; - -struct _QtDemuxStream -{ - GstPad *pad; - - /* stream type */ - guint32 subtype; - GstCaps *caps; - guint32 fourcc; - - /* duration/scale */ - guint64 duration; /* in timescale */ - guint32 timescale; - - /* our samples */ - guint32 n_samples; - QtDemuxSample *samples; - gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */ - guint32 min_duration; /* duration in timescale of first sample, used for figuring out - the framerate, in timescale units */ - - /* if we use chunks or samples */ - gboolean sampled; - guint padding; - - /* video info */ - gint width; - gint height; - /* aspect ratio */ - gint display_width; - gint display_height; - gint par_w; - gint par_h; - /* Numerator/denominator framerate */ - gint fps_n; - gint fps_d; - guint16 bits_per_sample; - guint16 color_table_id; - - /* audio info */ - gdouble rate; - gint n_channels; - guint samples_per_packet; - guint samples_per_frame; - guint bytes_per_packet; - guint bytes_per_sample; - guint bytes_per_frame; - guint compression; - - /* when a discontinuity is pending */ - gboolean discont; - - /* list of buffers to push first */ - GSList *buffers; - - /* if we need to clip this buffer. This is only needed for uncompressed - * data */ - gboolean need_clip; - - /* current position */ - guint32 segment_index; - guint32 sample_index; - guint64 time_position; /* in gst time */ - - /* the Gst segment we are processing out, used for clipping */ - GstSegment segment; - - /* last GstFlowReturn */ - GstFlowReturn last_ret; - - /* quicktime segments */ - guint32 n_segments; - QtDemuxSegment *segments; - guint32 from_sample; - guint32 to_sample; - - gboolean sent_eos; -}; - -enum QtDemuxState -{ - QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */ - QTDEMUX_STATE_HEADER, /* Parsing the header */ - QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */ - QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */ -}; - -static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc); -static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc); - -static const GstElementDetails gst_qtdemux_details = -GST_ELEMENT_DETAILS ("QuickTime demuxer", - "Codec/Demuxer", - "Demultiplex a QuickTime file into audio and video streams", - "David Schleef , Wim Taymans "); - -static GstStaticPadTemplate gst_qtdemux_sink_template = - GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; " - "application/x-3gp") - ); - -static GstStaticPadTemplate gst_qtdemux_videosrc_template = -GST_STATIC_PAD_TEMPLATE ("video_%02d", - GST_PAD_SRC, - GST_PAD_SOMETIMES, - GST_STATIC_CAPS_ANY); - -static GstStaticPadTemplate gst_qtdemux_audiosrc_template = -GST_STATIC_PAD_TEMPLATE ("audio_%02d", - GST_PAD_SRC, - GST_PAD_SOMETIMES, - GST_STATIC_CAPS_ANY); - -static GstStaticPadTemplate gst_qtdemux_subpsrc_template = -GST_STATIC_PAD_TEMPLATE ("subp_%02d", - GST_PAD_SRC, - GST_PAD_SOMETIMES, - GST_STATIC_CAPS_ANY); - -static GstElementClass *parent_class = NULL; - -static void gst_qtdemux_class_init (GstQTDemuxClass * klass); -static void gst_qtdemux_base_init (GstQTDemuxClass * klass); -static void gst_qtdemux_init (GstQTDemux * quicktime_demux); -static void gst_qtdemux_dispose (GObject * object); - -static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element, - GstStateChange transition); -static gboolean qtdemux_sink_activate (GstPad * sinkpad); -static gboolean qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active); -static gboolean qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active); - -static void gst_qtdemux_loop (GstPad * pad); -static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf); -static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstEvent * event); - -static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, - int length); -static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, - const guint8 * buffer, int length); -static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux); - -static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux, - QtDemuxStream * stream, GNode * esds, GstTagList * list); -static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux, - QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data, - gchar ** codec_name); -static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux, - QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len, - gchar ** codec_name); -static GstCaps *qtdemux_subp_caps (GstQTDemux * qtdemux, - QtDemuxStream * stream, guint32 fourcc, const guint8 * data, - gchar ** codec_name); - -GType -gst_qtdemux_get_type (void) -{ - static GType qtdemux_type = 0; - - if (G_UNLIKELY (!qtdemux_type)) { - static const GTypeInfo qtdemux_info = { - sizeof (GstQTDemuxClass), - (GBaseInitFunc) gst_qtdemux_base_init, NULL, - (GClassInitFunc) gst_qtdemux_class_init, - NULL, NULL, sizeof (GstQTDemux), 0, - (GInstanceInitFunc) gst_qtdemux_init, - }; - - qtdemux_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstQTDemux", &qtdemux_info, - 0); - } - return qtdemux_type; -} - -static void -gst_qtdemux_base_init (GstQTDemuxClass * klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_qtdemux_sink_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_qtdemux_videosrc_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_qtdemux_audiosrc_template)); - gst_element_class_set_details (element_class, &gst_qtdemux_details); - - GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin"); -} - -static void -gst_qtdemux_class_init (GstQTDemuxClass * klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class->dispose = gst_qtdemux_dispose; - - gstelement_class->change_state = gst_qtdemux_change_state; -} - -static void -gst_qtdemux_init (GstQTDemux * qtdemux) -{ - qtdemux->sinkpad = - gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink"); - gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate); - gst_pad_set_activatepull_function (qtdemux->sinkpad, - qtdemux_sink_activate_pull); - gst_pad_set_activatepush_function (qtdemux->sinkpad, - qtdemux_sink_activate_push); - gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain); - gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event); - gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad); - - qtdemux->state = QTDEMUX_STATE_INITIAL; - /* FIXME, use segment last_stop for this */ - qtdemux->last_ts = GST_CLOCK_TIME_NONE; - qtdemux->pullbased = FALSE; - qtdemux->neededbytes = 16; - qtdemux->todrop = 0; - qtdemux->adapter = gst_adapter_new (); - qtdemux->offset = 0; - qtdemux->mdatoffset = GST_CLOCK_TIME_NONE; - qtdemux->mdatbuffer = NULL; - gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME); -} - -static void -gst_qtdemux_dispose (GObject * object) -{ - GstQTDemux *qtdemux = GST_QTDEMUX (object); - - if (qtdemux->adapter) { - g_object_unref (G_OBJECT (qtdemux->adapter)); - qtdemux->adapter = NULL; - } - - G_OBJECT_CLASS (parent_class)->dispose (object); -} - -static GstFlowReturn -gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size, - GstBuffer ** buf) -{ - GstFlowReturn flow; - - /* Sanity check: catch bogus sizes (fuzzed/broken files) */ - if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) { - GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE, - (_("This file is invalid and cannot be played.")), - ("atom has bogus size %" G_GUINT64_FORMAT, size)); - return GST_FLOW_ERROR; - } - - flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf); - - if (G_UNLIKELY (flow != GST_FLOW_OK)) - return flow; - - /* Catch short reads - we don't want any partial atoms */ - if (G_UNLIKELY (GST_BUFFER_SIZE (*buf) < size)) { - GST_WARNING_OBJECT (qtdemux, "short read: %u < %" G_GUINT64_FORMAT, - GST_BUFFER_SIZE (*buf), size); - gst_buffer_unref (*buf); - *buf = NULL; - return GST_FLOW_UNEXPECTED; - } - - return flow; -} - -#if 0 -static gboolean -gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value, - GstFormat * dest_format, gint64 * dest_value) -{ - gboolean res = TRUE; - QtDemuxStream *stream = gst_pad_get_element_private (pad); - - if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e') && - (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES)) - return FALSE; - - switch (src_format) { - case GST_FORMAT_TIME: - switch (*dest_format) { - case GST_FORMAT_BYTES: - *dest_value = src_value * 1; /* FIXME */ - break; - case GST_FORMAT_DEFAULT: - *dest_value = src_value * 1; /* FIXME */ - break; - default: - res = FALSE; - break; - } - break; - case GST_FORMAT_BYTES: - switch (*dest_format) { - case GST_FORMAT_TIME: - *dest_value = src_value * 1; /* FIXME */ - break; - default: - res = FALSE; - break; - } - break; - case GST_FORMAT_DEFAULT: - switch (*dest_format) { - case GST_FORMAT_TIME: - *dest_value = src_value * 1; /* FIXME */ - break; - default: - res = FALSE; - break; - } - break; - default: - res = FALSE; - } - - return res; -} -#endif - -static const GstQueryType * -gst_qtdemux_get_src_query_types (GstPad * pad) -{ - static const GstQueryType src_types[] = { - GST_QUERY_POSITION, - GST_QUERY_DURATION, - GST_QUERY_SEEKING, - 0 - }; - - return src_types; -} - -static gboolean -gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration) -{ - gboolean res = TRUE; - - *duration = GST_CLOCK_TIME_NONE; - - if (qtdemux->duration != 0) { - if (qtdemux->duration != G_MAXINT32 && qtdemux->timescale != 0) { - *duration = gst_util_uint64_scale (qtdemux->duration, - GST_SECOND, qtdemux->timescale); - } - } - return res; -} - -static gboolean -gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query) -{ - gboolean res = FALSE; - GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query)); - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION: - if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.last_stop)) { - gst_query_set_position (query, GST_FORMAT_TIME, - qtdemux->segment.last_stop); - res = TRUE; - } - break; - case GST_QUERY_DURATION:{ - GstFormat fmt; - - gst_query_parse_duration (query, &fmt, NULL); - if (fmt == GST_FORMAT_TIME) { - gint64 duration = -1; - - gst_qtdemux_get_duration (qtdemux, &duration); - if (duration > 0) { - gst_query_set_duration (query, GST_FORMAT_TIME, duration); - res = TRUE; - } - } - break; - } - case GST_QUERY_SEEKING:{ - GstFormat fmt; - gboolean seekable; - - gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL); - if (fmt == GST_FORMAT_TIME) { - gint64 duration = -1; - - gst_qtdemux_get_duration (qtdemux, &duration); - seekable = TRUE; - if (!qtdemux->pullbased) { - GstQuery *q; - - /* we might be able with help from upstream */ - seekable = FALSE; - q = gst_query_new_seeking (GST_FORMAT_BYTES); - if (gst_pad_peer_query (qtdemux->sinkpad, q)) { - gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL); - GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable); - } - gst_query_unref (q); - } - gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration); - res = TRUE; - } - break; - } - default: - res = gst_pad_query_default (pad, query); - break; - } - - gst_object_unref (qtdemux); - - return res; -} - -/* push event on all source pads; takes ownership of the event */ -static void -gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event) -{ - guint n; - - GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads", - GST_EVENT_TYPE_NAME (event)); - - for (n = 0; n < qtdemux->n_streams; n++) { - GstPad *pad; - - if ((pad = qtdemux->streams[n]->pad)) - gst_pad_push_event (pad, gst_event_ref (event)); - } - gst_event_unref (event); -} - -/* push a pending newsegment event, if any from the streaming thread */ -static void -gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux) -{ - if (qtdemux->pending_newsegment) { - gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment); - qtdemux->pending_newsegment = NULL; - } -} - -typedef struct -{ - guint64 media_time; -} FindData; - -static gint -find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data) -{ - if (s1->timestamp > *media_time) - return 1; - - return -1; -} - -/* find the index of the sample that includes the data for @media_time - * - * Returns the index of the sample. - */ -static guint32 -gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str, - guint64 media_time) -{ - QtDemuxSample *result; - guint32 index; - - result = gst_util_array_binary_search (str->samples, str->n_samples, - sizeof (QtDemuxSample), (GCompareDataFunc) find_func, - GST_SEARCH_MODE_BEFORE, &media_time, NULL); - - if (G_LIKELY (result)) - index = result - str->samples; - else - index = 0; - - return index; -} - -/* find the index of the keyframe needed to decode the sample at @index - * of stream @str. - * - * Returns the index of the keyframe. - */ -static guint32 -gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str, - guint32 index) -{ - guint32 new_index = index; - - if (index >= str->n_samples) { - new_index = str->n_samples; - goto beach; - } - - /* all keyframes, return index */ - if (str->all_keyframe) { - new_index = index; - goto beach; - } - - /* else go back until we have a keyframe */ - while (TRUE) { - if (str->samples[new_index].keyframe) - break; - - if (new_index == 0) - break; - - new_index--; - } - -beach: - GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u " - "gave %u", index, new_index); - - return new_index; -} - -/* find the segment for @time_position for @stream - * - * Returns -1 if the segment cannot be found. - */ -static guint32 -gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream, - guint64 time_position) -{ - gint i; - guint32 seg_idx; - - GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT, - GST_TIME_ARGS (time_position)); - - /* find segment corresponding to time_position if we are looking - * for a segment. */ - seg_idx = -1; - for (i = 0; i < stream->n_segments; i++) { - QtDemuxSegment *segment = &stream->segments[i]; - - GST_LOG_OBJECT (qtdemux, - "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT, - GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time)); - - /* For the last segment we include stop_time in the last segment */ - if (i < stream->n_segments - 1) { - if (segment->time <= time_position && time_position < segment->stop_time) { - GST_LOG_OBJECT (qtdemux, "segment %d matches", i); - seg_idx = i; - break; - } - } else { - if (segment->time <= time_position && time_position <= segment->stop_time) { - GST_LOG_OBJECT (qtdemux, "segment %d matches", i); - seg_idx = i; - break; - } - } - } - return seg_idx; -} - -/* move the stream @str to the sample position @index. - * - * Updates @str->sample_index and marks discontinuity if needed. - */ -static void -gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str, - guint32 index) -{ - /* no change needed */ - if (index == str->sample_index) - return; - - GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index, - str->n_samples); - - /* position changed, we have a discont */ - str->sample_index = index; - /* Each time we move in the stream we store the position where we are - * starting from */ - str->from_sample = index; - str->discont = TRUE; -} - -static void -gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time, - gint64 * key_time, gint64 * key_offset) -{ - guint64 min_offset; - gint64 min_byte_offset = -1; - gint n; - - min_offset = desired_time; - - /* for each stream, find the index of the sample in the segment - * and move back to the previous keyframe. */ - for (n = 0; n < qtdemux->n_streams; n++) { - QtDemuxStream *str; - guint32 index, kindex; - guint32 seg_idx; - guint64 media_start; - guint64 media_time; - guint64 seg_time; - QtDemuxSegment *seg; - - str = qtdemux->streams[n]; - - seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time); - GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx); - - /* segment not found, continue with normal flow */ - if (seg_idx == -1) - continue; - - /* get segment and time in the segment */ - seg = &str->segments[seg_idx]; - seg_time = desired_time - seg->time; - - /* get the media time in the segment */ - media_start = seg->media_start + seg_time; - - /* get the index of the sample with media time */ - index = gst_qtdemux_find_index (qtdemux, str, media_start); - GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u", - GST_TIME_ARGS (media_start), index); - - /* find previous keyframe */ - kindex = gst_qtdemux_find_keyframe (qtdemux, str, index); - - /* if the keyframe is at a different position, we need to update the - * requested seek time */ - if (index != kindex) { - index = kindex; - - /* get timestamp of keyframe */ - media_time = str->samples[kindex].timestamp; - GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT, - kindex, GST_TIME_ARGS (media_time)); - - /* keyframes in the segment get a chance to change the - * desired_offset. keyframes out of the segment are - * ignored. */ - if (media_time >= seg->media_start) { - guint64 seg_time; - - /* this keyframe is inside the segment, convert back to - * segment time */ - seg_time = (media_time - seg->media_start) + seg->time; - if (seg_time < min_offset) - min_offset = seg_time; - } - } - - if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset) - min_byte_offset = str->samples[index].offset; - } - - if (key_time) - *key_time = min_offset; - if (key_offset) - *key_offset = min_byte_offset; -} - -static gboolean -gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format, - GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop) -{ - gboolean res; - GstFormat fmt; - - g_return_val_if_fail (format != NULL, FALSE); - g_return_val_if_fail (cur != NULL, FALSE); - g_return_val_if_fail (stop != NULL, FALSE); - - if (*format == GST_FORMAT_TIME) - return TRUE; - - fmt = GST_FORMAT_TIME; - res = TRUE; - if (cur_type != GST_SEEK_TYPE_NONE) - res = gst_pad_query_convert (pad, *format, *cur, &fmt, cur); - if (res && stop_type != GST_SEEK_TYPE_NONE) - res = gst_pad_query_convert (pad, *format, *stop, &fmt, stop); - - if (res) - *format = GST_FORMAT_TIME; - - return res; -} - -/* perform seek in push based mode: - find BYTE position to move to based on time and delegate to upstream -*/ -static gboolean -gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event) -{ - gdouble rate; - GstFormat format; - GstSeekFlags flags; - GstSeekType cur_type, stop_type; - gint64 cur, stop; - gboolean res; - gint64 byte_cur; - - GST_DEBUG_OBJECT (qtdemux, "doing push-based seek"); - - gst_event_parse_seek (event, &rate, &format, &flags, - &cur_type, &cur, &stop_type, &stop); - - if (stop_type != GST_SEEK_TYPE_NONE) - goto unsupported_seek; - stop = -1; - - /* only forward streaming and seeking is possible */ - if (rate <= 0) - goto unsupported_seek; - - /* convert to TIME if needed and possible */ - if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur, - stop_type, &stop)) - goto no_format; - - /* find reasonable corresponding BYTE position, - * also try to mind about keyframes, since we can not go back a bit for them - * later on */ - gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur); - - if (byte_cur == -1) - goto abort_seek; - - GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, " - "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur, - stop); - /* BYTE seek event */ - event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur, - stop_type, stop); - res = gst_pad_push_event (qtdemux->sinkpad, event); - - return res; - - /* ERRORS */ -abort_seek: - { - GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, " - "seek aborted."); - return FALSE; - } -unsupported_seek: - { - GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted."); - return FALSE; - } -no_format: - { - GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted."); - return FALSE; - } -} - -/* perform the seek. - * - * We set all segment_indexes in the streams to unknown and - * adjust the time_position to the desired position. this is enough - * to trigger a segment switch in the streaming thread to start - * streaming from the desired position. - * - * Keyframe seeking is a little more complicated when dealing with - * segments. Ideally we want to move to the previous keyframe in - * the segment but there might not be a keyframe in the segment. In - * fact, none of the segments could contain a keyframe. We take a - * practical approach: seek to the previous keyframe in the segment, - * if there is none, seek to the beginning of the segment. - * - * Called with STREAM_LOCK - */ -static gboolean -gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment) -{ - gint64 desired_offset; - gint n; - - desired_offset = segment->last_stop; - - GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT, - GST_TIME_ARGS (desired_offset)); - - if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) { - gint64 min_offset; - - gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL); - GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %" - GST_TIME_FORMAT, GST_TIME_ARGS (min_offset)); - desired_offset = min_offset; - } - - /* and set all streams to the final position */ - for (n = 0; n < qtdemux->n_streams; n++) { - QtDemuxStream *stream = qtdemux->streams[n]; - - stream->time_position = desired_offset; - stream->sample_index = -1; - stream->segment_index = -1; - stream->last_ret = GST_FLOW_OK; - stream->sent_eos = FALSE; - } - segment->last_stop = desired_offset; - segment->time = desired_offset; - - /* we stop at the end */ - if (segment->stop == -1) - segment->stop = segment->duration; - - return TRUE; -} - -/* do a seek in pull based mode */ -static gboolean -gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event) -{ - gdouble rate; - GstFormat format; - GstSeekFlags flags; - GstSeekType cur_type, stop_type; - gint64 cur, stop; - gboolean flush; - gboolean update; - GstSegment seeksegment; - int i; - - if (event) { - GST_DEBUG_OBJECT (qtdemux, "doing seek with event"); - - gst_event_parse_seek (event, &rate, &format, &flags, - &cur_type, &cur, &stop_type, &stop); - - /* we have to have a format as the segment format. Try to convert - * if not. */ - if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur, - stop_type, &stop)) - goto no_format; - - GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format)); - } else { - GST_DEBUG_OBJECT (qtdemux, "doing seek without event"); - flags = 0; - } - - flush = flags & GST_SEEK_FLAG_FLUSH; - - /* stop streaming, either by flushing or by pausing the task */ - if (flush) { - /* unlock upstream pull_range */ - gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ()); - /* make sure out loop function exits */ - gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ()); - } else { - /* non flushing seek, pause the task */ - gst_pad_pause_task (qtdemux->sinkpad); - } - - /* wait for streaming to finish */ - GST_PAD_STREAM_LOCK (qtdemux->sinkpad); - - /* copy segment, we need this because we still need the old - * segment when we close the current segment. */ - memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment)); - - if (event) { - /* configure the segment with the seek variables */ - GST_DEBUG_OBJECT (qtdemux, "configuring seek"); - gst_segment_set_seek (&seeksegment, rate, format, flags, - cur_type, cur, stop_type, stop, &update); - } - - /* now do the seek, this actually never returns FALSE */ - gst_qtdemux_perform_seek (qtdemux, &seeksegment); - - /* prepare for streaming again */ - if (flush) { - gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop ()); - gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop ()); - } else if (qtdemux->segment_running) { - /* we are running the current segment and doing a non-flushing seek, - * close the segment first based on the last_stop. */ - GST_DEBUG_OBJECT (qtdemux, "closing running segment %" G_GINT64_FORMAT - " to %" G_GINT64_FORMAT, qtdemux->segment.start, - qtdemux->segment.last_stop); - - if (qtdemux->segment.rate >= 0) { - /* FIXME, rate is the product of the global rate and the (quicktime) - * segment rate. */ - qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE, - qtdemux->segment.rate, qtdemux->segment.format, - qtdemux->segment.start, qtdemux->segment.last_stop, - qtdemux->segment.time); - } else { /* For Reverse Playback */ - guint64 stop; - - if ((stop = qtdemux->segment.stop) == -1) - stop = qtdemux->segment.duration; - /* for reverse playback, we played from stop to last_stop. */ - qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE, - qtdemux->segment.rate, qtdemux->segment.format, - qtdemux->segment.last_stop, stop, qtdemux->segment.last_stop); - } - } - - /* commit the new segment */ - memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment)); - - if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) { - gst_element_post_message (GST_ELEMENT_CAST (qtdemux), - gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux), - qtdemux->segment.format, qtdemux->segment.last_stop)); - } - - /* restart streaming, NEWSEGMENT will be sent from the streaming - * thread. */ - qtdemux->segment_running = TRUE; - for (i = 0; i < qtdemux->n_streams; i++) - qtdemux->streams[i]->last_ret = GST_FLOW_OK; - - gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop, - qtdemux->sinkpad); - - GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad); - - return TRUE; - - /* ERRORS */ -no_format: - { - GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted."); - return FALSE; - } -} - -static gboolean -gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event) -{ - gboolean res = TRUE; - GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - if (qtdemux->pullbased) { - res = gst_qtdemux_do_seek (qtdemux, pad, event); - } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams) { - res = gst_qtdemux_do_push_seek (qtdemux, pad, event); - } else { - GST_DEBUG_OBJECT (qtdemux, - "ignoring seek in push mode in current state"); - res = FALSE; - } - gst_event_unref (event); - break; - case GST_EVENT_QOS: - case GST_EVENT_NAVIGATION: - res = FALSE; - gst_event_unref (event); - break; - default: - res = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (qtdemux); - - return res; -} - -/* stream/index return sample that is min/max w.r.t. byte position, - * time is min/max w.r.t. time of samples, - * the latter need not be time of the former sample */ -static void -gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw, - gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time) -{ - gint i, n, index; - gint64 time, min_time; - QtDemuxStream *stream; - - min_time = -1; - stream = NULL; - index = -1; - - for (n = 0; n < qtdemux->n_streams; ++n) { - QtDemuxStream *str; - gint inc; - gboolean set_sample; - - - str = qtdemux->streams[n]; - set_sample = !set; - - if (fw) { - i = 0; - inc = 1; - } else { - i = str->n_samples - 1; - inc = -1; - } - for (; (i >= 0) && (i < str->n_samples); i += inc) { - if (str->samples[i].size && - ((fw && (str->samples[i].offset >= byte_pos)) || - (!fw && - (str->samples[i].offset + str->samples[i].size <= - byte_pos)))) { - /* move stream to first available sample */ - if (set) { - gst_qtdemux_move_stream (qtdemux, str, i); - set_sample = TRUE; - } - /* determine min/max time */ - time = str->samples[i].timestamp + str->samples[i].pts_offset; - if (min_time == -1 || (fw && min_time > time) || - (!fw && min_time < time)) { - min_time = time; - } - /* determine stream with leading sample, to get its position */ - /* only needed in fw case */ - if (fw && (!stream || - str->samples[i].offset < stream->samples[index].offset)) { - stream = str; - index = i; - } - break; - } - } - /* no sample for this stream, mark eos */ - if (!set_sample) - gst_qtdemux_move_stream (qtdemux, str, str->n_samples); - } - - if (_time) - *_time = min_time; - if (_stream) - *_stream = stream; - if (_index) - *_index = index; -} - -static gboolean -gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event) -{ - GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad)); - gboolean res; - - GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - { - GstFormat format; - gdouble rate, arate; - gint64 start, stop, time, offset = 0; - QtDemuxStream *stream; - gint idx; - gboolean update; - GstSegment segment; - - /* some debug output */ - gst_segment_init (&segment, GST_FORMAT_UNDEFINED); - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, - &start, &stop, &time); - gst_segment_set_newsegment_full (&segment, update, rate, arate, format, - start, stop, time); - GST_DEBUG_OBJECT (demux, - "received format %d newsegment %" GST_SEGMENT_FORMAT, format, - &segment); - - /* chain will send initial newsegment after pads have been added */ - if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) { - GST_DEBUG_OBJECT (demux, "still starting, eating event"); - goto exit; - } - - /* we only expect a BYTE segment, e.g. following a seek */ - if (format == GST_FORMAT_BYTES) { - if (start > 0) { - offset = start; - gst_qtdemux_find_sample (demux, start, TRUE, FALSE, NULL, NULL, - &start); - start = MAX (start, 0); - } - if (stop > 0) { - gst_qtdemux_find_sample (demux, stop, FALSE, FALSE, NULL, NULL, - &stop); - stop = MAX (stop, 0); - } - } else { - GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring"); - goto exit; - } - - /* accept upstream's notion of segment and distribute along */ - gst_segment_set_newsegment_full (&demux->segment, update, rate, arate, - GST_FORMAT_TIME, start, stop, start); - GST_DEBUG_OBJECT (demux, "Pushing newseg update %d, rate %g, " - "applied rate %g, format %d, start %" G_GINT64_FORMAT ", " - "stop %" G_GINT64_FORMAT, update, rate, arate, GST_FORMAT_TIME, - start, stop); - gst_qtdemux_push_event (demux, - gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME, - start, stop, start)); - - /* clear leftover in current segment, if any */ - gst_adapter_clear (demux->adapter); - /* set up streaming thread */ - gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL); - demux->offset = offset; - if (stream) { - demux->todrop = stream->samples[idx].offset - offset; - demux->neededbytes = demux->todrop + stream->samples[idx].size; - } else { - /* set up for EOS */ - demux->neededbytes = -1; - demux->todrop = 0; - } - exit: - gst_event_unref (event); - res = TRUE; - goto drop; - break; - } - case GST_EVENT_FLUSH_STOP: - { - gint i; - - /* clean up, force EOS if no more info follows */ - gst_adapter_clear (demux->adapter); - demux->offset = 0; - demux->neededbytes = -1; - /* reset flow return, e.g. following seek */ - for (i = 0; i < demux->n_streams; i++) { - demux->streams[i]->last_ret = GST_FLOW_OK; - demux->streams[i]->sent_eos = FALSE; - } - break; - } - case GST_EVENT_EOS: - /* If we are in push mode, and get an EOS before we've seen any streams, - * then error out - we have nowhere to send the EOS */ - if (!demux->pullbased && demux->n_streams == 0) { - GST_ELEMENT_ERROR (demux, STREAM, DECODE, - (_("This file contains no playable streams.")), - ("no known streams found")); - } - break; - default: - break; - } - - res = gst_pad_event_default (demux->sinkpad, event); - -drop: - return res; -} - -static GstStateChangeReturn -gst_qtdemux_change_state (GstElement * element, GstStateChange transition) -{ - GstQTDemux *qtdemux = GST_QTDEMUX (element); - GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - break; - default: - break; - } - - result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY:{ - gint n; - - qtdemux->state = QTDEMUX_STATE_INITIAL; - qtdemux->last_ts = GST_CLOCK_TIME_NONE; - qtdemux->neededbytes = 16; - qtdemux->todrop = 0; - qtdemux->pullbased = FALSE; - qtdemux->offset = 0; - qtdemux->mdatoffset = GST_CLOCK_TIME_NONE; - if (qtdemux->mdatbuffer) - gst_buffer_unref (qtdemux->mdatbuffer); - qtdemux->mdatbuffer = NULL; - gst_adapter_clear (qtdemux->adapter); - for (n = 0; n < qtdemux->n_streams; n++) { - QtDemuxStream *stream = qtdemux->streams[n]; - - while (stream->buffers) { - gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data)); - stream->buffers = - g_slist_delete_link (stream->buffers, stream->buffers); - } - if (stream->pad) - gst_element_remove_pad (element, stream->pad); - if (stream->samples) - g_free (stream->samples); - if (stream->caps) - gst_caps_unref (stream->caps); - if (stream->segments) - g_free (stream->segments); - g_free (stream); - } - qtdemux->major_brand = 0; - qtdemux->n_streams = 0; - qtdemux->n_video_streams = 0; - qtdemux->n_audio_streams = 0; - qtdemux->n_subp_streams = 0; - gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME); - break; - } - default: - break; - } - - return result; -} - -static void -extract_initial_length_and_fourcc (const guint8 * data, guint64 * plength, - guint32 * pfourcc) -{ - guint64 length; - guint32 fourcc; - - length = QT_UINT32 (data); - GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length); - fourcc = QT_FOURCC (data + 4); - GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc)); - - if (length == 0) { - length = G_MAXUINT32; - } else if (length == 1) { - /* this means we have an extended size, which is the 64 bit value of - * the next 8 bytes */ - length = QT_UINT64 (data + 8); - GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length); - } - - if (plength) - *plength = length; - if (pfourcc) - *pfourcc = fourcc; -} - -static GstFlowReturn -gst_qtdemux_loop_state_header (GstQTDemux * qtdemux) -{ - guint64 length = 0; - guint32 fourcc; - GstBuffer *buf = NULL; - GstFlowReturn ret = GST_FLOW_OK; - guint64 cur_offset = qtdemux->offset; - - ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf); - if (G_UNLIKELY (ret != GST_FLOW_OK)) - goto beach; - if (G_LIKELY (GST_BUFFER_SIZE (buf) == 16)) - extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf), &length, &fourcc); - gst_buffer_unref (buf); - - if (G_UNLIKELY (length == 0)) { - GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE, - (_("This file is invalid and cannot be played.")), - ("Header atom '%" GST_FOURCC_FORMAT "' has empty length", - GST_FOURCC_ARGS (fourcc))); - ret = GST_FLOW_ERROR; - goto beach; - } - - switch (fourcc) { - case FOURCC_mdat: - case FOURCC_free: - case FOURCC_wide: - case FOURCC_PICT: - case FOURCC_pnot: - { - GST_LOG_OBJECT (qtdemux, - "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT, - GST_FOURCC_ARGS (fourcc), cur_offset); - qtdemux->offset += length; - break; - } - case FOURCC_moov: - { - GstBuffer *moov; - - ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov); - if (ret != GST_FLOW_OK) - goto beach; - if (length != GST_BUFFER_SIZE (moov)) { - /* Some files have a 'moov' atom at the end of the file which contains - * a terminal 'free' atom where the body of the atom is missing. - * Check for, and permit, this special case. - */ - if (GST_BUFFER_SIZE (moov) >= 8) { - guint8 *final_data = GST_BUFFER_DATA (moov) + - (GST_BUFFER_SIZE (moov) - 8); - guint32 final_length = QT_UINT32 (final_data); - guint32 final_fourcc = QT_FOURCC (final_data + 4); - if (final_fourcc == FOURCC_free && - GST_BUFFER_SIZE (moov) + final_length - 8 == length) { - /* Ok, we've found that special case. Allocate a new buffer with - * that free atom actually present. */ - GstBuffer *newmoov = gst_buffer_new_and_alloc (length); - gst_buffer_copy_metadata (newmoov, moov, - GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS | - GST_BUFFER_COPY_CAPS); - memcpy (GST_BUFFER_DATA (newmoov), GST_BUFFER_DATA (moov), - GST_BUFFER_SIZE (moov)); - memset (GST_BUFFER_DATA (newmoov) + GST_BUFFER_SIZE (moov), 0, - final_length - 8); - gst_buffer_unref (moov); - moov = newmoov; - } - } - } - - if (length != GST_BUFFER_SIZE (moov)) { - GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE, - (_("This file is incomplete and cannot be played.")), - ("We got less than expected (received %u, wanted %u, offset %" - G_GUINT64_FORMAT ")", - GST_BUFFER_SIZE (moov), (guint) length, cur_offset)); - ret = GST_FLOW_ERROR; - goto beach; - } - qtdemux->offset += length; - - qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length); - qtdemux_node_dump (qtdemux, qtdemux->moov_node); - - qtdemux_parse_tree (qtdemux); - g_node_destroy (qtdemux->moov_node); - gst_buffer_unref (moov); - qtdemux->moov_node = NULL; - qtdemux->state = QTDEMUX_STATE_MOVIE; - GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)", - qtdemux->state); - break; - } - case FOURCC_ftyp: - { - GstBuffer *ftyp; - - /* extract major brand; might come in handy for ISO vs QT issues */ - ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp); - if (ret != GST_FLOW_OK) - goto beach; - qtdemux->offset += length; - /* only consider at least a sufficiently complete ftyp atom */ - if (length >= 20) { - qtdemux->major_brand = QT_FOURCC (GST_BUFFER_DATA (ftyp) + 8); - GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (qtdemux->major_brand)); - } - gst_buffer_unref (ftyp); - break; - } - default: - { - GstBuffer *unknown; - - GST_LOG_OBJECT (qtdemux, - "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT - " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length, - cur_offset); - ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown); - if (ret != GST_FLOW_OK) - goto beach; - GST_MEMDUMP ("Unknown tag", GST_BUFFER_DATA (unknown), - GST_BUFFER_SIZE (unknown)); - gst_buffer_unref (unknown); - qtdemux->offset += length; - break; - } - } - -beach: - return ret; -} - -/* Seeks to the previous keyframe of the indexed stream and - * aligns other streams with respect to the keyframe timestamp - * of indexed stream. Only called in case of Reverse Playback - */ -static GstFlowReturn -gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux) -{ - guint8 n = 0; - guint32 seg_idx = 0, k_index = 0; - guint64 k_pos = 0, last_stop = 0; - QtDemuxSegment *seg = NULL; - QtDemuxStream *ref_str = NULL; - - /* Now we choose an arbitrary stream, get the previous keyframe timestamp - * and finally align all the other streams on that timestamp with their - * respective keyframes */ - for (n = 0; n < qtdemux->n_streams; n++) { - QtDemuxStream *str = qtdemux->streams[n]; - - seg_idx = gst_qtdemux_find_segment (qtdemux, str, - qtdemux->segment.last_stop); - - /* segment not found, continue with normal flow */ - if (seg_idx == -1) - continue; - - /* No candidate yet, take that one */ - if (!ref_str) { - ref_str = str; - continue; - } - - /* So that stream has a segment, we prefer video streams */ - if (str->subtype == FOURCC_vide) { - ref_str = str; - break; - } - } - - if (G_UNLIKELY (!ref_str)) { - GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream"); - goto eos; - } - - if (G_UNLIKELY (!ref_str->from_sample)) { - GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file"); - goto eos; - } - - /* So that stream has been playing from from_sample to to_sample. We will - * get the timestamp of the previous sample and search for a keyframe before - * that. For audio streams we do an arbitrary jump in the past (10 samples) */ - if (ref_str->subtype == FOURCC_vide) { - k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str, - ref_str->from_sample - 1); - } else { - k_index = ref_str->from_sample - 10; - } - - /* get current segment for that stream */ - seg = &ref_str->segments[ref_str->segment_index]; - /* Crawl back through segments to find the one containing this I frame */ - while (ref_str->samples[k_index].timestamp < seg->media_start) { - GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u", - ref_str->segment_index); - if (G_UNLIKELY (!ref_str->segment_index)) { - /* Reached first segment, let's consider it's EOS */ - goto eos; - } - ref_str->segment_index--; - seg = &ref_str->segments[ref_str->segment_index]; - } - /* Calculate time position of the keyframe and where we should stop */ - k_pos = (ref_str->samples[k_index].timestamp - seg->media_start) + seg->time; - last_stop = ref_str->samples[ref_str->from_sample].timestamp; - last_stop = (last_stop - seg->media_start) + seg->time; - - GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, " - "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample, - k_index, GST_TIME_ARGS (k_pos)); - - /* Set last_stop with the keyframe timestamp we pushed of that stream */ - gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, last_stop); - GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT, - GST_TIME_ARGS (last_stop)); - - if (G_UNLIKELY (last_stop < qtdemux->segment.start)) { - GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment"); - goto eos; - } - - /* Align them all on this */ - for (n = 0; n < qtdemux->n_streams; n++) { - guint32 index = 0; - guint64 media_start = 0, seg_time = 0; - QtDemuxStream *str = qtdemux->streams[n]; - - seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos); - GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx); - - /* segment not found, continue with normal flow */ - if (seg_idx == -1) - continue; - - /* get segment and time in the segment */ - seg = &str->segments[seg_idx]; - seg_time = k_pos - seg->time; - - /* get the media time in the segment */ - media_start = seg->media_start + seg_time; - - /* get the index of the sample with media time */ - index = gst_qtdemux_find_index (qtdemux, str, media_start); - GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u", - GST_TIME_ARGS (media_start), index); - - /* find previous keyframe */ - k_index = gst_qtdemux_find_keyframe (qtdemux, str, index); - - /* Remember until where we want to go */ - str->to_sample = str->from_sample - 1; - /* Define our time position */ - str->time_position = - (str->samples[k_index].timestamp - seg->media_start) + seg->time; - /* Now seek back in time */ - gst_qtdemux_move_stream (qtdemux, str, k_index); - GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %" - GST_TIME_FORMAT " playing from sample %u to %u", k_index, - GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample); - } - - return GST_FLOW_OK; - -eos: - return GST_FLOW_UNEXPECTED; -} - -/* activate the given segment number @seg_idx of @stream at time @offset. - * @offset is an absolute global position over all the segments. - * - * This will push out a NEWSEGMENT event with the right values and - * position the stream index to the first decodable sample before - * @offset. - */ -static gboolean -gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream, - guint32 seg_idx, guint64 offset) -{ - GstEvent *event; - QtDemuxSegment *segment; - guint32 index, kf_index; - guint64 seg_time; - guint64 start, stop, time; - gdouble rate; - - GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT, - seg_idx, offset); - - /* update the current segment */ - stream->segment_index = seg_idx; - - /* get the segment */ - segment = &stream->segments[seg_idx]; - - if (G_UNLIKELY (offset < segment->time)) { - GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT, - segment->time); - return FALSE; - } - - /* get time in this segment */ - seg_time = offset - segment->time; - - GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT, - GST_TIME_ARGS (seg_time)); - - if (G_UNLIKELY (seg_time > segment->duration)) { - GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT, - GST_TIME_ARGS (segment->duration)); - return FALSE; - } - - /* qtdemux->segment.stop is in outside-time-realm, whereas - * segment->media_stop is in track-time-realm. - * - * In order to compare the two, we need to bring segment.stop - * into the track-time-realm */ - - if (qtdemux->segment.stop == -1) - stop = segment->media_stop; - else - stop = - MIN (segment->media_stop, - qtdemux->segment.stop - segment->time + segment->media_start); - - if (qtdemux->segment.rate >= 0) { - start = MIN (segment->media_start + seg_time, stop); - time = offset; - } else { - start = segment->media_start; - stop = MIN (segment->media_start + seg_time, stop); - time = segment->time; - } - - GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT - " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx, - GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time)); - - /* combine global rate with that of the segment */ - rate = segment->rate * qtdemux->segment.rate; - - /* update the segment values used for clipping */ - gst_segment_init (&stream->segment, GST_FORMAT_TIME); - gst_segment_set_newsegment (&stream->segment, FALSE, rate, GST_FORMAT_TIME, - start, stop, time); - - /* now prepare and send the segment */ - if (stream->pad) { - event = gst_event_new_new_segment (FALSE, rate, GST_FORMAT_TIME, - start, stop, time); - gst_pad_push_event (stream->pad, event); - /* assume we can send more data now */ - stream->last_ret = GST_FLOW_OK; - } - - /* and move to the keyframe before the indicated media time of the - * segment */ - if (qtdemux->segment.rate >= 0) { - index = gst_qtdemux_find_index (qtdemux, stream, start); - stream->to_sample = stream->n_samples; - GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT - ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index, - GST_TIME_ARGS (stream->samples[index].timestamp)); - } else { - index = gst_qtdemux_find_index (qtdemux, stream, stop); - stream->to_sample = index; - GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT - ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index, - GST_TIME_ARGS (stream->samples[index].timestamp)); - } - - /* we're at the right spot */ - if (index == stream->sample_index) { - GST_DEBUG_OBJECT (qtdemux, "we are at the right index"); - return TRUE; - } - - /* find keyframe of the target index */ - kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index); - - /* if we move forwards, we don't have to go back to the previous - * keyframe since we already sent that. We can also just jump to - * the keyframe right before the target index if there is one. */ - if (index > stream->sample_index) { - /* moving forwards check if we move past a keyframe */ - if (kf_index > stream->sample_index) { - GST_DEBUG_OBJECT (qtdemux, "moving forwards to keyframe at %u (pts %" - GST_TIME_FORMAT, kf_index, - GST_TIME_ARGS (stream->samples[kf_index].timestamp)); - gst_qtdemux_move_stream (qtdemux, stream, kf_index); - } else { - GST_DEBUG_OBJECT (qtdemux, "moving forwards, keyframe at %u (pts %" - GST_TIME_FORMAT " already sent", kf_index, - GST_TIME_ARGS (stream->samples[kf_index].timestamp)); - } - } else { - GST_DEBUG_OBJECT (qtdemux, "moving backwards to keyframe at %u (pts %" - GST_TIME_FORMAT, kf_index, - GST_TIME_ARGS (stream->samples[kf_index].timestamp)); - gst_qtdemux_move_stream (qtdemux, stream, kf_index); - } - - return TRUE; -} - -/* prepare to get the current sample of @stream, getting essential values. - * - * This function will also prepare and send the segment when needed. - * - * Return FALSE if the stream is EOS. - */ -static gboolean -gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux, - QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp, - guint64 * duration, gboolean * keyframe) -{ - QtDemuxSample *sample; - guint64 time_position; - guint32 seg_idx; - - g_return_val_if_fail (stream != NULL, FALSE); - - time_position = stream->time_position; - if (G_UNLIKELY (time_position == -1)) - goto eos; - - seg_idx = stream->segment_index; - if (G_UNLIKELY (seg_idx == -1)) { - /* find segment corresponding to time_position if we are looking - * for a segment. */ - seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position); - - /* nothing found, we're really eos */ - if (seg_idx == -1) - goto eos; - } - - /* different segment, activate it, sample_index will be set. */ - if (G_UNLIKELY (stream->segment_index != seg_idx)) - gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position); - - GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u", - stream->sample_index, stream->n_samples); - - /* send out pending buffers */ - while (stream->buffers) { - GstBuffer *buffer = (GstBuffer *) stream->buffers->data; - - if (G_UNLIKELY (stream->discont)) { - GST_LOG_OBJECT (qtdemux, "marking discont buffer"); - GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT); - stream->discont = FALSE; - } - gst_buffer_set_caps (buffer, stream->caps); - - gst_pad_push (stream->pad, buffer); - - stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers); - } - - if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) - goto eos; - - /* now get the info for the sample we're at */ - sample = &stream->samples[stream->sample_index]; - - *timestamp = sample->timestamp + sample->pts_offset; - *offset = sample->offset; - *size = sample->size; - *duration = sample->duration; - *keyframe = stream->all_keyframe || sample->keyframe; - - /* add padding */ - if (stream->padding) { - *offset += stream->padding; - *size -= stream->padding; - } - - return TRUE; - - /* special cases */ -eos: - { - stream->time_position = -1; - return FALSE; - } -} - -/* move to the next sample in @stream. - * - * Moves to the next segment when needed. - */ -static void -gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream) -{ - QtDemuxSample *sample; - QtDemuxSegment *segment; - - if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) { - /* Mark the stream as EOS */ - GST_DEBUG_OBJECT (qtdemux, "reached max allowed sample %u, mark EOS", - stream->to_sample); - stream->time_position = -1; - return; - } - - /* move to next sample */ - stream->sample_index++; - - /* get current segment */ - segment = &stream->segments[stream->segment_index]; - - /* reached the last sample, we need the next segment */ - if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) - goto next_segment; - - /* get next sample */ - sample = &stream->samples[stream->sample_index]; - - /* see if we are past the segment */ - if (G_UNLIKELY (sample->timestamp >= segment->media_stop)) - goto next_segment; - - if (sample->timestamp >= segment->media_start) { - /* inside the segment, update time_position, looks very familiar to - * GStreamer segments, doesn't it? */ - stream->time_position = - (sample->timestamp - segment->media_start) + segment->time; - } else { - /* not yet in segment, time does not yet increment. This means - * that we are still prerolling keyframes to the decoder so it can - * decode the first sample of the segment. */ - stream->time_position = segment->time; - } - return; - - /* move to the next segment */ -next_segment: - { - GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index); - - if (stream->segment_index == stream->n_segments - 1) { - /* are we at the end of the last segment, we're EOS */ - stream->time_position = -1; - } else { - /* else we're only at the end of the current segment */ - stream->time_position = segment->stop_time; - } - /* make sure we select a new segment */ - stream->segment_index = -1; - } -} - -static void -gst_qtdemux_sync_streams (GstQTDemux * demux) -{ - gint i; - - if (demux->n_streams <= 1) - return; - - for (i = 0; i < demux->n_streams; i++) { - QtDemuxStream *stream; - GstClockTime end_time; - - stream = demux->streams[i]; - - if (!stream->pad) - continue; - - /* TODO advance time on subtitle streams here, if any some day */ - - /* some clips/trailers may have unbalanced streams at the end, - * so send EOS on shorter stream to prevent stalling others */ - - /* do not mess with EOS if SEGMENT seeking */ - if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) - continue; - - if (demux->pullbased) { - /* loop mode is sample time based */ - if (stream->time_position != -1) - continue; - } else { - /* push mode is byte position based */ - if (stream->samples[stream->n_samples - 1].offset >= demux->offset) - continue; - } - - if (stream->sent_eos) - continue; - - /* only act if some gap */ - end_time = stream->segments[stream->n_segments - 1].stop_time; - GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT - ", stream end: %" GST_TIME_FORMAT, GST_TIME_ARGS (end_time), - GST_TIME_ARGS (demux->segment.last_stop)); - if (end_time + 2 * GST_SECOND < demux->segment.last_stop) { - GST_DEBUG_OBJECT (demux, "sending EOS for stream %s", - GST_PAD_NAME (stream->pad)); - stream->sent_eos = TRUE; - gst_pad_push_event (stream->pad, gst_event_new_eos ()); - } - } -} - -/* UNEXPECTED and NOT_LINKED need to be combined. This means that we return: - * - * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED. - * GST_FLOW_UNEXPECTED: when all pads UNEXPECTED or NOT_LINKED. - */ -static GstFlowReturn -gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream, - GstFlowReturn ret) -{ - gint i; - gboolean unexpected = FALSE, not_linked = TRUE; - - GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret)); - - /* store the value */ - stream->last_ret = ret; - - for (i = 0; i < demux->n_streams; i++) { - QtDemuxStream *ostream = demux->streams[i]; - - ret = ostream->last_ret; - - /* no unexpected or unlinked, return */ - if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED)) - goto done; - - /* we check to see if we have at least 1 unexpected or all unlinked */ - unexpected |= (ret == GST_FLOW_UNEXPECTED); - not_linked &= (ret == GST_FLOW_NOT_LINKED); - } - - /* when we get here, we all have unlinked or unexpected */ - if (not_linked) - ret = GST_FLOW_NOT_LINKED; - else if (unexpected) - ret = GST_FLOW_UNEXPECTED; -done: - GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret)); - return ret; -} - -/* the input buffer metadata must be writable. Returns NULL when the buffer is - * completely cliped */ -static GstBuffer * -gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream, - GstBuffer * buf) -{ - gint64 start, stop, cstart, cstop, diff; - GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE; - guint8 *data; - guint size; - gint num_rate, denom_rate; - gint frame_size; - gboolean clip_data; - - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); - - /* depending on the type, setup the clip parameters */ - if (stream->subtype == FOURCC_soun) { - frame_size = stream->bytes_per_frame; - num_rate = GST_SECOND; - denom_rate = (gint) stream->rate; - clip_data = TRUE; - } else if (stream->subtype == FOURCC_vide) { - frame_size = size; - num_rate = stream->fps_n; - denom_rate = stream->fps_d; - clip_data = FALSE; - } else - goto wrong_type; - - /* we can only clip if we have a valid timestamp */ - timestamp = GST_BUFFER_TIMESTAMP (buf); - if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) - goto no_timestamp; - - if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf))) { - duration = GST_BUFFER_DURATION (buf); - } else { - duration = - gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate); - } - - start = timestamp; - stop = start + duration; - - if (G_UNLIKELY (!gst_segment_clip (&stream->segment, GST_FORMAT_TIME, - start, stop, &cstart, &cstop))) - goto clipped; - - /* see if some clipping happened */ - diff = cstart - start; - if (diff > 0) { - timestamp = cstart; - duration -= diff; - - if (clip_data) { - /* bring clipped time to samples and to bytes */ - diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate); - diff *= frame_size; - - GST_DEBUG_OBJECT (qtdemux, "clipping start to %" GST_TIME_FORMAT " %" - G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff); - - data += diff; - size -= diff; - } - } - diff = stop - cstop; - if (diff > 0) { - duration -= diff; - - if (clip_data) { - /* bring clipped time to samples and then to bytes */ - diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate); - diff *= frame_size; - - GST_DEBUG_OBJECT (qtdemux, "clipping stop to %" GST_TIME_FORMAT " %" - G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstop), diff); - - size -= diff; - } - } - - GST_BUFFER_TIMESTAMP (buf) = timestamp; - GST_BUFFER_DURATION (buf) = duration; - GST_BUFFER_SIZE (buf) = size; - GST_BUFFER_DATA (buf) = data; - - return buf; - - /* dropped buffer */ -wrong_type: - { - GST_DEBUG_OBJECT (qtdemux, "unknown stream type"); - return buf; - } -no_timestamp: - { - GST_DEBUG_OBJECT (qtdemux, "no timestamp on buffer"); - return buf; - } -clipped: - { - GST_DEBUG_OBJECT (qtdemux, "clipped buffer"); - gst_buffer_unref (buf); - return NULL; - } -} - -static GstFlowReturn -gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux) -{ - GstFlowReturn ret = GST_FLOW_OK; - GstBuffer *buf = NULL; - QtDemuxStream *stream; - guint64 min_time; - guint64 offset = 0; - guint64 timestamp = GST_CLOCK_TIME_NONE; - guint64 duration = 0; - gboolean keyframe = FALSE; - guint size = 0; - gint index; - gint i; - - gst_qtdemux_push_pending_newsegment (qtdemux); - - /* Figure out the next stream sample to output, min_time is expressed in - * global time and runs over the edit list segments. */ - min_time = G_MAXUINT64; - index = -1; - for (i = 0; i < qtdemux->n_streams; i++) { - guint64 position; - - stream = qtdemux->streams[i]; - position = stream->time_position; - - /* position of -1 is EOS */ - if (position != -1 && position < min_time) { - min_time = position; - index = i; - } - } - /* all are EOS */ - if (G_UNLIKELY (index == -1)) { - GST_DEBUG_OBJECT (qtdemux, "all streams are EOS"); - goto eos; - } - - /* check for segment end */ - if (G_UNLIKELY (qtdemux->segment.stop != -1 - && qtdemux->segment.stop < min_time)) { - GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment."); - goto eos; - } - - stream = qtdemux->streams[index]; - - /* fetch info for the current sample of this stream */ - if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset, - &size, ×tamp, &duration, &keyframe))) - goto eos_stream; - - GST_LOG_OBJECT (qtdemux, - "pushing from stream %d, offset %" G_GUINT64_FORMAT - ", size %d, timestamp=%" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, - index, offset, size, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration)); - - /* hmm, empty sample, skip and move to next sample */ - if (G_UNLIKELY (size <= 0)) - goto next; - - /* last pushed sample was out of boundary, goto next sample */ - if (G_UNLIKELY (stream->last_ret == GST_FLOW_UNEXPECTED)) - goto next; - - GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size, - offset); - - ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf); - if (G_UNLIKELY (ret != GST_FLOW_OK)) - goto beach; - - if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) { - GstMessage *m; - gchar *url; - - url = g_strndup ((gchar *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); - - /* we have RTSP redirect now */ - m = gst_message_new_element (GST_OBJECT_CAST (qtdemux), - gst_structure_new ("redirect", - "new-location", G_TYPE_STRING, url, NULL)); - g_free (url); - - gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m); - } - - qtdemux->last_ts = min_time; - if (qtdemux->segment.rate >= 0) { - gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, min_time); - gst_qtdemux_sync_streams (qtdemux); - } - if (G_LIKELY (stream->pad)) { - /* we're going to modify the metadata */ - buf = gst_buffer_make_metadata_writable (buf); - - GST_BUFFER_TIMESTAMP (buf) = timestamp; - GST_BUFFER_DURATION (buf) = duration; - GST_BUFFER_OFFSET (buf) = -1; - GST_BUFFER_OFFSET_END (buf) = -1; - - if (stream->need_clip) - buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf); - - if (buf == NULL) - goto next; - - if (stream->discont) { - GST_LOG_OBJECT (qtdemux, "marking discont buffer"); - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - stream->discont = FALSE; - } - - if (!keyframe) - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); - - gst_buffer_set_caps (buf, stream->caps); - - GST_LOG_OBJECT (qtdemux, - "Pushing buffer with time %" GST_TIME_FORMAT ", duration %" - GST_TIME_FORMAT " on pad %s", - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad)); - - ret = gst_pad_push (stream->pad, buf); - } else { - GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring"); - gst_buffer_unref (buf); - ret = GST_FLOW_OK; - } - - /* combine flows */ - ret = gst_qtdemux_combine_flows (qtdemux, stream, ret); - /* ignore unlinked, we will not push on the pad anymore and we will EOS when - * we have no more data for the pad to push */ - if (ret == GST_FLOW_UNEXPECTED) - ret = GST_FLOW_OK; - -next: - gst_qtdemux_advance_sample (qtdemux, stream); - -beach: - return ret; - - /* special cases */ -eos: - { - GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS"); - ret = GST_FLOW_UNEXPECTED; - goto beach; - } -eos_stream: - { - GST_DEBUG_OBJECT (qtdemux, "No samples left for stream"); - /* EOS will be raised if all are EOS */ - ret = GST_FLOW_OK; - goto beach; - } -} - -static void -gst_qtdemux_loop (GstPad * pad) -{ - GstQTDemux *qtdemux; - guint64 cur_offset; - GstFlowReturn ret; - - qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad)); - - cur_offset = qtdemux->offset; - GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d", - cur_offset, qtdemux->state); - - switch (qtdemux->state) { - case QTDEMUX_STATE_INITIAL: - case QTDEMUX_STATE_HEADER: - ret = gst_qtdemux_loop_state_header (qtdemux); - break; - case QTDEMUX_STATE_MOVIE: - ret = gst_qtdemux_loop_state_movie (qtdemux); - if (qtdemux->segment.rate < 0 && ret == GST_FLOW_UNEXPECTED) { - ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux); - } - break; - default: - /* ouch */ - goto invalid_state; - } - - /* if something went wrong, pause */ - if (ret != GST_FLOW_OK) - goto pause; - -done: - gst_object_unref (qtdemux); - return; - - /* ERRORS */ -invalid_state: - { - GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED, - (NULL), ("streaming stopped, invalid state")); - qtdemux->segment_running = FALSE; - gst_pad_pause_task (pad); - gst_qtdemux_push_event (qtdemux, gst_event_new_eos ()); - goto done; - } -pause: - { - const gchar *reason = gst_flow_get_name (ret); - - GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason); - - qtdemux->segment_running = FALSE; - gst_pad_pause_task (pad); - - /* fatal errors need special actions */ - if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) { - /* check EOS */ - if (ret == GST_FLOW_UNEXPECTED) { - if (qtdemux->n_streams == 0) { - /* we have no streams, post an error */ - GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE, - (_("This file contains no playable streams.")), - ("no known streams found")); - } - if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) { - gint64 stop; - - /* FIXME: I am not sure this is the right fix. If the sinks are - * supposed to detect the segment is complete and accumulate - * automatically, it does not seem to work here. Need more work */ - qtdemux->segment_running = TRUE; - - if ((stop = qtdemux->segment.stop) == -1) - stop = qtdemux->segment.duration; - - if (qtdemux->segment.rate >= 0) { - GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment"); - gst_element_post_message (GST_ELEMENT_CAST (qtdemux), - gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux), - GST_FORMAT_TIME, stop)); - } else { - /* For Reverse Playback */ - GST_LOG_OBJECT (qtdemux, - "Sending segment done, at start of segment"); - gst_element_post_message (GST_ELEMENT_CAST (qtdemux), - gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux), - GST_FORMAT_TIME, qtdemux->segment.start)); - } - } else { - GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment"); - gst_qtdemux_push_event (qtdemux, gst_event_new_eos ()); - } - } else { - GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED, - (NULL), ("streaming stopped, reason %s", reason)); - gst_qtdemux_push_event (qtdemux, gst_event_new_eos ()); - } - } - goto done; - } -} - -/* - * next_entry_size - * - * Returns the size of the first entry at the current offset. - * If -1, there are none (which means EOS or empty file). - */ -static guint64 -next_entry_size (GstQTDemux * demux) -{ - QtDemuxStream *stream; - int i; - int smallidx = -1; - guint64 smalloffs = (guint64) - 1; - - GST_LOG_OBJECT (demux, "Finding entry at offset %lld", demux->offset); - - for (i = 0; i < demux->n_streams; i++) { - stream = demux->streams[i]; - - if (stream->sample_index == -1) - stream->sample_index = 0; - - if (stream->sample_index >= stream->n_samples) { - GST_LOG_OBJECT (demux, "stream %d samples exhausted", i); - continue; - } - - GST_LOG_OBJECT (demux, - "Checking Stream %d (sample_index:%d / offset:%lld / size:%d)", - i, stream->sample_index, stream->samples[stream->sample_index].offset, - stream->samples[stream->sample_index].size); - - if (((smalloffs == -1) - || (stream->samples[stream->sample_index].offset < smalloffs)) - && (stream->samples[stream->sample_index].size)) { - smallidx = i; - smalloffs = stream->samples[stream->sample_index].offset; - } - } - - GST_LOG_OBJECT (demux, "stream %d offset %lld demux->offset :%lld", - smallidx, smalloffs, demux->offset); - - if (smallidx == -1) - return -1; - stream = demux->streams[smallidx]; - - if (stream->samples[stream->sample_index].offset >= demux->offset) { - demux->todrop = - stream->samples[stream->sample_index].offset - demux->offset; - return stream->samples[stream->sample_index].size + demux->todrop; - } - - GST_DEBUG_OBJECT (demux, "There wasn't any entry at offset %lld", - demux->offset); - return -1; -} - -static void -gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom) -{ - gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom); - - gst_element_post_message (GST_ELEMENT_CAST (demux), - gst_message_new_element (GST_OBJECT_CAST (demux), - gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL))); -} - -/* FIXME, unverified after edit list updates */ -static GstFlowReturn -gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf) -{ - GstQTDemux *demux; - GstFlowReturn ret = GST_FLOW_OK; - - demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad)); - - gst_adapter_push (demux->adapter, inbuf); - - /* we never really mean to buffer that much */ - if (demux->neededbytes == -1) - goto eos; - - GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u", - inbuf, demux->neededbytes, gst_adapter_available (demux->adapter)); - - while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) && - (ret == GST_FLOW_OK)) { - - GST_DEBUG_OBJECT (demux, - "state:%d , demux->neededbytes:%d, demux->offset:%lld", demux->state, - demux->neededbytes, demux->offset); - - switch (demux->state) { - case QTDEMUX_STATE_INITIAL:{ - const guint8 *data; - guint32 fourcc; - guint64 size; - - data = gst_adapter_peek (demux->adapter, demux->neededbytes); - - /* get fourcc/length, set neededbytes */ - extract_initial_length_and_fourcc ((guint8 *) data, &size, &fourcc); - GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] " - "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size); - if (size == 0) { - GST_ELEMENT_ERROR (demux, STREAM, DECODE, - (_("This file is invalid and cannot be played.")), - ("initial atom '%" GST_FOURCC_FORMAT "' has empty length", - GST_FOURCC_ARGS (fourcc))); - ret = GST_FLOW_ERROR; - break; - } - if (fourcc == FOURCC_mdat) { - if (demux->n_streams > 0) { - demux->state = QTDEMUX_STATE_MOVIE; - demux->neededbytes = next_entry_size (demux); - } else { - guint bs; - - buffer_data: - /* there may be multiple mdat (or alike) buffers */ - /* sanity check */ - if (demux->mdatbuffer) - bs = GST_BUFFER_SIZE (demux->mdatbuffer); - else - bs = 0; - if (size + bs > 10 * (1 << 20)) - goto no_moov; - demux->state = QTDEMUX_STATE_BUFFER_MDAT; - demux->neededbytes = size; - if (!demux->mdatbuffer) - demux->mdatoffset = demux->offset; - } - } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) { - GST_ELEMENT_ERROR (demux, STREAM, DECODE, - (_("This file is invalid and cannot be played.")), - ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT, - GST_FOURCC_ARGS (fourcc), size)); - ret = GST_FLOW_ERROR; - break; - } else { - /* this means we already started buffering and still no moov header, - * let's continue buffering everything till we get moov */ - if (demux->mdatbuffer && (fourcc != FOURCC_moov)) - goto buffer_data; - demux->neededbytes = size; - demux->state = QTDEMUX_STATE_HEADER; - } - break; - } - case QTDEMUX_STATE_HEADER:{ - const guint8 *data; - guint32 fourcc; - - GST_DEBUG_OBJECT (demux, "In header"); - - data = gst_adapter_peek (demux->adapter, demux->neededbytes); - - /* parse the header */ - extract_initial_length_and_fourcc (data, NULL, &fourcc); - if (fourcc == FOURCC_moov) { - GST_DEBUG_OBJECT (demux, "Parsing [moov]"); - - qtdemux_parse_moov (demux, data, demux->neededbytes); - qtdemux_node_dump (demux, demux->moov_node); - qtdemux_parse_tree (demux); - - g_node_destroy (demux->moov_node); - demux->moov_node = NULL; - GST_DEBUG_OBJECT (demux, "Finished parsing the header"); - } else { - GST_WARNING_OBJECT (demux, - "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (fourcc)); - /* Let's jump that one and go back to initial state */ - } - - if (demux->mdatbuffer && demux->n_streams) { - GstBuffer *buf; - - /* the mdat was before the header */ - GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p", - demux->n_streams, demux->mdatbuffer); - /* restore our adapter/offset view of things with upstream; - * put preceding buffered data ahead of current moov data. - * This should also handle evil mdat, moov, mdat cases and alike */ - buf = gst_adapter_take_buffer (demux->adapter, - gst_adapter_available (demux->adapter)); - gst_adapter_clear (demux->adapter); - gst_adapter_push (demux->adapter, demux->mdatbuffer); - gst_adapter_push (demux->adapter, buf); - demux->mdatbuffer = NULL; - demux->offset = demux->mdatoffset; - demux->neededbytes = next_entry_size (demux); - demux->state = QTDEMUX_STATE_MOVIE; - } else { - GST_DEBUG_OBJECT (demux, "Carrying on normally"); - gst_adapter_flush (demux->adapter, demux->neededbytes); - demux->offset += demux->neededbytes; - demux->neededbytes = 16; - demux->state = QTDEMUX_STATE_INITIAL; - } - - break; - } - case QTDEMUX_STATE_BUFFER_MDAT:{ - GstBuffer *buf; - - GST_DEBUG_OBJECT (demux, "Got our buffer at offset %lld", - demux->offset); - buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes); - GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (QT_FOURCC (GST_BUFFER_DATA (buf) + 4))); - if (demux->mdatbuffer) - demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf); - else - demux->mdatbuffer = buf; - demux->offset += demux->neededbytes; - demux->neededbytes = 16; - demux->state = QTDEMUX_STATE_INITIAL; - gst_qtdemux_post_progress (demux, 1, 1); - - break; - } - case QTDEMUX_STATE_MOVIE:{ - GstBuffer *outbuf; - QtDemuxStream *stream = NULL; - int i = -1; - - GST_DEBUG_OBJECT (demux, "BEGIN // in MOVIE for offset %lld", - demux->offset); - - if (demux->todrop) { - GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop); - gst_adapter_flush (demux->adapter, demux->todrop); - demux->neededbytes -= demux->todrop; - demux->offset += demux->todrop; - } - - /* Figure out which stream this is packet belongs to */ - for (i = 0; i < demux->n_streams; i++) { - stream = demux->streams[i]; - if (stream->sample_index >= stream->n_samples) - continue; - GST_LOG_OBJECT (demux, - "Checking stream %d (sample_index:%d / offset:%lld / size:%d)", - i, stream->sample_index, - stream->samples[stream->sample_index].offset, - stream->samples[stream->sample_index].size); - - if (stream->samples[stream->sample_index].offset == demux->offset) - break; - } - - if (G_UNLIKELY (stream == NULL || i == demux->n_streams)) - goto unknown_stream; - - /* first buffer? */ - /* initial newsegment sent here after having added pads, - * possible others in sink_event */ - if (G_UNLIKELY (demux->last_ts == GST_CLOCK_TIME_NONE)) { - gst_qtdemux_push_event (demux, - gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, - 0, GST_CLOCK_TIME_NONE, 0)); - } - - /* Put data in a buffer, set timestamps, caps, ... */ - outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes); - GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (stream->fourcc)); - - g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR); - - if (stream->samples[stream->sample_index].pts_offset) { - demux->last_ts = stream->samples[stream->sample_index].timestamp; - GST_BUFFER_TIMESTAMP (outbuf) = demux->last_ts + - stream->samples[stream->sample_index].pts_offset; - } else { - GST_BUFFER_TIMESTAMP (outbuf) = - stream->samples[stream->sample_index].timestamp; - demux->last_ts = GST_BUFFER_TIMESTAMP (outbuf); - } - GST_BUFFER_DURATION (outbuf) = - stream->samples[stream->sample_index].duration; - if (!stream->all_keyframe && - !stream->samples[stream->sample_index].keyframe) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); - - /* position reporting */ - gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME, - demux->last_ts); - gst_qtdemux_sync_streams (demux); - - /* send buffer */ - if (stream->pad) { - GST_LOG_OBJECT (demux, - "Pushing buffer with time %" GST_TIME_FORMAT " on pad %p", - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), stream->pad); - gst_buffer_set_caps (outbuf, stream->caps); - ret = gst_pad_push (stream->pad, outbuf); - } else { - gst_buffer_unref (outbuf); - ret = GST_FLOW_OK; - } - - /* combine flows */ - ret = gst_qtdemux_combine_flows (demux, stream, ret); - - stream->sample_index++; - - /* update current offset and figure out size of next buffer */ - GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u", - demux->offset, demux->neededbytes); - demux->offset += demux->neededbytes; - GST_LOG_OBJECT (demux, "offset is now %lld", demux->offset); - - if ((demux->neededbytes = next_entry_size (demux)) == -1) - goto eos; - break; - } - default: - goto invalid_state; - } - } - - /* when buffering movie data, at least show user something is happening */ - if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT && - gst_adapter_available (demux->adapter) <= demux->neededbytes) { - gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter), - demux->neededbytes); - } -done: - gst_object_unref (demux); - - return ret; - - /* ERRORS */ -unknown_stream: - { - GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found")); - ret = GST_FLOW_ERROR; - goto done; - } -eos: - { - GST_DEBUG_OBJECT (demux, "no next entry, EOS"); - ret = GST_FLOW_UNEXPECTED; - goto done; - } -invalid_state: - { - GST_ELEMENT_ERROR (demux, STREAM, FAILED, - (NULL), ("qtdemuxer invalid state %d", demux->state)); - ret = GST_FLOW_ERROR; - goto done; - } -no_moov: - { - GST_ELEMENT_ERROR (demux, STREAM, FAILED, - (NULL), ("no 'moov' atom withing first 10 MB")); - ret = GST_FLOW_ERROR; - goto done; - } -} - -static gboolean -qtdemux_sink_activate (GstPad * sinkpad) -{ - if (gst_pad_check_pull_range (sinkpad)) - return gst_pad_activate_pull (sinkpad, TRUE); - else - return gst_pad_activate_push (sinkpad, TRUE); -} - -static gboolean -qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active) -{ - GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad)); - - if (active) { - demux->pullbased = TRUE; - demux->segment_running = TRUE; - return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop, - sinkpad); - } else { - demux->segment_running = FALSE; - return gst_pad_stop_task (sinkpad); - } -} - -static gboolean -qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active) -{ - GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad)); - - demux->pullbased = FALSE; - - return TRUE; -} - -#ifdef HAVE_ZLIB -static void * -qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size) -{ - return g_malloc (items * size); -} - -static void -qtdemux_zfree (void *opaque, void *addr) -{ - g_free (addr); -} - -static void * -qtdemux_inflate (void *z_buffer, int z_length, int length) -{ - guint8 *buffer; - z_stream *z; - int ret; - - z = g_new0 (z_stream, 1); - z->zalloc = qtdemux_zalloc; - z->zfree = qtdemux_zfree; - z->opaque = NULL; - - z->next_in = z_buffer; - z->avail_in = z_length; - - buffer = (guint8 *) g_malloc (length); - ret = inflateInit (z); - while (z->avail_in > 0) { - if (z->avail_out == 0) { - length += 1024; - buffer = (guint8 *) g_realloc (buffer, length); - z->next_out = buffer + z->total_out; - z->avail_out = 1024; - } - ret = inflate (z, Z_SYNC_FLUSH); - if (ret != Z_OK) - break; - } - if (ret != Z_STREAM_END) { - g_warning ("inflate() returned %d", ret); - } - - g_free (z); - return buffer; -} -#endif /* HAVE_ZLIB */ - -static gboolean -qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, int length) -{ - GNode *cmov; - - qtdemux->moov_node = g_node_new ((guint8 *) buffer); - - GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom"); - qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length); - - cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov); - if (cmov) { - guint32 method; - GNode *dcom; - GNode *cmvd; - - dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom); - cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd); - if (dcom == NULL || cmvd == NULL) - goto invalid_compression; - - method = QT_FOURCC ((guint8 *) dcom->data + 8); - switch (method) { -#ifdef HAVE_ZLIB - case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{ - int uncompressed_length; - int compressed_length; - guint8 *buf; - - uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8); - compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12; - GST_LOG ("length = %d", uncompressed_length); - - buf = - (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12, - compressed_length, uncompressed_length); - - qtdemux->moov_node_compressed = qtdemux->moov_node; - qtdemux->moov_node = g_node_new (buf); - - qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf, - uncompressed_length); - break; - } -#endif /* HAVE_ZLIB */ - default: - GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression " - "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method)); - break; - } - } - return TRUE; - - /* ERRORS */ -invalid_compression: - { - GST_ERROR_OBJECT (qtdemux, "invalid compressed header"); - return FALSE; - } -} - -static gboolean -qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf, - const guint8 * end) -{ - while (G_UNLIKELY (buf < end)) { - GNode *child; - guint32 len; - - if (G_UNLIKELY (buf + 4 > end)) { - GST_LOG_OBJECT (qtdemux, "buffer overrun"); - break; - } - len = QT_UINT32 (buf); - if (G_UNLIKELY (len == 0)) { - GST_LOG_OBJECT (qtdemux, "empty container"); - break; - } - if (G_UNLIKELY (len < 8)) { - GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len); - break; - } - if (G_UNLIKELY (len > (end - buf))) { - GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len, end - buf); - break; - } - - child = g_node_new ((guint8 *) buf); - g_node_append (node, child); - qtdemux_parse_node (qtdemux, child, buf, len); - - buf += len; - } - return TRUE; -} - -static gboolean -qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream, - GNode * xdxt) -{ - int len = QT_UINT32 (xdxt->data); - guint8 *buf = xdxt->data; - guint8 *end = buf + len; - GstBuffer *buffer; - - /* skip size and type */ - buf += 8; - end -= 8; - - while (buf < end) { - gint size; - guint32 type; - - size = QT_UINT32 (buf); - type = QT_FOURCC (buf + 4); - - GST_LOG_OBJECT (qtdemux, "%p %p", buf, end); - - if (buf + size > end || size <= 0) - break; - - buf += 8; - size -= 8; - - GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (type)); - - switch (type) { - case FOURCC_tCtH: - buffer = gst_buffer_new_and_alloc (size); - memcpy (GST_BUFFER_DATA (buffer), buf, size); - stream->buffers = g_slist_append (stream->buffers, buffer); - GST_LOG_OBJECT (qtdemux, "parsing theora header"); - break; - case FOURCC_tCt_: - buffer = gst_buffer_new_and_alloc (size); - memcpy (GST_BUFFER_DATA (buffer), buf, size); - stream->buffers = g_slist_append (stream->buffers, buffer); - GST_LOG_OBJECT (qtdemux, "parsing theora comment"); - break; - case FOURCC_tCtC: - buffer = gst_buffer_new_and_alloc (size); - memcpy (GST_BUFFER_DATA (buffer), buf, size); - stream->buffers = g_slist_append (stream->buffers, buffer); - GST_LOG_OBJECT (qtdemux, "parsing theora codebook"); - break; - default: - GST_WARNING_OBJECT (qtdemux, - "unknown theora cookie %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (type)); - break; - } - buf += size; - } - return TRUE; -} - -static gboolean -qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer, - int length) -{ - guint32 fourcc; - guint32 node_length; - const QtNodeType *type; - const guint8 *end; - - GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %d", buffer, length); - - node_length = QT_UINT32 (buffer); - fourcc = QT_FOURCC (buffer + 4); - - /* ignore empty nodes */ - if (G_UNLIKELY (fourcc == 0 || node_length == 8)) - return TRUE; - - type = qtdemux_type_get (fourcc); - - end = buffer + length; - - GST_LOG_OBJECT (qtdemux, - "parsing '%" GST_FOURCC_FORMAT "', length=%d, name '%s'", - GST_FOURCC_ARGS (fourcc), node_length, type->name); - - if (type->flags & QT_FLAG_CONTAINER) { - qtdemux_parse_container (qtdemux, node, buffer + 8, end); - } else { - switch (fourcc) { - case FOURCC_stsd: - { - if (node_length < 20) { - GST_LOG_OBJECT (qtdemux, "skipping small stsd box"); - break; - } - GST_DEBUG_OBJECT (qtdemux, - "parsing stsd (sample table, sample description) atom"); - qtdemux_parse_container (qtdemux, node, buffer + 16, end); - break; - } - case FOURCC_mp4a: - { - guint32 version; - guint32 offset; - - if (length < 20) { - /* small boxes are also inside wave inside the mp4a box */ - GST_LOG_OBJECT (qtdemux, "skipping small mp4a box"); - break; - } - version = QT_UINT32 (buffer + 16); - - GST_DEBUG_OBJECT (qtdemux, "mp4a version 0x%08x", version); - - /* parse any esds descriptors */ - switch (version) { - case 0x00000000: - offset = 0x24; - break; - case 0x00010000: - offset = 0x34; - break; - case 0x00020000: - offset = 0x58; - break; - default: - GST_WARNING_OBJECT (qtdemux, "unhandled mp4a version 0x%08x", - version); - offset = 0; - break; - } - if (offset) - qtdemux_parse_container (qtdemux, node, buffer + offset, end); - break; - } - case FOURCC_mp4v: - { - const guint8 *buf; - guint32 version; - int tlen; - - GST_DEBUG_OBJECT (qtdemux, "parsing in mp4v"); - version = QT_UINT32 (buffer + 16); - GST_DEBUG_OBJECT (qtdemux, "version %08x", version); - if (1 || version == 0x00000000) { - buf = buffer + 0x32; - - /* FIXME Quicktime uses PASCAL string while - * the iso format uses C strings. Check the file - * type before attempting to parse the string here. */ - tlen = QT_UINT8 (buf); - GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen); - buf++; - GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf); - /* the string has a reserved space of 32 bytes so skip - * the remaining 31 */ - buf += 31; - buf += 4; /* and 4 bytes reserved */ - - GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf); - - qtdemux_parse_container (qtdemux, node, buf, end); - } - break; - } - case FOURCC_mjp2: - { - qtdemux_parse_container (qtdemux, node, buffer + 86, end); - break; - } - case FOURCC_meta: - { - GST_DEBUG_OBJECT (qtdemux, "parsing meta atom"); - qtdemux_parse_container (qtdemux, node, buffer + 12, end); - break; - } - case FOURCC_XiTh: - { - guint32 version; - guint32 offset; - - version = QT_UINT32 (buffer + 12); - GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version); - - switch (version) { - case 0x00000001: - offset = 0x62; - break; - default: - GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version); - offset = 0; - break; - } - if (offset) - qtdemux_parse_container (qtdemux, node, buffer + offset, end); - break; - } - case FOURCC_in24: - { - qtdemux_parse_container (qtdemux, node, buffer + 0x34, end); - break; - } - default: - if (!strcmp (type->name, "unknown")) - GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4); - break; - } - } - GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (fourcc)); - return TRUE; -} - -static GNode * -qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc) -{ - GNode *child; - guint8 *buffer; - guint32 child_fourcc; - - for (child = g_node_first_child (node); child; - child = g_node_next_sibling (child)) { - buffer = (guint8 *) child->data; - - child_fourcc = QT_FOURCC (buffer + 4); - - if (G_UNLIKELY (child_fourcc == fourcc)) { - return child; - } - } - return NULL; -} - -static GNode * -qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc) -{ - GNode *child; - guint8 *buffer; - guint32 child_fourcc; - - for (child = g_node_next_sibling (node); child; - child = g_node_next_sibling (child)) { - buffer = (guint8 *) child->data; - - child_fourcc = QT_FOURCC (buffer + 4); - - if (child_fourcc == fourcc) { - return child; - } - } - return NULL; -} - -static gboolean -gst_qtdemux_add_stream (GstQTDemux * qtdemux, - QtDemuxStream * stream, GstTagList * list) -{ - if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS) - goto too_many_streams; - - if (stream->subtype == FOURCC_vide) { - gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams); - - stream->pad = - gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name); - g_free (name); - - /* fps is calculated base on the duration of the first frames since - * qt does not have a fixed framerate. */ - if ((stream->n_samples == 1) && (stream->min_duration == 0)) { - /* still frame */ - stream->fps_n = 0; - stream->fps_d = 1; - } else { - stream->fps_n = stream->timescale; - if (stream->min_duration == 0) - stream->fps_d = 1; - else - stream->fps_d = stream->min_duration; - } - - if (stream->caps) { - gboolean gray; - gint depth, palette_count; - const guint32 *palette_data = NULL; - - gst_caps_set_simple (stream->caps, - "width", G_TYPE_INT, stream->width, - "height", G_TYPE_INT, stream->height, - "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL); - - /* iso files: - * calculate pixel-aspect-ratio using display width and height */ - if (qtdemux->major_brand != FOURCC_qt__) { - GST_DEBUG_OBJECT (qtdemux, - "video size %dx%d, target display size %dx%d", stream->width, - stream->height, stream->display_width, stream->display_height); - - if (stream->display_width > 0 && stream->display_height > 0 && - stream->width > 0 && stream->height > 0) { - gint n, d; - - /* calculate the pixel aspect ratio using the display and pixel w/h */ - n = stream->display_width * stream->height; - d = stream->display_height * stream->width; - if (n != d) { - GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d); - gst_caps_set_simple (stream->caps, "pixel-aspect-ratio", - GST_TYPE_FRACTION, n, d, NULL); - } - } - } - - /* qt file might have pasp atom */ - if (stream->par_w > 0 && stream->par_h > 0) { - GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h); - gst_caps_set_simple (stream->caps, "pixel-aspect-ratio", - GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL); - } - - depth = stream->bits_per_sample; - - /* more than 32 bits means grayscale */ - gray = (depth > 32); - /* low 32 bits specify the depth */ - depth &= 0x1F; - - /* different number of palette entries is determined by depth. */ - palette_count = 0; - if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8)) - palette_count = (1 << depth); - - switch (palette_count) { - case 0: - break; - case 2: - palette_data = ff_qt_default_palette_2; - break; - case 4: - palette_data = ff_qt_default_palette_4; - break; - case 16: - if (gray) - palette_data = ff_qt_grayscale_palette_16; - else - palette_data = ff_qt_default_palette_16; - break; - case 256: - if (gray) - palette_data = ff_qt_grayscale_palette_256; - else - palette_data = ff_qt_default_palette_256; - break; - default: - GST_ELEMENT_WARNING (qtdemux, STREAM, DECODE, - (_("The video in this file might not play correctly.")), - ("unsupported palette depth %d", depth)); - break; - } - if (palette_data) { - GstBuffer *palette; - - /* make sure it's not writable. We leave MALLOCDATA to NULL so that we - * don't free any of the buffer data. */ - palette = gst_buffer_new (); - GST_BUFFER_FLAG_SET (palette, GST_BUFFER_FLAG_READONLY); - GST_BUFFER_DATA (palette) = (guint8 *) palette_data; - GST_BUFFER_SIZE (palette) = sizeof (guint32) * palette_count; - - gst_caps_set_simple (stream->caps, "palette_data", - GST_TYPE_BUFFER, palette, NULL); - gst_buffer_unref (palette); - } else if (palette_count != 0) { - GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED, - (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth)); - - gst_object_unref (stream->pad); - stream->pad = NULL; - } - } - qtdemux->n_video_streams++; - } else if (stream->subtype == FOURCC_soun) { - gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams); - - stream->pad = - gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name); - g_free (name); - if (stream->caps) { - gst_caps_set_simple (stream->caps, - "rate", G_TYPE_INT, (int) stream->rate, - "channels", G_TYPE_INT, stream->n_channels, NULL); - } - qtdemux->n_audio_streams++; - } else if (stream->subtype == FOURCC_strm) { - GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad"); - } else if (stream->subtype == FOURCC_subp) { - gchar *name = g_strdup_printf ("subp_%02d", qtdemux->n_subp_streams); - - stream->pad = - gst_pad_new_from_static_template (&gst_qtdemux_subpsrc_template, name); - g_free (name); - qtdemux->n_subp_streams++; - } else { - GST_DEBUG_OBJECT (qtdemux, "unknown stream type"); - goto done; - } - - qtdemux->streams[qtdemux->n_streams] = stream; - qtdemux->n_streams++; - GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams); - - if (stream->pad) { - GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream; - - gst_pad_use_fixed_caps (stream->pad); - gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event); - gst_pad_set_query_type_function (stream->pad, - gst_qtdemux_get_src_query_types); - gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query); - - GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps); - gst_pad_set_caps (stream->pad, stream->caps); - - GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p", - GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux); - gst_pad_set_active (stream->pad, TRUE); - gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad); - if (list) - gst_element_found_tags_for_pad (GST_ELEMENT_CAST (qtdemux), stream->pad, - list); - } -done: - return TRUE; - -too_many_streams: - { - GST_ELEMENT_WARNING (qtdemux, STREAM, DECODE, - (_("This file contains too many streams. Only playing first %d"), - GST_QTDEMUX_MAX_STREAMS), (NULL)); - return TRUE; - } -} - -/* collect all samples for @stream by reading the info from @stbl - */ -static gboolean -qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, - GNode * stbl) -{ - GNode *stsc; - GNode *stsz; - GNode *stco; - GNode *co64; - GNode *stts; - GNode *stss; - GNode *stps; - GNode *ctts; - const guint8 *stsc_data, *stsz_data, *stco_data, *co64_data, *stts_data; - int sample_size; - int sample_index; - int n_samples; - int n_samples_per_chunk; - int n_sample_times; - QtDemuxSample *samples; - gint i, j, k; - int index; - guint64 timestamp, time; - - /* sample to chunk */ - if (!(stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc))) - goto corrupt_file; - stsc_data = (const guint8 *) stsc->data; - - /* sample size */ - if (!(stsz = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsz))) - goto corrupt_file; - stsz_data = (const guint8 *) stsz->data; - - /* chunk offsets */ - stco = qtdemux_tree_get_child_by_type (stbl, FOURCC_stco); - co64 = qtdemux_tree_get_child_by_type (stbl, FOURCC_co64); - if (stco) { - stco_data = (const guint8 *) stco->data; - co64_data = NULL; - } else { - stco_data = NULL; - if (co64 == NULL) - goto corrupt_file; - co64_data = (const guint8 *) co64->data; - } - /* sample time */ - if (!(stts = qtdemux_tree_get_child_by_type (stbl, FOURCC_stts))) - goto corrupt_file; - stts_data = (const guint8 *) stts->data; - - sample_size = QT_UINT32 (stsz_data + 12); - if (sample_size == 0 || stream->sampled) { - n_samples = QT_UINT32 (stsz_data + 16); - - if (n_samples == 0) - goto no_samples; - else if (n_samples < 0) - goto corrupt_file; - - GST_DEBUG_OBJECT (qtdemux, "stsz sample_size 0, allocating n_samples %d", - n_samples); - - samples = g_try_new0 (QtDemuxSample, n_samples); - if (samples == NULL) - goto out_of_memory; - - stream->n_samples = n_samples; - stream->samples = samples; - - /* set the sample sizes */ - if (sample_size == 0) { - const guint8 *stsz_p = stsz_data + 20; - /* different sizes for each sample */ - for (i = 0; i < n_samples; i++) { - samples[i].size = QT_UINT32 (stsz_p); - GST_LOG_OBJECT (qtdemux, "sample %d has size %d", i, samples[i].size); - stsz_p += 4; - } - } else { - /* samples have the same size */ - GST_LOG_OBJECT (qtdemux, "all samples have size %d", sample_size); - for (i = 0; i < n_samples; i++) - samples[i].size = sample_size; - } - - /* set the sample offsets in the file */ - n_samples_per_chunk = QT_UINT32 (stsc_data + 12); - index = 0; - for (i = 0; i < n_samples_per_chunk; i++) { - guint32 first_chunk, last_chunk; - guint32 samples_per_chunk; - - first_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 0) - 1; - if (G_UNLIKELY (i == n_samples_per_chunk - 1)) { - last_chunk = G_MAXUINT32; - } else { - last_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 12) - 1; - } - samples_per_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 4); - - for (j = first_chunk; j < last_chunk; j++) { - guint64 chunk_offset; - - if (stco) { - chunk_offset = QT_UINT32 (stco_data + 16 + j * 4); - } else { - chunk_offset = QT_UINT64 (co64_data + 16 + j * 8); - } - for (k = 0; k < samples_per_chunk; k++) { - GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld", - index, chunk_offset); - samples[index].offset = chunk_offset; - chunk_offset += samples[index].size; - index++; - if (G_UNLIKELY (index >= n_samples)) - goto done2; - } - } - } - done2: - - n_sample_times = QT_UINT32 (stts_data + 12); - GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", n_sample_times); - timestamp = 0; - stream->min_duration = 0; - time = 0; - index = 0; - stts_data += 16; - for (i = 0; i < n_sample_times; i++) { - guint32 n; - guint32 duration; - - n = QT_UINT32 (stts_data); - stts_data += 4; - duration = QT_UINT32 (stts_data); - stts_data += 4; - GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u ", i, n, - duration); - - /* take first duration for fps */ - if (G_UNLIKELY (stream->min_duration == 0)) - stream->min_duration = duration; - - for (j = 0; j < n; j++) { - GST_DEBUG_OBJECT (qtdemux, - "sample %d: index %d, timestamp %" GST_TIME_FORMAT, index, j, - GST_TIME_ARGS (timestamp)); - - samples[index].timestamp = timestamp; - /* add non-scaled values to avoid rounding errors */ - time += duration; - timestamp = gst_util_uint64_scale (time, GST_SECOND, stream->timescale); - samples[index].duration = timestamp - samples[index].timestamp; - - index++; - if (G_UNLIKELY (index >= n_samples)) - goto done3; - } - } - /* fill up empty timestamps with the last timestamp, this can happen when - * the last samples do not decode and so we don't have timestamps for them. - * We however look at the last timestamp to estimate the track length so we - * need something in here. */ - for (; index < n_samples; index++) { - GST_DEBUG_OBJECT (qtdemux, "fill sample %d: timestamp %" GST_TIME_FORMAT, - index, GST_TIME_ARGS (timestamp)); - samples[index].timestamp = timestamp; - samples[index].duration = -1; - } - done3: - - /* sample sync, can be NULL */ - stss = qtdemux_tree_get_child_by_type (stbl, FOURCC_stss); - - if (stss) { - /* mark keyframes */ - guint32 n_sample_syncs; - const guint8 *stss_p = (guint8 *) stss->data; - - stss_p += 12; - n_sample_syncs = QT_UINT32 (stss_p); - if (n_sample_syncs == 0) { - stream->all_keyframe = TRUE; - } else { - for (i = 0; i < n_sample_syncs; i++) { - stss_p += 4; - /* note that the first sample is index 1, not 0 */ - index = QT_UINT32 (stss_p); - if (G_LIKELY (index > 0 && index <= n_samples)) - samples[index - 1].keyframe = TRUE; - } - } - stps = qtdemux_tree_get_child_by_type (stbl, FOURCC_stps); - if (stps) { - /* stps marks partial sync frames like open GOP I-Frames */ - guint32 n_sample_syncs; - const guint8 *stps_p = (guint8 *) stps->data; - - stps_p += 12; - n_sample_syncs = QT_UINT32 (stps_p); - if (n_sample_syncs != 0) { - /* no entries, the stss table contains the real sync - * samples */ - } else { - for (i = 0; i < n_sample_syncs; i++) { - stps_p += 4; - /* note that the first sample is index 1, not 0 */ - index = QT_UINT32 (stps_p); - if (G_LIKELY (index > 0 && index <= n_samples)) - samples[index - 1].keyframe = TRUE; - } - } - } - } else { - /* no stss, all samples are keyframes */ - stream->all_keyframe = TRUE; - } - } else { - GST_DEBUG_OBJECT (qtdemux, - "stsz sample_size %d != 0, treating chunks as samples", sample_size); - /* treat chunks as samples */ - if (stco) { - n_samples = QT_UINT32 (stco_data + 12); - } else { - n_samples = QT_UINT32 (co64_data + 12); - } - - if (n_samples == 0) - goto no_samples; - else if (n_samples < 0) - goto corrupt_file; - - GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %d", n_samples); - - samples = g_try_new0 (QtDemuxSample, n_samples); - if (samples == NULL) - goto out_of_memory; - - stream->n_samples = n_samples; - stream->samples = samples; - - n_samples_per_chunk = QT_UINT32 (stsc_data + 12); - GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %d", n_samples_per_chunk); - sample_index = 0; - timestamp = 0; - for (i = 0; i < n_samples_per_chunk; i++) { - guint32 first_chunk, last_chunk; - guint32 samples_per_chunk; - - first_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 0) - 1; - /* the last chunk of each entry is calculated by taking the first chunk - * of the next entry; except if there is no next, where we fake it with - * INT_MAX */ - if (i == n_samples_per_chunk - 1) { - last_chunk = G_MAXUINT32; - } else { - last_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 12) - 1; - } - samples_per_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 4); - - GST_LOG_OBJECT (qtdemux, - "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i, - first_chunk, last_chunk, samples_per_chunk); - - for (j = first_chunk; j < last_chunk; j++) { - guint64 chunk_offset; - - if (j >= n_samples) - goto done; - - if (stco) { - chunk_offset = QT_UINT32 (stco_data + 16 + j * 4); - } else { - chunk_offset = QT_UINT64 (co64_data + 16 + j * 8); - } - GST_LOG_OBJECT (qtdemux, - "Creating entry %d with offset %" G_GUINT64_FORMAT, j, - chunk_offset); - - samples[j].offset = chunk_offset; - - if (stream->samples_per_frame * stream->bytes_per_frame) { - samples[j].size = (samples_per_chunk * stream->n_channels) / - stream->samples_per_frame * stream->bytes_per_frame; - } else { - samples[j].size = samples_per_chunk; - } - - GST_DEBUG_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT - ", size %u", j, GST_TIME_ARGS (timestamp), samples[j].size); - - samples[j].timestamp = timestamp; - sample_index += samples_per_chunk; - - timestamp = gst_util_uint64_scale (sample_index, - GST_SECOND, stream->timescale); - samples[j].duration = timestamp - samples[j].timestamp; - - samples[j].keyframe = TRUE; - } - } - } - - /* composition time to sample */ - if ((ctts = qtdemux_tree_get_child_by_type (stbl, FOURCC_ctts))) { - const guint8 *ctts_data, *ctts_p; - guint32 n_entries; - guint32 count; - gint32 soffset; - - ctts_data = (const guint8 *) ctts->data; - n_entries = QT_UINT32 (ctts_data + 12); - - /* Fill in the pts_offsets */ - index = 0; - ctts_p = ctts_data + 16; - /* FIXME: make sure we don't read beyond the atom size/boundary */ - for (i = 0; i < n_entries; i++) { - count = QT_UINT32 (ctts_p); - ctts_p += 4; - soffset = QT_UINT32 (ctts_p); - ctts_p += 4; - for (j = 0; j < count; j++) { - /* we operate with very small soffset values here, it shouldn't overflow */ - samples[index].pts_offset = soffset * GST_SECOND / stream->timescale; - index++; - if (G_UNLIKELY (index >= n_samples)) - goto done; - } - } - } -done: - return TRUE; - -/* ERRORS */ -corrupt_file: - { - GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE, - (_("This file is corrupt and cannot be played.")), (NULL)); - return FALSE; - } -no_samples: - { - GST_WARNING_OBJECT (qtdemux, "stream has no samples"); - return FALSE; - } -out_of_memory: - { - GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples", n_samples); - return FALSE; - } -} - -/* collect all segment info for @stream. - */ -static gboolean -qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream, - GNode * trak) -{ - GNode *edts; - - /* parse and prepare segment info from the edit list */ - GST_DEBUG_OBJECT (qtdemux, "looking for edit list container"); - stream->n_segments = 0; - stream->segments = NULL; - if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) { - GNode *elst; - gint n_segments; - gint i, count; - guint64 time, stime; - guint8 *buffer; - - GST_DEBUG_OBJECT (qtdemux, "looking for edit list"); - if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst))) - goto done; - - buffer = elst->data; - - n_segments = QT_UINT32 (buffer + 12); - - /* we might allocate a bit too much, at least allocate 1 segment */ - stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1)); - - /* segments always start from 0 */ - time = 0; - stime = 0; - count = 0; - for (i = 0; i < n_segments; i++) { - guint64 duration; - guint64 media_time; - QtDemuxSegment *segment; - guint32 rate_int; - - media_time = QT_UINT32 (buffer + 20 + i * 12); - - /* -1 media time is an empty segment, just ignore it */ - if (media_time == G_MAXUINT32) - continue; - - duration = QT_UINT32 (buffer + 16 + i * 12); - - segment = &stream->segments[count++]; - - /* time and duration expressed in global timescale */ - segment->time = stime; - /* add non scaled values so we don't cause roundoff errors */ - time += duration; - stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale); - segment->stop_time = stime; - segment->duration = stime - segment->time; - /* media_time expressed in stream timescale */ - segment->media_start = - gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale); - segment->media_stop = segment->media_start + segment->duration; - rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12); - - if (rate_int <= 1) { - /* 0 is not allowed, some programs write 1 instead of the floating point - * value */ - GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT, - rate_int); - segment->rate = 1; - } else { - segment->rate = rate_int / 65536.0; - } - - GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT - ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT - ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time), - GST_TIME_ARGS (segment->duration), - GST_TIME_ARGS (segment->media_start), segment->rate, rate_int); - } - GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count); - stream->n_segments = count; - } -done: - - /* push based does not handle segments, so act accordingly here, - * and warn if applicable */ - if (!qtdemux->pullbased) { - GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments"); - /* remove and use default one below, we stream like it anyway */ - g_free (stream->segments); - stream->segments = NULL; - stream->n_segments = 0; - } - - /* no segments, create one to play the complete trak */ - if (stream->n_segments == 0) { - GstClockTime stream_duration = 0; - - if (stream->segments == NULL) - stream->segments = g_new (QtDemuxSegment, 1); - - /* samples know best */ - if (stream->n_samples > 0) { - stream_duration = - stream->samples[stream->n_samples - 1].timestamp + - stream->samples[stream->n_samples - 1].pts_offset + - stream->samples[stream->n_samples - 1].duration; - } - - stream->segments[0].time = 0; - stream->segments[0].stop_time = stream_duration; - stream->segments[0].duration = stream_duration; - stream->segments[0].media_start = 0; - stream->segments[0].media_stop = stream_duration; - stream->segments[0].rate = 1.0; - - GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT, - GST_TIME_ARGS (stream_duration)); - stream->n_segments = 1; - } - GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments); - - return TRUE; -} - -/* parse the traks. - * With each track we associate a new QtDemuxStream that contains all the info - * about the trak. - * traks that do not decode to something (like strm traks) will not have a pad. - */ -static gboolean -qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak) -{ - int offset; - GNode *tkhd; - GNode *mdia; - GNode *mdhd; - GNode *hdlr; - GNode *minf; - GNode *stbl; - GNode *stsd; - GNode *mp4a; - GNode *mp4v; - GNode *wave; - GNode *esds; - GNode *pasp; - QtDemuxStream *stream; - GstTagList *list = NULL; - gchar *codec = NULL; - const guint8 *stsd_data; - guint32 version; - - stream = g_new0 (QtDemuxStream, 1); - /* new streams always need a discont */ - stream->discont = TRUE; - /* we enable clipping for raw audio/video streams */ - stream->need_clip = FALSE; - stream->segment_index = -1; - stream->time_position = 0; - stream->sample_index = -1; - stream->last_ret = GST_FLOW_OK; - - if (!(tkhd = qtdemux_tree_get_child_by_type (trak, FOURCC_tkhd))) - goto corrupt_file; - - GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags: 0x%08x", - QT_UINT32 ((guint8 *) tkhd->data + 8)); - - if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia))) - goto corrupt_file; - - if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) { - /* be nice for some crooked mjp2 files that use mhdr for mdhd */ - if (qtdemux->major_brand != FOURCC_mjp2 || - !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr))) - goto corrupt_file; - } - - version = QT_UINT32 ((guint8 *) mdhd->data + 8); - GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version); - if (version == 0x01000000) { - stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28); - stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32); - } else { - stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20); - stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24); - } - - GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT, - stream->timescale); - GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT, - stream->duration); - - if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0)) - goto corrupt_file; - - if (qtdemux->duration != G_MAXINT32 && stream->duration != G_MAXINT32) { - guint64 tdur1, tdur2; - - /* don't overflow */ - tdur1 = stream->timescale * (guint64) qtdemux->duration; - tdur2 = qtdemux->timescale * (guint64) stream->duration; - - /* HACK: - * some of those trailers, nowadays, have prologue images that are - * themselves vide tracks as well. I haven't really found a way to - * identify those yet, except for just looking at their duration. */ - if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) { - GST_WARNING_OBJECT (qtdemux, - "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT - " vs. %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT ") of the stream " - "found, assuming preview image or something; skipping track", - stream->duration, stream->timescale, qtdemux->duration, - qtdemux->timescale); - g_free (stream); - return TRUE; - } - } - - if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr))) - goto corrupt_file; - - GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12))); - - stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16); - GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (stream->subtype)); - - if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf))) - goto corrupt_file; - - if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl))) - goto corrupt_file; - - /* parse stsd */ - if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd))) - goto corrupt_file; - stsd_data = (const guint8 *) stsd->data; - - if (stream->subtype == FOURCC_vide) { - guint32 fourcc; - const guint8 *tkhd_data = (const guint8 *) tkhd->data; - - stream->sampled = TRUE; - - /* version 1 uses some 64-bit ints */ - offset = (QT_UINT8 (tkhd_data + 8) == 1) ? 96 : 84; - stream->display_width = (guint) QT_FP32 (tkhd_data + offset); - stream->display_height = (guint) QT_FP32 (tkhd_data + offset + 4); - - offset = 16; - stream->fourcc = fourcc = QT_FOURCC (stsd_data + offset + 4); - GST_LOG_OBJECT (qtdemux, "st type: %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (fourcc)); - - stream->width = QT_UINT16 (stsd_data + offset + 32); - stream->height = QT_UINT16 (stsd_data + offset + 34); - stream->fps_n = 0; /* this is filled in later */ - stream->fps_d = 0; /* this is filled in later */ - stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82); - stream->color_table_id = QT_UINT16 (stsd_data + offset + 84); - - GST_LOG_OBJECT (qtdemux, "frame count: %u", - QT_UINT16 (stsd_data + offset + 48)); - - if (fourcc == FOURCC_drms) - goto error_encrypted; - - stream->caps = - qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec); - if (codec) { - list = gst_tag_list_new (); - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - GST_TAG_VIDEO_CODEC, codec, NULL); - g_free (codec); - codec = NULL; - } - - esds = NULL; - pasp = NULL; - mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4v); - if (mp4v) { - esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds); - pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp); - } - - if (pasp) { - const guint8 *pasp_data = (const guint8 *) pasp->data; - - stream->par_w = QT_UINT32 (pasp_data + 8); - stream->par_h = QT_UINT32 (pasp_data + 12); - } else { - stream->par_w = 0; - stream->par_h = 0; - } - - if (esds) { - gst_qtdemux_handle_esds (qtdemux, stream, esds, list); - } else { - switch (fourcc) { - case FOURCC_avc1: - { - gint len = QT_UINT32 (stsd_data) - 0x66; - const guint8 *avc_data = stsd_data + 0x66; - - /* find avcC */ - while (len >= 0x8 && - QT_FOURCC (avc_data + 0x4) != FOURCC_avcC && - QT_UINT32 (avc_data) < len) { - len -= QT_UINT32 (avc_data); - avc_data += QT_UINT32 (avc_data); - } - - /* parse, if found */ - if (len > 0x8 && QT_FOURCC (avc_data + 0x4) == FOURCC_avcC) { - GstBuffer *buf; - gint size; - - if (QT_UINT32 (avc_data) < len) - size = QT_UINT32 (avc_data) - 0x8; - else - size = len - 0x8; - - GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd"); - - buf = gst_buffer_new_and_alloc (size); - memcpy (GST_BUFFER_DATA (buf), avc_data + 0x8, size); - gst_caps_set_simple (stream->caps, - "codec_data", GST_TYPE_BUFFER, buf, NULL); - gst_buffer_unref (buf); - } - break; - } - case FOURCC_mjp2: - { - GNode *jp2h, *colr, *mjp2, *field, *prefix; - const guint8 *data; - guint32 fourcc = 0; - - GST_DEBUG_OBJECT (qtdemux, "found mjp2"); - /* some required atoms */ - mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2); - if (!mjp2) - break; - jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h); - if (!jp2h) - break; - colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr); - if (!colr) - break; - GST_DEBUG_OBJECT (qtdemux, "found colr"); - /* try to extract colour space info */ - if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) { - switch (QT_UINT32 ((guint8 *) colr->data + 11)) { - case 16: - fourcc = GST_MAKE_FOURCC ('s', 'R', 'G', 'B'); - break; - case 17: - fourcc = GST_MAKE_FOURCC ('G', 'R', 'A', 'Y'); - break; - case 18: - fourcc = GST_MAKE_FOURCC ('s', 'Y', 'U', 'V'); - break; - default: - break; - } - } - - if (fourcc) - gst_caps_set_simple (stream->caps, - "fourcc", GST_TYPE_FOURCC, fourcc, NULL); - - /* some optional atoms */ - field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel); - prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x); - - /* indicate possible fields in caps */ - if (field) { - data = (guint8 *) field->data + 8; - if (*data != 1) - gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT, - (gint) * data, NULL); - } - /* add codec_data if provided */ - if (prefix) { - GstBuffer *buf; - gint len; - - GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd"); - data = prefix->data; - len = QT_UINT32 (data); - if (len > 0x8) { - len -= 0x8; - buf = gst_buffer_new_and_alloc (len); - memcpy (GST_BUFFER_DATA (buf), data + 8, len); - gst_caps_set_simple (stream->caps, - "codec_data", GST_TYPE_BUFFER, buf, NULL); - gst_buffer_unref (buf); - } - } - break; - } - case FOURCC_SVQ3: - case FOURCC_VP31: - { - GstBuffer *buf; - gint len = QT_UINT32 (stsd_data); - - GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd"); - - buf = gst_buffer_new_and_alloc (len); - memcpy (GST_BUFFER_DATA (buf), stsd_data, len); - gst_caps_set_simple (stream->caps, - "codec_data", GST_TYPE_BUFFER, buf, NULL); - gst_buffer_unref (buf); - break; - } - case FOURCC_rle_: - { - gst_caps_set_simple (stream->caps, - "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL); - break; - } - case FOURCC_XiTh: - { - GNode *xith, *xdxt; - - GST_DEBUG_OBJECT (qtdemux, "found XiTh"); - xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh); - if (!xith) - break; - - xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT); - if (!xdxt) - break; - - GST_DEBUG_OBJECT (qtdemux, "found XdxT node"); - /* collect the headers and store them in a stream list so that we can - * send them out first */ - qtdemux_parse_theora_extension (qtdemux, stream, xdxt); - break; - } - default: - break; - } - } - - GST_INFO_OBJECT (qtdemux, - "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT, - GST_FOURCC_ARGS (fourcc), stream->caps); - - } else if (stream->subtype == FOURCC_soun) { - int version, samplesize; - guint32 fourcc; - int len; - guint16 compression_id; - - len = QT_UINT32 (stsd_data + 16); - GST_LOG_OBJECT (qtdemux, "stsd len: %d", len); - - stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4); - GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (stream->fourcc)); - - offset = 32; - - version = QT_UINT32 (stsd_data + offset); - stream->n_channels = QT_UINT16 (stsd_data + offset + 8); - samplesize = QT_UINT16 (stsd_data + offset + 10); - compression_id = QT_UINT16 (stsd_data + offset + 12); - stream->rate = QT_FP32 (stsd_data + offset + 16); - - GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version); - GST_LOG_OBJECT (qtdemux, "vendor: %08x", - QT_UINT32 (stsd_data + offset + 4)); - GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels); - GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize); - GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id); - GST_LOG_OBJECT (qtdemux, "packet size: %d", - QT_UINT16 (stsd_data + offset + 14)); - GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate); - - if (compression_id == 0xfffe) - stream->sampled = TRUE; - - /* first assume uncompressed audio */ - stream->bytes_per_sample = samplesize / 8; - stream->samples_per_frame = stream->n_channels; - stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample; - stream->samples_per_packet = stream->samples_per_frame; - stream->bytes_per_packet = stream->bytes_per_sample; - - offset = 52; - switch (fourcc) { - /* Yes, these have to be hard-coded */ - case FOURCC_MAC6: - { - stream->samples_per_packet = 6; - stream->bytes_per_packet = 1; - stream->bytes_per_frame = 1 * stream->n_channels; - stream->bytes_per_sample = 1; - stream->samples_per_frame = 6 * stream->n_channels; - break; - } - case FOURCC_MAC3: - { - stream->samples_per_packet = 3; - stream->bytes_per_packet = 1; - stream->bytes_per_frame = 1 * stream->n_channels; - stream->bytes_per_sample = 1; - stream->samples_per_frame = 3 * stream->n_channels; - break; - } - case FOURCC_ima4: - { - stream->samples_per_packet = 64; - stream->bytes_per_packet = 34; - stream->bytes_per_frame = 34 * stream->n_channels; - stream->bytes_per_sample = 2; - stream->samples_per_frame = 64 * stream->n_channels; - break; - } - case FOURCC_ulaw: - case FOURCC_alaw: - { - stream->samples_per_packet = 1; - stream->bytes_per_packet = 1; - stream->bytes_per_frame = 1 * stream->n_channels; - stream->bytes_per_sample = 1; - stream->samples_per_frame = 1 * stream->n_channels; - break; - } - case FOURCC_agsm: - { - stream->samples_per_packet = 160; - stream->bytes_per_packet = 33; - stream->bytes_per_frame = 33 * stream->n_channels; - stream->bytes_per_sample = 2; - stream->samples_per_frame = 160 * stream->n_channels; - break; - } - default: - break; - } - - if (version == 0x00010000) { - switch (fourcc) { - case FOURCC_twos: - case FOURCC_sowt: - case FOURCC_raw_: - break; - default: - { - /* only parse extra decoding config for non-pcm audio */ - stream->samples_per_packet = QT_UINT32 (stsd_data + offset); - stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4); - stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8); - stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12); - - GST_LOG_OBJECT (qtdemux, "samples/packet: %d", - stream->samples_per_packet); - GST_LOG_OBJECT (qtdemux, "bytes/packet: %d", - stream->bytes_per_packet); - GST_LOG_OBJECT (qtdemux, "bytes/frame: %d", - stream->bytes_per_frame); - GST_LOG_OBJECT (qtdemux, "bytes/sample: %d", - stream->bytes_per_sample); - - if (!stream->sampled && stream->bytes_per_packet) { - stream->samples_per_frame = (stream->bytes_per_frame / - stream->bytes_per_packet) * stream->samples_per_packet; - GST_LOG_OBJECT (qtdemux, "samples/frame: %d", - stream->samples_per_frame); - } - break; - } - } - } else if (version == 0x00020000) { - union - { - gdouble fp; - guint64 val; - } qtfp; - - stream->samples_per_packet = QT_UINT32 (stsd_data + offset); - qtfp.val = QT_UINT64 (stsd_data + offset + 4); - stream->rate = qtfp.fp; - stream->n_channels = QT_UINT32 (stsd_data + offset + 12); - - GST_LOG_OBJECT (qtdemux, "samples/packet: %d", - stream->samples_per_packet); - GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate); - GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels); - - } else { - GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version); - } - - if (fourcc == FOURCC_drms) - goto error_encrypted; - - stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0, - &codec); - - switch (fourcc) { - case FOURCC_in24: - { - GNode *enda; - GNode *in24; - - in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24); - - enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda); - if (!enda) { - wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave); - if (wave) - enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda); - } - if (enda) { - gst_caps_set_simple (stream->caps, - "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL); - } - break; - } - default: - break; - } - - if (codec) { - list = gst_tag_list_new (); - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - GST_TAG_AUDIO_CODEC, codec, NULL); - g_free (codec); - codec = NULL; - } - - mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a); - wave = NULL; - esds = NULL; - if (mp4a) { - wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave); - if (wave) - esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds); - if (!esds) - esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds); - } - - if (esds) { - gst_qtdemux_handle_esds (qtdemux, stream, esds, list); - } else { - switch (fourcc) { -#if 0 - /* FIXME: what is in the chunk? */ - case FOURCC_QDMC: - { - gint len = QT_UINT32 (stsd_data); - - /* seems to be always = 116 = 0x74 */ - break; - } -#endif - case FOURCC_QDM2: - { - gint len = QT_UINT32 (stsd_data); - - if (len > 0x4C) { - GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C); - - memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x4C, len - 0x4C); - gst_caps_set_simple (stream->caps, - "codec_data", GST_TYPE_BUFFER, buf, NULL); - gst_buffer_unref (buf); - } - gst_caps_set_simple (stream->caps, - "samplesize", G_TYPE_INT, samplesize, NULL); - break; - } - case FOURCC_alac: - { - gint len = QT_UINT32 (stsd_data); - - if (len > 0x34) { - GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34); - - memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34); - gst_caps_set_simple (stream->caps, - "codec_data", GST_TYPE_BUFFER, buf, NULL); - gst_buffer_unref (buf); - } - gst_caps_set_simple (stream->caps, - "samplesize", G_TYPE_INT, samplesize, NULL); - break; - } - case FOURCC_samr: - { - gint len = QT_UINT32 (stsd_data); - - if (len > 0x34) { - GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34); - - memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34); - - gst_caps_set_simple (stream->caps, - "codec_data", GST_TYPE_BUFFER, buf, NULL); - gst_buffer_unref (buf); - } - break; - } - default: - break; - } - } - GST_INFO_OBJECT (qtdemux, - "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT, - GST_FOURCC_ARGS (fourcc), stream->caps); - - } else if (stream->subtype == FOURCC_strm) { - guint32 fourcc; - - stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4); - GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (fourcc)); - - if (fourcc != FOURCC_rtsp) { - GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (fourcc)); - goto unknown_stream; - } - stream->sampled = TRUE; - } else if (stream->subtype == FOURCC_subp) { - guint32 fourcc; - - stream->sampled = TRUE; - - offset = 16; - stream->fourcc = fourcc = QT_FOURCC (stsd_data + offset + 4); - GST_LOG_OBJECT (qtdemux, "st type: %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (fourcc)); - - stream->caps = - qtdemux_subp_caps (qtdemux, stream, fourcc, stsd_data, &codec); - } else { - goto unknown_stream; - } - - /* promote to sampled format */ - if (stream->fourcc == FOURCC_samr) { - /* force mono 8000 Hz for AMR */ - stream->sampled = TRUE; - stream->n_channels = 1; - stream->rate = 8000; - } else if (stream->fourcc == FOURCC_sawb) { - /* force mono 16000 Hz for AMR-WB */ - stream->sampled = TRUE; - stream->n_channels = 1; - stream->rate = 16000; - } else if (stream->fourcc == FOURCC_mp4a) { - stream->sampled = TRUE; - } - - /* collect sample information */ - if (!qtdemux_parse_samples (qtdemux, stream, stbl)) - goto samples_failed; - - /* configure segments */ - if (!qtdemux_parse_segments (qtdemux, stream, trak)) - goto segments_failed; - - /* now we are ready to add the stream */ - gst_qtdemux_add_stream (qtdemux, stream, list); - - return TRUE; - -/* ERRORS */ -corrupt_file: - { - GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE, - (_("This file is corrupt and cannot be played.")), (NULL)); - g_free (stream); - return FALSE; - } -error_encrypted: - { - GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL)); - g_free (stream); - return FALSE; - } -samples_failed: - { - /* we posted an error already */ - g_free (stream); - return FALSE; - } -segments_failed: - { - /* we posted an error already */ - g_free (stream); - return FALSE; - } -unknown_stream: - { - GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (stream->subtype)); - g_free (stream); - return TRUE; - } -} - -static inline gboolean -qtdemux_is_string_3gp (GstQTDemux * qtdemux, guint32 fourcc) -{ - /* Detect if the tag must be handled as 3gpp - i18n metadata. The first - * check is for catching all the possible brands, e.g. 3gp4,3gp5,3gg6,.. and - * handling properly the tags present in more than one brand.*/ - return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) == - GST_MAKE_FOURCC ('3', 'g', 0, 0) - && (fourcc == FOURCC_cprt || fourcc == FOURCC_gnre - || fourcc == FOURCC_kywd)) || fourcc == FOURCC_titl - || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth - || fourcc == FOURCC_albm; -} - -static void -qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag, - const char *dummy, GNode * node) -{ - const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; - int offset; - char *name; - gchar *data; - gdouble longitude, latitude, altitude; - - data = node->data; - offset = 14; - - /* TODO: language code skipped */ - - name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars); - - if (!name) { - /* do not alarm in trivial case, but bail out otherwise */ - if (*(data + offset) != 0) { - GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, " - "giving up", tag); - } - } else { - gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, - GST_TAG_GEO_LOCATION_NAME, name, NULL); - offset += strlen (name); - g_free (name); - } - - /* +1 +1 = skip null-terminator and location role byte */ - offset += 1 + 1; - longitude = QT_FP32 (data + offset); - - offset += 4; - latitude = QT_FP32 (data + offset); - - offset += 4; - altitude = QT_FP32 (data + offset); - - /* one invalid means all are invalid */ - if (longitude >= -180.0 && longitude <= 180.0 && - latitude >= -90.0 && latitude <= 90.0) { - gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, - GST_TAG_GEO_LOCATION_LATITUDE, latitude, - GST_TAG_GEO_LOCATION_LONGITUDE, longitude, - GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL); - } - - /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */ -} - - -static void -qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy, - GNode * node) -{ - guint16 y; - GDate *date; - - y = QT_UINT16 ((guint8 *) node->data + 12); - GST_DEBUG_OBJECT (qtdemux, "year: %u", y); - - date = g_date_new_dmy (1, 1, y); - gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL); - g_date_free (date); -} - -static void -qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag, - const char *dummy, GNode * node) -{ - int offset; - char *tag_str = NULL; - guint8 *entity; - guint16 table; - - - offset = 12; - entity = (guint8 *) node->data + offset; - - offset += 4; - table = QT_UINT16 ((guint8 *) node->data + offset); - - /* Language code skipped */ - - offset += 4; - - /* Tag format: "XXXX://Y[YYYY]/classification info string" - * XXXX: classification entity, fixed length 4 chars. - * Y[YYYY]: classification table, max 5 chars. - */ - tag_str = g_strdup_printf ("----://%u/%s", - table, (char *) node->data + offset); - - /* memcpy To be sure we're preserving byte order */ - memcpy (tag_str, entity, 4); - GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str); - - gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag, - tag_str, NULL); - - g_free (tag_str); -} - -static void -qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag, const char *dummy, - GNode * node) -{ - const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; - GNode *data; - char *s; - int len; - guint32 type; - int offset; - - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - if (data) { - len = QT_UINT32 (data->data); - type = QT_UINT32 ((guint8 *) data->data + 8); - if (type == 0x00000001) { - s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16, - env_vars); - if (s) { - GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s)); - gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, - NULL); - g_free (s); - } else { - GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag); - } - } - } else { - len = QT_UINT32 (node->data); - type = QT_UINT32 ((guint8 *) node->data + 4); - if ((type >> 24) == 0xa9) { - /* Type starts with the (C) symbol, so the next 32 bits are - * the language code, which we ignore */ - offset = 12; - GST_DEBUG_OBJECT (qtdemux, "found international text tag"); - } else if (qtdemux_is_string_3gp (qtdemux, - QT_FOURCC ((guint8 *) node->data + 4))) { - offset = 14; - /* 16-bit Language code is ignored here as well */ - GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag"); - } else { - offset = 8; - GST_DEBUG_OBJECT (qtdemux, "found normal text tag"); - } - s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset, - len - offset, env_vars); - if (s) { - GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s)); - gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL); - g_free (s); - } else { - GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag); - } - } -} - -static void -qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag, - const char *dummy, GNode * node) -{ - const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; - guint8 *data; - char *s, *t, *k = NULL; - int len; - int offset; - int count; - - /* re-route to normal string tag if not 3GP */ - if (!qtdemux_is_string_3gp (qtdemux, FOURCC_kywd)) - { - qtdemux_tag_add_str (qtdemux, tag, dummy, node); - return ; - } - - GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag"); - - data = node->data; - - len = QT_UINT32 (data); - if (len < 15) - goto short_read; - - count = QT_UINT8 (data + 14); - offset = 15; - for (; count; count--) { - gint slen; - - if (offset + 1 > len) - goto short_read; - slen = QT_UINT8 (data + offset); - offset += 1; - if (offset + slen > len) - goto short_read; - s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset, - slen, env_vars); - if (s) { - GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s)); - if (k) { - t = g_strjoin (",", k, s, NULL); - g_free (s); - g_free (k); - k = t; - } else { - k = s; - } - } else { - GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8"); - } - offset += slen; - } - -done: - if (k) { - GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k)); - gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL); - } - g_free (k); - - return; - - /* ERRORS */ -short_read: - { - GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords"); - goto done; - } -} - -static void -qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1, - const char *tag2, GNode * node) -{ - GNode *data; - int len; - int type; - int n1, n2; - - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - if (data) { - len = QT_UINT32 (data->data); - type = QT_UINT32 ((guint8 *) data->data + 8); - if (type == 0x00000000 && len >= 22) { - n1 = QT_UINT16 ((guint8 *) data->data + 18); - n2 = QT_UINT16 ((guint8 *) data->data + 20); - if (n1 > 0) { - GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1); - gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, - tag1, n1, NULL); - } - if (n2 > 0) { - GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2); - gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, - tag2, n2, NULL); - } - } - } -} - -static void -qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy, - GNode * node) -{ - GNode *data; - int len; - int type; - int n1; - - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - if (data) { - len = QT_UINT32 (data->data); - type = QT_UINT32 ((guint8 *) data->data + 8); - GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len); - /* some files wrongly have a type 0x0f=15, but it should be 0x15 */ - if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) { - n1 = QT_UINT16 ((guint8 *) data->data + 16); - if (n1) { - /* do not add bpm=0 */ - GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1); - gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, - tag1, (gdouble) n1, NULL); - } - } - } -} - -static void -qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy, - GNode * node) -{ - GNode *data; - int len; - int type; - GstBuffer *buf; - - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - if (data) { - len = QT_UINT32 (data->data); - type = QT_UINT32 ((guint8 *) data->data + 8); - GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len); - if ((type == 0x0000000d || type == 0x0000000e) && len > 16) { - if ((buf = gst_tag_image_data_to_image_buffer ((guint8 *) data->data + 16, - len - 16, GST_TAG_IMAGE_TYPE_NONE))) { - GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16); - gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, - tag1, buf, NULL); - gst_buffer_unref (buf); - } - } - } -} - -static void -qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy, - GNode * node) -{ - GNode *data; - char *s; - int len; - int type; - - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - if (data) { - len = QT_UINT32 (data->data); - type = QT_UINT32 ((guint8 *) data->data + 8); - if (type == 0x00000001) { - guint y, m = 1, d = 1; - gint ret; - - s = g_strndup ((char *) data->data + 16, len - 16); - GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s); - ret = sscanf (s, "%u-%u-%u", &y, &m, &d); - if (ret >= 1 && y > 1500 && y < 3000) { - GDate *date; - - date = g_date_new_dmy (d, m, y); - gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, - date, NULL); - g_date_free (date); - } else { - GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s); - } - g_free (s); - } - } -} - -static void -qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy, - GNode * node) -{ - static const gchar *genres[] = { - "N/A", "Blues", "Classic Rock", "Country", "Dance", "Disco", - "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", - "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", - "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", - "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", - "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", - "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", - "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", - "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", - "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", - "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", - "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", - "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", - "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", - "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", - "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob", - "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", - "Gothic Rock", "Progressive Rock", "Psychedelic Rock", - "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", - "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", - "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", - "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", - "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", - "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", - "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club House", - "Hardcore", "Terror", "Indie", "BritPop", "NegerPunk", - "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal", - "Black Metal", "Crossover", "Contemporary C", "Christian Rock", - "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop" - }; - GNode *data; - int len; - int type; - int n; - - /* re-route to normal string tag if 3GP */ - if (qtdemux_is_string_3gp (qtdemux, FOURCC_gnre)) - { - qtdemux_tag_add_str (qtdemux, tag, dummy, node); - return; - } - - data = qtdemux_tree_get_child_by_type (node, FOURCC_data); - if (data) { - len = QT_UINT32 (data->data); - type = QT_UINT32 ((guint8 *) data->data + 8); - if (type == 0x00000000 && len >= 18) { - n = QT_UINT16 ((guint8 *) data->data + 16); - if (n > 0 && n < sizeof (genres) / sizeof (char *)) { - GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genres[n]); - gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, - tag, genres[n], NULL); - } - } - } -} - -typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, - const char *tag, const char *tag_bis, GNode * node); - -static const struct -{ - guint32 fourcc; - const gchar *gst_tag; - const gchar *gst_tag_bis; - const GstQTDemuxAddTagFunc func; -} add_funcs[] = { - { - FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, { - FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, { - FOURCC__grp, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { - FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, { - FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { - FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, { - FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, { - FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, { - FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, { - FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, { - FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, { - FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, { - FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, { - FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, { - FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, { - FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, { - FOURCC__too, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, { - FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, { - FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, { - FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, - qtdemux_tag_add_num}, { - FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT, - qtdemux_tag_add_num}, { - FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, { - FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, { - FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, { - FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, { - FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, { - FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, { - FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, { - FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, { - FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL, - qtdemux_tag_add_classification} -}; - -static void -qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux) -{ - gint len; - guint8 *data; - GstBuffer *buf; - gchar *media_type, *style; - GstCaps *caps; - guint i; - guint8 ndata[4]; - - data = node->data; - len = QT_UINT32 (data); - buf = gst_buffer_new_and_alloc (len); - memcpy (GST_BUFFER_DATA (buf), data, len); - - /* heuristic to determine style of tag */ - if (QT_FOURCC (data + 4) == FOURCC_____ || - (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data)) - style = "itunes"; - else if (demux->major_brand == FOURCC_qt__) - style = "quicktime"; - /* fall back to assuming iso/3gp tag style */ - else - style = "iso"; - - /* santize the name for the caps. */ - for (i = 0; i < 4; i++) { - guint8 d = data[4 + i]; - if (g_ascii_isalnum (d)) - ndata[i] = g_ascii_tolower (d); - else - ndata[i] = '_'; - } - - media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag", - ndata[0], ndata[1], ndata[2], ndata[3]); - GST_DEBUG_OBJECT (demux, "media type %s", media_type); - - caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL); - gst_buffer_set_caps (buf, caps); - gst_caps_unref (caps); - g_free (media_type); - - GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT, - GST_BUFFER_SIZE (buf), caps); - - gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND, - GST_QT_DEMUX_PRIVATE_TAG, buf, NULL); - gst_buffer_unref (buf); -} - -static void -qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta) -{ - GNode *meta; - GNode *ilst; - GNode *node; - gint i; - - meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta); - if (meta != NULL) { - ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst); - if (ilst == NULL) { - GST_LOG_OBJECT (qtdemux, "no ilst"); - return; - } - } else { - ilst = udta; - GST_LOG_OBJECT (qtdemux, "no meta so using udta itself"); - } - - GST_DEBUG_OBJECT (qtdemux, "new tag list"); - qtdemux->tag_list = gst_tag_list_new (); - - for (i = 0; i < G_N_ELEMENTS (add_funcs); ++i) { - node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc); - if (node) { - add_funcs[i].func (qtdemux, add_funcs[i].gst_tag, - add_funcs[i].gst_tag_bis, node); - g_node_destroy (node); - } - } - - /* parsed nodes have been removed, pass along remainder as blob */ - g_node_children_foreach (ilst, G_TRAVERSE_ALL, - (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux); - -} - -typedef struct -{ - GstStructure *structure; /* helper for sort function */ - gchar *location; - guint min_req_bitrate; - guint min_req_qt_version; -} GstQtReference; - -static gint -qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b) -{ - GstQtReference *ref_a = (GstQtReference *) a; - GstQtReference *ref_b = (GstQtReference *) b; - - if (ref_b->min_req_qt_version != ref_a->min_req_qt_version) - return ref_b->min_req_qt_version - ref_a->min_req_qt_version; - - /* known bitrates go before unknown; higher bitrates go first */ - return ref_b->min_req_bitrate - ref_a->min_req_bitrate; -} - -/* sort the redirects and post a message for the application. - */ -static void -qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references) -{ - GstQtReference *best; - GstStructure *s; - GstMessage *msg; - GValue list_val = { 0, }; - GList *l; - - g_assert (references != NULL); - - references = g_list_sort (references, qtdemux_redirects_sort_func); - - best = (GstQtReference *) references->data; - - g_value_init (&list_val, GST_TYPE_LIST); - - for (l = references; l != NULL; l = l->next) { - GstQtReference *ref = (GstQtReference *) l->data; - GValue struct_val = { 0, }; - - ref->structure = gst_structure_new ("redirect", - "new-location", G_TYPE_STRING, ref->location, NULL); - - if (ref->min_req_bitrate > 0) { - gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT, - ref->min_req_bitrate, NULL); - } - - g_value_init (&struct_val, GST_TYPE_STRUCTURE); - g_value_set_boxed (&struct_val, ref->structure); - gst_value_list_append_value (&list_val, &struct_val); - g_value_unset (&struct_val); - /* don't free anything here yet, since we need best->structure below */ - } - - g_assert (best != NULL); - s = gst_structure_copy (best->structure); - - if (g_list_length (references) > 1) { - gst_structure_set_value (s, "locations", &list_val); - } - - g_value_unset (&list_val); - - for (l = references; l != NULL; l = l->next) { - GstQtReference *ref = (GstQtReference *) l->data; - - gst_structure_free (ref->structure); - g_free (ref->location); - g_free (ref); - } - g_list_free (references); - - GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s); - msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s); - gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg); -} - -/* look for redirect nodes, collect all redirect information and - * process it. - */ -static gboolean -qtdemux_parse_redirects (GstQTDemux * qtdemux) -{ - GNode *rmra, *rmda, *rdrf; - - rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra); - if (rmra) { - GList *redirects = NULL; - - rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda); - while (rmda) { - GstQtReference ref = { NULL, NULL, 0, 0 }; - GNode *rmdr, *rmvc; - - if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) { - ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12); - GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u", - ref.min_req_bitrate); - } - - if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) { - guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12); - guint version = QT_UINT32 ((guint8 *) rmvc->data + 16); - -#ifndef GST_DISABLE_GST_DEBUG - guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20); -#endif - guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24); - - GST_LOG_OBJECT (qtdemux, - "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x" - ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version, - bitmask, check_type); - if (package == FOURCC_qtim && check_type == 0) { - ref.min_req_qt_version = version; - } - } - - rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf); - if (rdrf) { - guint32 ref_type; - guint8 *ref_data; - - ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12); - ref_data = (guint8 *) rdrf->data + 20; - if (ref_type == FOURCC_alis) { - guint record_len, record_version, fn_len; - - /* MacOSX alias record, google for alias-layout.txt */ - record_len = QT_UINT16 (ref_data + 4); - record_version = QT_UINT16 (ref_data + 4 + 2); - fn_len = QT_UINT8 (ref_data + 50); - if (record_len > 50 && record_version == 2 && fn_len > 0) { - ref.location = g_strndup ((gchar *) ref_data + 51, fn_len); - } - } else if (ref_type == FOURCC_url_) { - ref.location = g_strdup ((gchar *) ref_data); - } else { - GST_DEBUG_OBJECT (qtdemux, - "unknown rdrf reference type %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (ref_type)); - } - if (ref.location != NULL) { - GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location); - redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref))); - } else { - GST_WARNING_OBJECT (qtdemux, - "Failed to extract redirect location from rdrf atom"); - } - } - - /* look for others */ - rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda); - } - - if (redirects != NULL) { - qtdemux_process_redirects (qtdemux, redirects); - } - } - return TRUE; -} - -static GstTagList * -qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags) -{ - const gchar *fmt; - - if (tags == NULL) - tags = gst_tag_list_new (); - - if (qtdemux->major_brand == FOURCC_mjp2) - fmt = "Motion JPEG 2000"; - else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0)) - fmt = "3GP"; - else if (qtdemux->major_brand == FOURCC_qt__) - fmt = "Quicktime"; - else - fmt = "ISO MP4/M4A"; - - GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'", - GST_FOURCC_ARGS (qtdemux->major_brand), fmt); - - gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT, - fmt, NULL); - - return tags; -} - -/* we have read th complete moov node now. - * This function parses all of the relevant info, creates the traks and - * prepares all data structures for playback - */ -static gboolean -qtdemux_parse_tree (GstQTDemux * qtdemux) -{ - GNode *mvhd; - GNode *trak; - GNode *udta; - gint64 duration; - - mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd); - if (mvhd == NULL) { - GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects."); - return qtdemux_parse_redirects (qtdemux); - } - - qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20); - qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24); - - GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale); - GST_INFO_OBJECT (qtdemux, "duration: %u", qtdemux->duration); - - /* set duration in the segment info */ - gst_qtdemux_get_duration (qtdemux, &duration); - gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration); - - /* parse all traks */ - trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak); - while (trak) { - qtdemux_parse_trak (qtdemux, trak); - /* iterate all siblings */ - trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak); - } - gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux)); - - /* find and push tags, we do this after adding the pads so we can push the - * tags downstream as well. */ - udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta); - if (udta) { - qtdemux_parse_udta (qtdemux, udta); - } else { - GST_LOG_OBJECT (qtdemux, "No udta node found."); - } - - /* FIXME: tags must be pushed after the initial newsegment event */ - qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list); - GST_INFO_OBJECT (qtdemux, "global tags: %" GST_PTR_FORMAT, qtdemux->tag_list); - gst_element_found_tags (GST_ELEMENT_CAST (qtdemux), qtdemux->tag_list); - qtdemux->tag_list = NULL; - - return TRUE; -} - -/* taken from ffmpeg */ -static unsigned int -get_size (guint8 * ptr, guint8 ** end) -{ - int count = 4; - int len = 0; - - while (count--) { - int c = *ptr; - - ptr++; - len = (len << 7) | (c & 0x7f); - if (!(c & 0x80)) - break; - } - if (end) - *end = ptr; - return len; -} - -/* this can change the codec originally present in @list */ -static void -gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream, - GNode * esds, GstTagList * list) -{ - int len = QT_UINT32 (esds->data); - guint8 *ptr = esds->data; - guint8 *end = ptr + len; - int tag; - guint8 *data_ptr = NULL; - int data_len = 0; - guint8 object_type_id = 0; - char *codec_name = NULL; - GstCaps *caps = NULL; - - GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len); - ptr += 8; - GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr)); - ptr += 4; - while (ptr < end) { - tag = QT_UINT8 (ptr); - GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag); - ptr++; - len = get_size (ptr, &ptr); - GST_DEBUG_OBJECT (qtdemux, "len = %d", len); - - switch (tag) { - case 0x03: - GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr)); - GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2)); - ptr += 3; - break; - case 0x04: - object_type_id = QT_UINT8 (ptr); - GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id); - GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1)); - GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2)); - GST_DEBUG_OBJECT (qtdemux, "max bitrate %d", QT_UINT32 (ptr + 5)); - GST_DEBUG_OBJECT (qtdemux, "avg bitrate %d", QT_UINT32 (ptr + 9)); - ptr += 13; - break; - case 0x05: - GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len); - data_ptr = ptr; - data_len = len; - ptr += len; - break; - case 0x06: - GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr)); - ptr += 1; - break; - default: - GST_ERROR_OBJECT (qtdemux, "parse error"); - break; - } - } - - /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is - * in use, and should also be used to override some other parameters for some - * codecs. */ - switch (object_type_id) { - case 0x20: /* MPEG-4 */ - break; /* Nothing special needed here */ - case 0x21: /* H.264 */ - codec_name = "H.264 / AVC"; - caps = gst_caps_new_simple ("video/x-h264", NULL); - break; - case 0x40: /* AAC (any) */ - case 0x66: /* AAC Main */ - case 0x67: /* AAC LC */ - case 0x68: /* AAC SSR */ - /* Override channels and rate based on the codec_data, as it's often - * wrong. */ - if (data_ptr && data_len >= 2) { - guint channels, rateindex; - int rates[] = { 96000, 88200, 64000, 48000, 44100, 32000, - 24000, 22050, 16000, 12000, 11025, 8000 - }; - - channels = (data_ptr[1] & 0x7f) >> 3; - if (channels <= 7) { - stream->n_channels = channels; - } - - rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7); - if (rateindex < sizeof (rates) / sizeof (*rates)) { - stream->rate = rates[rateindex]; - } - } - break; - case 0x60: /* MPEG-2, various profiles */ - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - codec_name = "MPEG-2 video"; - - gst_caps_unref (stream->caps); - stream->caps = gst_caps_new_simple ("video/mpeg", - "mpegversion", G_TYPE_INT, 2, - "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); - break; - case 0x69: /* MP3 has two different values, accept either */ - case 0x6B: - /* change to mpeg1 layer 3 audio */ - gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3, - "mpegversion", G_TYPE_INT, 1, NULL); - codec_name = "MPEG-1 layer 3"; - break; - case 0x6A: /* MPEG-1 */ - codec_name = "MPEG-1 video"; - - gst_caps_unref (stream->caps); - stream->caps = gst_caps_new_simple ("video/mpeg", - "mpegversion", G_TYPE_INT, 1, - "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); - break; - case 0x6C: /* MJPEG */ - caps = gst_caps_new_simple ("image/jpeg", NULL); - codec_name = "Motion-JPEG"; - break; - case 0x6D: /* PNG */ - caps = gst_caps_new_simple ("image/png", NULL); - codec_name = "PNG still images"; - break; - case 0x6E: /* JPEG2000 */ - codec_name = "JPEG-2000"; - caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL); - break; - case 0xA4: /* Dirac */ - codec_name = "Dirac"; - caps = gst_caps_new_simple ("video/x-dirac", NULL); - break; - case 0xA5: /* AC3 */ - codec_name = "AC-3 audio"; - caps = gst_caps_new_simple ("audio/x-ac3", NULL); - break; - case 0xE1: /* QCELP */ - /* QCELP, the codec_data is a riff tag (little endian) with - * more info (http://ftp.3gpp2.org/TSGC/Working/2003/2003-05-SanDiego/TSG-C-2003-05-San%20Diego/WG1/SWG12/C12-20030512-006%20=%20C12-20030217-015_Draft_Baseline%20Text%20of%20FFMS_R2.doc). */ - caps = gst_caps_new_simple ("audio/qcelp", NULL); - codec_name = "QCELP"; - break; - default: - break; - } - - /* If we have a replacement caps, then change our caps for this stream */ - if (caps) { - gst_caps_unref (stream->caps); - stream->caps = caps; - } - - if (codec_name && list) - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - GST_TAG_AUDIO_CODEC, codec_name, NULL); - - /* Add the codec_data attribute to caps, if we have it */ - if (data_ptr) { - GstBuffer *buffer; - - buffer = gst_buffer_new_and_alloc (data_len); - memcpy (GST_BUFFER_DATA (buffer), data_ptr, data_len); - - GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds"); - GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len); - - gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER, - buffer, NULL); - gst_buffer_unref (buffer); - } - -} - -#define _codec(name) \ - do { \ - if (codec_name) { \ - *codec_name = g_strdup (name); \ - } \ - } while (0) - -static GstCaps * -qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, - guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name) -{ - GstCaps *caps; - const GstStructure *s; - const gchar *name; - - switch (fourcc) { - case GST_MAKE_FOURCC ('p', 'n', 'g', ' '): - _codec ("PNG still images"); - caps = gst_caps_new_simple ("image/png", NULL); - break; - case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'): - _codec ("JPEG still images"); - caps = gst_caps_new_simple ("image/jpeg", NULL); - break; - case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'): - case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'): - case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'): - _codec ("Motion-JPEG"); - caps = gst_caps_new_simple ("image/jpeg", NULL); - break; - case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'): - _codec ("Motion-JPEG format B"); - caps = gst_caps_new_simple ("video/x-mjpeg-b", NULL); - break; - case GST_MAKE_FOURCC ('m', 'j', 'p', '2'): - _codec ("JPEG-2000"); - /* override to what it should be according to spec, avoid palette_data */ - stream->bits_per_sample = 24; - caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL); - break; - case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'): - _codec ("Sorensen video v.3"); - caps = gst_caps_new_simple ("video/x-svq", - "svqversion", G_TYPE_INT, 3, NULL); - break; - case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'): - case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'): - _codec ("Sorensen video v.1"); - caps = gst_caps_new_simple ("video/x-svq", - "svqversion", G_TYPE_INT, 1, NULL); - break; - case GST_MAKE_FOURCC ('r', 'a', 'w', ' '): - { - guint16 bps; - - _codec ("Raw RGB video"); - bps = QT_UINT16 (stsd_data + 98); - /* set common stuff */ - caps = gst_caps_new_simple ("video/x-raw-rgb", - "endianness", G_TYPE_INT, G_BYTE_ORDER, "depth", G_TYPE_INT, bps, - NULL); - - switch (bps) { - case 15: - gst_caps_set_simple (caps, - "bpp", G_TYPE_INT, 16, - "endianness", G_TYPE_INT, G_BIG_ENDIAN, - "red_mask", G_TYPE_INT, 0x7c00, - "green_mask", G_TYPE_INT, 0x03e0, - "blue_mask", G_TYPE_INT, 0x001f, NULL); - break; - case 16: - gst_caps_set_simple (caps, - "bpp", G_TYPE_INT, 16, - "endianness", G_TYPE_INT, G_BIG_ENDIAN, - "red_mask", G_TYPE_INT, 0xf800, - "green_mask", G_TYPE_INT, 0x07e0, - "blue_mask", G_TYPE_INT, 0x001f, NULL); - break; - case 24: - gst_caps_set_simple (caps, - "bpp", G_TYPE_INT, 24, - "endianness", G_TYPE_INT, G_BIG_ENDIAN, - "red_mask", G_TYPE_INT, 0xff0000, - "green_mask", G_TYPE_INT, 0x00ff00, - "blue_mask", G_TYPE_INT, 0x0000ff, NULL); - break; - case 32: - gst_caps_set_simple (caps, - "bpp", G_TYPE_INT, 32, - "endianness", G_TYPE_INT, G_BIG_ENDIAN, - "alpha_mask", G_TYPE_INT, 0xff000000, - "red_mask", G_TYPE_INT, 0x00ff0000, - "green_mask", G_TYPE_INT, 0x0000ff00, - "blue_mask", G_TYPE_INT, 0x000000ff, NULL); - break; - default: - /* unknown */ - break; - } - break; - } - case GST_MAKE_FOURCC ('y', 'v', '1', '2'): - _codec ("Raw planar YUV 4:2:0"); - caps = gst_caps_new_simple ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'), - NULL); - break; - case GST_MAKE_FOURCC ('y', 'u', 'v', '2'): - case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'): - _codec ("Raw packed YUV 4:2:2"); - caps = gst_caps_new_simple ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'), - NULL); - break; - case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'): - _codec ("Raw packed YUV 4:2:0"); - caps = gst_caps_new_simple ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'), - NULL); - break; - case GST_MAKE_FOURCC ('v', '2', '1', '0'): - _codec ("Raw packed YUV 10-bit 4:2:2"); - caps = gst_caps_new_simple ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('v', '2', '1', '0'), - NULL); - break; - case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'): - case GST_MAKE_FOURCC ('m', 'p', 'g', '1'): - _codec ("MPEG-1 video"); - caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1, - "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); - break; - case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): // HDV 720p30 - case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): // HDV 1080i60 - case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): // HDV 1080i50 - case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): // HDV 720p25 - case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): // HDV 1080i60 - case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): // MPEG2 IMX NTSC 525/60 50mb/s produced by FCP - case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): // MPEG2 IMX PAL 625/60 50mb/s produced by FCP - case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): // MPEG2 IMX NTSC 525/60 40mb/s produced by FCP - case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): // MPEG2 IMX PAL 625/60 40mb/s produced by FCP - case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): // MPEG2 IMX NTSC 525/60 30mb/s produced by FCP - case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): // MPEG2 IMX PAL 625/50 30mb/s produced by FCP - case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): // XDCAM HD 1080i60 - case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): // AVID IMX PAL - case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): // AVID IMX PAL - _codec ("MPEG-2 video"); - caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2, - "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); - break; - case GST_MAKE_FOURCC ('g', 'i', 'f', ' '): - _codec ("GIF still images"); - caps = gst_caps_new_simple ("image/gif", NULL); - break; - case GST_MAKE_FOURCC ('h', '2', '6', '3'): - case GST_MAKE_FOURCC ('H', '2', '6', '3'): - case GST_MAKE_FOURCC ('s', '2', '6', '3'): - case GST_MAKE_FOURCC ('U', '2', '6', '3'): - _codec ("H.263"); - /* ffmpeg uses the height/width props, don't know why */ - caps = gst_caps_new_simple ("video/x-h263", NULL); - break; - case GST_MAKE_FOURCC ('m', 'p', '4', 'v'): - _codec ("MPEG-4 video"); - caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4, - "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); - break; - case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'): - case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'): - _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */ - caps = gst_caps_new_simple ("video/x-msmpeg", - "msmpegversion", G_TYPE_INT, 43, NULL); - break; - case GST_MAKE_FOURCC ('3', 'I', 'V', '1'): - case GST_MAKE_FOURCC ('3', 'I', 'V', '2'): - _codec ("3ivX video"); - caps = gst_caps_new_simple ("video/x-3ivx", NULL); - break; - case GST_MAKE_FOURCC ('D', 'I', 'V', '3'): - _codec ("DivX 3"); - caps = gst_caps_new_simple ("video/x-divx", - "divxversion", G_TYPE_INT, 3, NULL); - break; - case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'): - case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'): - _codec ("DivX 4"); - caps = gst_caps_new_simple ("video/x-divx", - "divxversion", G_TYPE_INT, 4, NULL); - break; - case GST_MAKE_FOURCC ('D', 'X', '5', '0'): - _codec ("DivX 5"); - caps = gst_caps_new_simple ("video/x-divx", - "divxversion", G_TYPE_INT, 5, NULL); - break; - case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'): - case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'): - _codec ("XVID MPEG-4"); - caps = gst_caps_new_simple ("video/x-xvid", NULL); - break; - - case GST_MAKE_FOURCC ('F', 'M', 'P', '4'): - case GST_MAKE_FOURCC ('U', 'M', 'P', '4'): - caps = gst_caps_new_simple ("video/mpeg", - "mpegversion", G_TYPE_INT, 4, NULL); - if (codec_name) - *codec_name = g_strdup ("FFmpeg MPEG-4"); - break; - - case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'): - _codec ("Cinepak"); - caps = gst_caps_new_simple ("video/x-cinepak", NULL); - break; - case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'): - _codec ("Apple QuickDraw"); - caps = gst_caps_new_simple ("video/x-qdrw", NULL); - break; - case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'): - _codec ("Apple video"); - caps = gst_caps_new_simple ("video/x-apple-video", NULL); - break; - case GST_MAKE_FOURCC ('a', 'v', 'c', '1'): - _codec ("H.264 / AVC"); - caps = gst_caps_new_simple ("video/x-h264", NULL); - break; - case GST_MAKE_FOURCC ('r', 'l', 'e', ' '): - _codec ("Run-length encoding"); - caps = gst_caps_new_simple ("video/x-rle", - "layout", G_TYPE_STRING, "quicktime", NULL); - break; - case GST_MAKE_FOURCC ('i', 'v', '3', '2'): - _codec ("Indeo Video 3"); - caps = gst_caps_new_simple ("video/x-indeo", - "indeoversion", G_TYPE_INT, 3, NULL); - break; - case GST_MAKE_FOURCC ('I', 'V', '4', '1'): - case GST_MAKE_FOURCC ('i', 'v', '4', '1'): - _codec ("Intel Video 4"); - caps = gst_caps_new_simple ("video/x-indeo", - "indeoversion", G_TYPE_INT, 4, NULL); - break; - case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'): - case GST_MAKE_FOURCC ('d', 'v', 'c', ' '): - case GST_MAKE_FOURCC ('d', 'v', 's', 'd'): - case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'): - case GST_MAKE_FOURCC ('d', 'v', 'c', 's'): - case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'): - case GST_MAKE_FOURCC ('d', 'v', '2', '5'): - case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'): - _codec ("DV Video"); - caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25, - "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); - break; - case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): //DVCPRO50 NTSC - case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): //DVCPRO50 PAL - _codec ("DVCPro50 Video"); - caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50, - "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); - break; - case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): //DVCPRO HD 50i produced by FCP - case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): //DVCPRO HD 60i produced by FCP - _codec ("DVCProHD Video"); - caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100, - "systemstream", G_TYPE_BOOLEAN, FALSE, NULL); - break; - case GST_MAKE_FOURCC ('s', 'm', 'c', ' '): - _codec ("Apple Graphics (SMC)"); - caps = gst_caps_new_simple ("video/x-smc", NULL); - break; - case GST_MAKE_FOURCC ('V', 'P', '3', '1'): - _codec ("VP3"); - caps = gst_caps_new_simple ("video/x-vp3", NULL); - break; - case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'): - _codec ("Theora"); - caps = gst_caps_new_simple ("video/x-theora", NULL); - /* theora uses one byte of padding in the data stream because it does not - * allow 0 sized packets while theora does */ - stream->padding = 1; - break; - case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'): - _codec ("Dirac"); - caps = gst_caps_new_simple ("video/x-dirac", NULL); - break; - case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'): - _codec ("TIFF still images"); - caps = gst_caps_new_simple ("image/tiff", NULL); - break; - case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'): - _codec ("Apple Intermediate Codec"); - caps = gst_caps_from_string ("video/x-apple-intermediate-codec"); - break; - case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'): - _codec ("AVID DNxHD"); - caps = gst_caps_from_string ("video/x-dnxhd"); - break; - case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'): - default: - { - char *s; - - s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (fourcc)); - caps = gst_caps_new_simple (s, NULL); - break; - } - } - - /* enable clipping for raw video streams */ - s = gst_caps_get_structure (caps, 0); - name = gst_structure_get_name (s); - if (g_str_has_prefix (name, "video/x-raw-")) { - stream->need_clip = TRUE; - } - return caps; -} - -static GstCaps * -qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, - guint32 fourcc, const guint8 * data, int len, gchar ** codec_name) -{ - GstCaps *caps; - const GstStructure *s; - const gchar *name; - gint endian = 0; - - GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc); - - switch (fourcc) { - case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'): - case GST_MAKE_FOURCC ('r', 'a', 'w', ' '): - _codec ("Raw 8-bit PCM audio"); - caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 8, - "depth", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL); - break; - case GST_MAKE_FOURCC ('t', 'w', 'o', 's'): - endian = G_BIG_ENDIAN; - /* fall-through */ - case GST_MAKE_FOURCC ('s', 'o', 'w', 't'): - { - gchar *str; - gint depth; - - if (!endian) - endian = G_LITTLE_ENDIAN; - - depth = stream->bytes_per_packet * 8; - str = g_strdup_printf ("Raw %d-bit PCM audio", depth); - _codec (str); - g_free (str); - caps = gst_caps_new_simple ("audio/x-raw-int", - "width", G_TYPE_INT, depth, "depth", G_TYPE_INT, depth, - "endianness", G_TYPE_INT, endian, - "signed", G_TYPE_BOOLEAN, TRUE, NULL); - break; - } - case GST_MAKE_FOURCC ('f', 'l', '6', '4'): - _codec ("Raw 64-bit floating-point audio"); - caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 64, - "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL); - break; - case GST_MAKE_FOURCC ('f', 'l', '3', '2'): - _codec ("Raw 32-bit floating-point audio"); - caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 32, - "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL); - break; - case FOURCC_in24: - _codec ("Raw 24-bit PCM audio"); - /* we assume BIG ENDIAN, an enda box will tell us to change this to little - * endian later */ - caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 24, - "depth", G_TYPE_INT, 24, - "endianness", G_TYPE_INT, G_BIG_ENDIAN, - "signed", G_TYPE_BOOLEAN, TRUE, NULL); - break; - case GST_MAKE_FOURCC ('i', 'n', '3', '2'): - _codec ("Raw 32-bit PCM audio"); - caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 32, - "depth", G_TYPE_INT, 32, - "endianness", G_TYPE_INT, G_BIG_ENDIAN, - "signed", G_TYPE_BOOLEAN, TRUE, NULL); - break; - case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'): - _codec ("Mu-law audio"); - caps = gst_caps_new_simple ("audio/x-mulaw", NULL); - break; - case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'): - _codec ("A-law audio"); - caps = gst_caps_new_simple ("audio/x-alaw", NULL); - break; - case 0x0200736d: - case 0x6d730002: - _codec ("Microsoft ADPCM"); - /* Microsoft ADPCM-ACM code 2 */ - caps = gst_caps_new_simple ("audio/x-adpcm", - "layout", G_TYPE_STRING, "microsoft", NULL); - break; - case 0x1100736d: - case 0x6d730011: - _codec ("IMA Loki SDL MJPEG ADPCM"); - /* Loki ADPCM, See #550288 for a file that only decodes - * with the smjpeg variant of the ADPCM decoder. */ - caps = gst_caps_new_simple ("audio/x-adpcm", - "layout", G_TYPE_STRING, "smjpeg", NULL); - break; - case 0x1700736d: - case 0x6d730017: - _codec ("DVI/Intel IMA ADPCM"); - /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */ - caps = gst_caps_new_simple ("audio/x-adpcm", - "layout", G_TYPE_STRING, "quicktime", NULL); - break; - case 0x5500736d: - case 0x6d730055: - /* MPEG layer 3, CBR only (pre QT4.1) */ - case GST_MAKE_FOURCC ('.', 'm', 'p', '3'): - _codec ("MPEG-1 layer 3"); - /* MPEG layer 3, CBR & VBR (QT4.1 and later) */ - caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3, - "mpegversion", G_TYPE_INT, 1, NULL); - break; - case 0x20736d: - case GST_MAKE_FOURCC ('a', 'c', '-', '3'): - _codec ("AC-3 audio"); - caps = gst_caps_new_simple ("audio/x-ac3", NULL); - stream->sampled = TRUE; - break; - case GST_MAKE_FOURCC ('M', 'A', 'C', '3'): - _codec ("MACE-3"); - caps = gst_caps_new_simple ("audio/x-mace", - "maceversion", G_TYPE_INT, 3, NULL); - break; - case GST_MAKE_FOURCC ('M', 'A', 'C', '6'): - _codec ("MACE-6"); - caps = gst_caps_new_simple ("audio/x-mace", - "maceversion", G_TYPE_INT, 6, NULL); - break; - case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'): - /* ogg/vorbis */ - caps = gst_caps_new_simple ("application/ogg", NULL); - break; - case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'): - _codec ("DV audio"); - caps = gst_caps_new_simple ("audio/x-dv", NULL); - break; - case GST_MAKE_FOURCC ('m', 'p', '4', 'a'): - _codec ("MPEG-4 AAC audio"); - caps = gst_caps_new_simple ("audio/mpeg", - "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE, NULL); - break; - case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'): - _codec ("QDesign Music"); - caps = gst_caps_new_simple ("audio/x-qdm", NULL); - break; - case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'): - _codec ("QDesign Music v.2"); - /* FIXME: QDesign music version 2 (no constant) */ - if (data) { - caps = gst_caps_new_simple ("audio/x-qdm2", - "framesize", G_TYPE_INT, QT_UINT32 (data + 52), - "bitrate", G_TYPE_INT, QT_UINT32 (data + 40), - "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL); - } else { - caps = gst_caps_new_simple ("audio/x-qdm2", NULL); - } - break; - case GST_MAKE_FOURCC ('a', 'g', 's', 'm'): - _codec ("GSM audio"); - caps = gst_caps_new_simple ("audio/x-gsm", NULL); - break; - case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'): - _codec ("AMR audio"); - caps = gst_caps_new_simple ("audio/AMR", NULL); - break; - case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'): - _codec ("AMR-WB audio"); - caps = gst_caps_new_simple ("audio/AMR-WB", NULL); - break; - case GST_MAKE_FOURCC ('i', 'm', 'a', '4'): - _codec ("Quicktime IMA ADPCM"); - caps = gst_caps_new_simple ("audio/x-adpcm", - "layout", G_TYPE_STRING, "quicktime", NULL); - break; - case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'): - _codec ("Apple lossless audio"); - caps = gst_caps_new_simple ("audio/x-alac", NULL); - break; - case GST_MAKE_FOURCC ('q', 't', 'v', 'r'): - /* ? */ - case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'): - /* QUALCOMM PureVoice */ - default: - { - char *s; - - s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (fourcc)); - caps = gst_caps_new_simple (s, NULL); - break; - } - } - - /* enable clipping for raw audio streams */ - s = gst_caps_get_structure (caps, 0); - name = gst_structure_get_name (s); - if (g_str_has_prefix (name, "audio/x-raw-")) { - stream->need_clip = TRUE; - } - return caps; -} - -static GstCaps * -qtdemux_subp_caps (GstQTDemux * qtdemux, QtDemuxStream * stream, - guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name) -{ - GstCaps *caps; - - GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc); - - switch (fourcc) { - case GST_MAKE_FOURCC ('m', 'p', '4', 's'): - _codec ("DVD subtitle"); - caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL); - break; - default: - { - char *s; - - s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (fourcc)); - caps = gst_caps_new_simple (s, NULL); - break; - } - } - return caps; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/qtdemux/qtdemux.h --- a/gst_plugins_good/gst/qtdemux/qtdemux.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -/* GStreamer - * 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. - */ - - -#ifndef __GST_QTDEMUX_H__ -#define __GST_QTDEMUX_H__ - -#include -#include - -G_BEGIN_DECLS - -GST_DEBUG_CATEGORY_EXTERN (qtdemux_debug); -#define GST_CAT_DEFAULT qtdemux_debug - -#define GST_TYPE_QTDEMUX \ - (gst_qtdemux_get_type()) -#define GST_QTDEMUX(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QTDEMUX,GstQTDemux)) -#define GST_QTDEMUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QTDEMUX,GstQTDemuxClass)) -#define GST_IS_QTDEMUX(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QTDEMUX)) -#define GST_IS_QTDEMUX_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QTDEMUX)) - -#define GST_QTDEMUX_CAST(obj) ((GstQTDemux *)(obj)) - -/* qtdemux produces these for atoms it cannot parse */ -#define GST_QT_DEMUX_PRIVATE_TAG "private-qt-tag" -#define GST_QT_DEMUX_CLASSIFICATION_TAG "classification" - -#define GST_QTDEMUX_MAX_STREAMS 8 - -typedef struct _GstQTDemux GstQTDemux; -typedef struct _GstQTDemuxClass GstQTDemuxClass; -typedef struct _QtDemuxStream QtDemuxStream; - -struct _GstQTDemux { - GstElement element; - - /* pads */ - GstPad *sinkpad; - - QtDemuxStream *streams[GST_QTDEMUX_MAX_STREAMS]; - gint n_streams; - gint n_video_streams; - gint n_audio_streams; - gint n_subp_streams; - - guint major_brand; - GNode *moov_node; - GNode *moov_node_compressed; - - guint32 timescale; - guint32 duration; - - gint state; - - gboolean pullbased; - - /* push based variables */ - guint neededbytes; - guint todrop; - GstAdapter *adapter; - GstBuffer *mdatbuffer; - - /* offset of the media data (i.e.: Size of header) */ - guint64 offset; - /* offset of the mdat atom */ - guint64 mdatoffset; - - GstTagList *tag_list; - - /* track stuff */ - guint64 last_ts; - - /* configured playback region */ - GstSegment segment; - gboolean segment_running; - GstEvent *pending_newsegment; -}; - -struct _GstQTDemuxClass { - GstElementClass parent_class; -}; - -#ifdef __SYMBIAN32__ -IMPORT_C -#endif -GType gst_qtdemux_get_type (void); - -G_END_DECLS - -#endif /* __GST_QTDEMUX_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/qtdemux/qtdemux_dump.c --- a/gst_plugins_good/gst/qtdemux/qtdemux_dump.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,432 +0,0 @@ -/* GStreamer - * 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. - */ - -#include "qtdemux_types.h" -#include "qtdemux_dump.h" - -void -qtdemux_dump_mvhd (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - GST_LOG ("%*s creation time: %u", depth, "", QT_UINT32 (buffer + 12)); - GST_LOG ("%*s modify time: %u", depth, "", QT_UINT32 (buffer + 16)); - GST_LOG ("%*s time scale: 1/%u sec", depth, "", QT_UINT32 (buffer + 20)); - GST_LOG ("%*s duration: %u", depth, "", QT_UINT32 (buffer + 24)); - GST_LOG ("%*s pref. rate: %g", depth, "", QT_FP32 (buffer + 28)); - GST_LOG ("%*s pref. volume: %g", depth, "", QT_FP16 (buffer + 32)); - GST_LOG ("%*s preview time: %u", depth, "", QT_UINT32 (buffer + 80)); - GST_LOG ("%*s preview dur.: %u", depth, "", QT_UINT32 (buffer + 84)); - GST_LOG ("%*s poster time: %u", depth, "", QT_UINT32 (buffer + 88)); - GST_LOG ("%*s select time: %u", depth, "", QT_UINT32 (buffer + 92)); - GST_LOG ("%*s select dur.: %u", depth, "", QT_UINT32 (buffer + 96)); - GST_LOG ("%*s current time: %u", depth, "", QT_UINT32 (buffer + 100)); - GST_LOG ("%*s next track ID: %d", depth, "", QT_UINT32 (buffer + 104)); -} - -void -qtdemux_dump_tkhd (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - GST_LOG ("%*s creation time: %u", depth, "", QT_UINT32 (buffer + 12)); - GST_LOG ("%*s modify time: %u", depth, "", QT_UINT32 (buffer + 16)); - GST_LOG ("%*s track ID: %u", depth, "", QT_UINT32 (buffer + 20)); - GST_LOG ("%*s duration: %u", depth, "", QT_UINT32 (buffer + 28)); - GST_LOG ("%*s layer: %u", depth, "", QT_UINT16 (buffer + 36)); - GST_LOG ("%*s alt group: %u", depth, "", QT_UINT16 (buffer + 38)); - GST_LOG ("%*s volume: %g", depth, "", QT_FP16 (buffer + 44)); - GST_LOG ("%*s track width: %g", depth, "", QT_FP32 (buffer + 84)); - GST_LOG ("%*s track height: %g", depth, "", QT_FP32 (buffer + 88)); - -} - -void -qtdemux_dump_elst (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - int i; - int n; - - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - GST_LOG ("%*s n entries: %u", depth, "", QT_UINT32 (buffer + 12)); - n = QT_UINT32 (buffer + 12); - for (i = 0; i < n; i++) { - GST_LOG ("%*s track dur: %u", depth, "", - QT_UINT32 (buffer + 16 + i * 12)); - GST_LOG ("%*s media time: %u", depth, "", - QT_UINT32 (buffer + 20 + i * 12)); - GST_LOG ("%*s media rate: %g", depth, "", - QT_FP32 (buffer + 24 + i * 12)); - } -} - -void -qtdemux_dump_mdhd (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - guint32 version; - guint64 duration, ctime, mtime; - guint32 time_scale; - guint16 language, quality; - - version = QT_UINT32 (buffer + 8); - GST_LOG ("%*s version/flags: %08x", depth, "", version); - - if (version == 0x01000000) { - ctime = QT_UINT64 (buffer + 12); - mtime = QT_UINT64 (buffer + 20); - time_scale = QT_UINT32 (buffer + 28); - duration = QT_UINT64 (buffer + 32); - language = QT_UINT16 (buffer + 40); - quality = QT_UINT16 (buffer + 42); - } else { - ctime = QT_UINT32 (buffer + 12); - mtime = QT_UINT32 (buffer + 16); - time_scale = QT_UINT32 (buffer + 20); - duration = QT_UINT32 (buffer + 24); - language = QT_UINT16 (buffer + 28); - quality = QT_UINT16 (buffer + 30); - } - - GST_LOG ("%*s creation time: %" G_GUINT64_FORMAT, depth, "", ctime); - GST_LOG ("%*s modify time: %" G_GUINT64_FORMAT, depth, "", mtime); - GST_LOG ("%*s time scale: 1/%u sec", depth, "", time_scale); - GST_LOG ("%*s duration: %" G_GUINT64_FORMAT, depth, "", duration); - GST_LOG ("%*s language: %u", depth, "", language); - GST_LOG ("%*s quality: %u", depth, "", quality); -} - -void -qtdemux_dump_hdlr (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - GST_LOG ("%*s type: %" GST_FOURCC_FORMAT, depth, "", - GST_FOURCC_ARGS (QT_FOURCC (buffer + 12))); - GST_LOG ("%*s subtype: %" GST_FOURCC_FORMAT, depth, "", - GST_FOURCC_ARGS (QT_FOURCC (buffer + 16))); - GST_LOG ("%*s manufacturer: %" GST_FOURCC_FORMAT, depth, "", - GST_FOURCC_ARGS (QT_FOURCC (buffer + 20))); - GST_LOG ("%*s flags: %08x", depth, "", QT_UINT32 (buffer + 24)); - GST_LOG ("%*s flags mask: %08x", depth, "", QT_UINT32 (buffer + 28)); - GST_LOG ("%*s name: %*s", depth, "", - QT_UINT8 (buffer + 32), (char *) (buffer + 33)); - -} - -void -qtdemux_dump_vmhd (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - GST_LOG ("%*s mode/color: %08x", depth, "", QT_UINT32 (buffer + 16)); -} - -void -qtdemux_dump_dref (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - int n; - int i; - int offset; - - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - GST_LOG ("%*s n entries: %u", depth, "", QT_UINT32 (buffer + 12)); - n = QT_UINT32 (buffer + 12); - offset = 16; - for (i = 0; i < n; i++) { - GST_LOG ("%*s size: %u", depth, "", - QT_UINT32 (buffer + offset)); - GST_LOG ("%*s type: %" GST_FOURCC_FORMAT, depth, "", - GST_FOURCC_ARGS (QT_FOURCC (buffer + offset + 4))); - offset += QT_UINT32 (buffer + offset); - } -} - -void -qtdemux_dump_stsd (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - int i; - int n; - int offset; - - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - GST_LOG ("%*s n entries: %d", depth, "", QT_UINT32 (buffer + 12)); - n = QT_UINT32 (buffer + 12); - offset = 16; - for (i = 0; i < n; i++) { - GST_LOG ("%*s size: %u", depth, "", - QT_UINT32 (buffer + offset)); - GST_LOG ("%*s type: %" GST_FOURCC_FORMAT, depth, "", - GST_FOURCC_ARGS (QT_FOURCC (buffer + offset + 4))); - GST_LOG ("%*s data reference:%d", depth, "", - QT_UINT16 (buffer + offset + 14)); - - GST_LOG ("%*s version/rev.: %08x", depth, "", - QT_UINT32 (buffer + offset + 16)); - GST_LOG ("%*s vendor: %" GST_FOURCC_FORMAT, depth, "", - GST_FOURCC_ARGS (QT_FOURCC (buffer + offset + 20))); - GST_LOG ("%*s temporal qual: %u", depth, "", - QT_UINT32 (buffer + offset + 24)); - GST_LOG ("%*s spatial qual: %u", depth, "", - QT_UINT32 (buffer + offset + 28)); - GST_LOG ("%*s width: %u", depth, "", - QT_UINT16 (buffer + offset + 32)); - GST_LOG ("%*s height: %u", depth, "", - QT_UINT16 (buffer + offset + 34)); - GST_LOG ("%*s horiz. resol: %g", depth, "", - QT_FP32 (buffer + offset + 36)); - GST_LOG ("%*s vert. resol.: %g", depth, "", - QT_FP32 (buffer + offset + 40)); - GST_LOG ("%*s data size: %u", depth, "", - QT_UINT32 (buffer + offset + 44)); - GST_LOG ("%*s frame count: %u", depth, "", - QT_UINT16 (buffer + offset + 48)); - GST_LOG ("%*s compressor: %d %d %d", depth, "", - QT_UINT8 (buffer + offset + 49), - QT_UINT8 (buffer + offset + 50), QT_UINT8 (buffer + offset + 51)); - //(char *) (buffer + offset + 51)); - GST_LOG ("%*s depth: %u", depth, "", - QT_UINT16 (buffer + offset + 82)); - GST_LOG ("%*s color table ID:%u", depth, "", - QT_UINT16 (buffer + offset + 84)); - - offset += QT_UINT32 (buffer + offset); - } -} - -void -qtdemux_dump_stts (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - int i; - int n; - int offset; - - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - GST_LOG ("%*s n entries: %d", depth, "", QT_UINT32 (buffer + 12)); - n = QT_UINT32 (buffer + 12); - offset = 16; - for (i = 0; i < n; i++) { - GST_LOG ("%*s count: %u", depth, "", - QT_UINT32 (buffer + offset)); - GST_LOG ("%*s duration: %u", depth, "", - QT_UINT32 (buffer + offset + 4)); - - offset += 8; - } -} - -void -qtdemux_dump_stps (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - int i; - int n; - int offset; - - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - GST_LOG ("%*s n entries: %d", depth, "", QT_UINT32 (buffer + 12)); - n = QT_UINT32 (buffer + 12); - offset = 16; - for (i = 0; i < n; i++) { - GST_LOG ("%*s sample: %u", depth, "", - QT_UINT32 (buffer + offset)); - - offset += 4; - } -} - -void -qtdemux_dump_stss (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - int i; - int n; - int offset; - - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - GST_LOG ("%*s n entries: %d", depth, "", QT_UINT32 (buffer + 12)); - n = QT_UINT32 (buffer + 12); - offset = 16; - for (i = 0; i < n; i++) { - GST_LOG ("%*s sample: %u", depth, "", - QT_UINT32 (buffer + offset)); - - offset += 4; - } -} - -void -qtdemux_dump_stsc (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - int i; - int n; - int offset; - - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - GST_LOG ("%*s n entries: %d", depth, "", QT_UINT32 (buffer + 12)); - n = QT_UINT32 (buffer + 12); - offset = 16; - for (i = 0; i < n; i++) { - GST_LOG ("%*s first chunk: %u", depth, "", - QT_UINT32 (buffer + offset)); - GST_LOG ("%*s sample per ch: %u", depth, "", - QT_UINT32 (buffer + offset + 4)); - GST_LOG ("%*s sample desc id:%08x", depth, "", - QT_UINT32 (buffer + offset + 8)); - - offset += 12; - } -} - -void -qtdemux_dump_stsz (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - //int i; - int n; - int offset; - int sample_size; - - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - sample_size = QT_UINT32 (buffer + 12); - GST_LOG ("%*s sample size: %d", depth, "", sample_size); - if (sample_size == 0) { - GST_LOG ("%*s n entries: %d", depth, "", QT_UINT32 (buffer + 16)); - n = QT_UINT32 (buffer + 16); - offset = 20; -#if 0 - for (i = 0; i < n; i++) { - GST_LOG ("%*s sample size: %u", depth, "", - QT_UINT32 (buffer + offset)); - - offset += 4; - } -#endif - } -} - -void -qtdemux_dump_stco (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - int i; - int n; - int offset; - - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - n = QT_UINT32 (buffer + 12); - GST_LOG ("%*s n entries: %d", depth, "", n); - offset = 16; - for (i = 0; i < n; i++) { - GST_LOG ("%*s chunk offset: %d", depth, "", - QT_UINT32 (buffer + offset)); - - offset += 4; - } -} - -void -qtdemux_dump_ctts (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - int i; - int n; - int offset; - - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - n = QT_UINT32 (buffer + 12); - GST_LOG ("%*s n entries: %d", depth, "", n); - offset = 16; - for (i = 0; i < n; i++) { - GST_LOG ("%*s sample count :%8d offset: %8d", - depth, "", QT_UINT32 (buffer + offset), - QT_UINT32 (buffer + offset + 4)); - - offset += 8; - } -} - -void -qtdemux_dump_co64 (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - //int i; - int n; - int offset; - - GST_LOG ("%*s version/flags: %08x", depth, "", QT_UINT32 (buffer + 8)); - GST_LOG ("%*s n entries: %d", depth, "", QT_UINT32 (buffer + 12)); - n = QT_UINT32 (buffer + 12); - offset = 16; -#if 0 - for (i = 0; i < n; i++) { - GST_LOG ("%*s chunk offset: %" G_GUINT64_FORMAT, depth, "", - QTDEMUX_GUINT64_GET (buffer + offset)); - - offset += 8; - } -#endif -} - -void -qtdemux_dump_dcom (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - GST_LOG ("%*s compression type: %" GST_FOURCC_FORMAT, depth, "", - GST_FOURCC_ARGS (QT_FOURCC (buffer + 8))); -} - -void -qtdemux_dump_cmvd (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - GST_LOG ("%*s length: %d", depth, "", QT_UINT32 (buffer + 8)); -} - -void -qtdemux_dump_unknown (GstQTDemux * qtdemux, guint8 * buffer, int depth) -{ - int len; - - GST_LOG ("%*s length: %d", depth, "", QT_UINT32 (buffer + 0)); - - len = QT_UINT32 (buffer + 0); - GST_MEMDUMP_OBJECT (qtdemux, "unknown atom data", buffer, len); -} - -static gboolean -qtdemux_node_dump_foreach (GNode * node, gpointer qtdemux) -{ - guint8 *buffer = (guint8 *) node->data; - guint32 node_length; - guint32 fourcc; - const QtNodeType *type; - int depth; - - node_length = GST_READ_UINT32_BE (buffer); - fourcc = GST_READ_UINT32_LE (buffer + 4); - - type = qtdemux_type_get (fourcc); - - depth = (g_node_depth (node) - 1) * 2; - GST_LOG ("%*s'%" GST_FOURCC_FORMAT "', [%d], %s", - depth, "", GST_FOURCC_ARGS (fourcc), node_length, type->name); - - if (type->dump) - type->dump (GST_QTDEMUX_CAST (qtdemux), buffer, depth); - - return FALSE; -} - -void -qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node) -{ - if (__gst_debug_min < GST_LEVEL_LOG) - return; - - g_node_traverse (qtdemux->moov_node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, - qtdemux_node_dump_foreach, qtdemux); -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/qtdemux/qtdemux_dump.h --- a/gst_plugins_good/gst/qtdemux/qtdemux_dump.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* GStreamer - * 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. - */ - -#ifndef __GST_QTDEMUX_DUMP_H__ -#define __GST_QTDEMUX_DUMP_H__ - -#include -#include - -G_BEGIN_DECLS - -void qtdemux_dump_mvhd (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_tkhd (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_elst (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_mdhd (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_hdlr (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_vmhd (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_dref (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_stsd (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_stts (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_stss (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_stps (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_stsc (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_stsz (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_stco (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_co64 (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_dcom (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_cmvd (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_ctts (GstQTDemux * qtdemux, guint8 * buffer, int depth); -void qtdemux_dump_unknown (GstQTDemux * qtdemux, guint8 * buffer, int depth); - -void qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node); - -G_END_DECLS - -#endif /* __GST_QTDEMUX_DUMP_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/qtdemux/qtdemux_fourcc.h --- a/gst_plugins_good/gst/qtdemux/qtdemux_fourcc.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,178 +0,0 @@ -/* GStreamer - * 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. - */ - -#ifndef __GST_QTDEMUX_FOURCC_H__ -#define __GST_QTDEMUX_FOURCC_H__ - -#include - -G_BEGIN_DECLS - -#define FOURCC_ftyp GST_MAKE_FOURCC('f','t','y','p') -#define FOURCC_qt__ GST_MAKE_FOURCC('q','t',' ',' ') -#define FOURCC_moov GST_MAKE_FOURCC('m','o','o','v') -#define FOURCC_mvhd GST_MAKE_FOURCC('m','v','h','d') -#define FOURCC_clip GST_MAKE_FOURCC('c','l','i','p') -#define FOURCC_trak GST_MAKE_FOURCC('t','r','a','k') -#define FOURCC_udta GST_MAKE_FOURCC('u','d','t','a') -#define FOURCC_ctab GST_MAKE_FOURCC('c','t','a','b') -#define FOURCC_tkhd GST_MAKE_FOURCC('t','k','h','d') -#define FOURCC_crgn GST_MAKE_FOURCC('c','r','g','n') -#define FOURCC_matt GST_MAKE_FOURCC('m','a','t','t') -#define FOURCC_kmat GST_MAKE_FOURCC('k','m','a','t') -#define FOURCC_edts GST_MAKE_FOURCC('e','d','t','s') -#define FOURCC_elst GST_MAKE_FOURCC('e','l','s','t') -#define FOURCC_load GST_MAKE_FOURCC('l','o','a','d') -#define FOURCC_tref GST_MAKE_FOURCC('t','r','e','f') -#define FOURCC_imap GST_MAKE_FOURCC('i','m','a','p') -#define FOURCC___in GST_MAKE_FOURCC(' ',' ','i','n') -#define FOURCC___ty GST_MAKE_FOURCC(' ',' ','t','y') -#define FOURCC_mdia GST_MAKE_FOURCC('m','d','i','a') -#define FOURCC_mdhd GST_MAKE_FOURCC('m','d','h','d') -#define FOURCC_hdlr GST_MAKE_FOURCC('h','d','l','r') -#define FOURCC_minf GST_MAKE_FOURCC('m','i','n','f') -#define FOURCC_vmhd GST_MAKE_FOURCC('v','m','h','d') -#define FOURCC_smhd GST_MAKE_FOURCC('s','m','h','d') -#define FOURCC_gmhd GST_MAKE_FOURCC('g','m','h','d') -#define FOURCC_gmin GST_MAKE_FOURCC('g','m','i','n') -#define FOURCC_dinf GST_MAKE_FOURCC('d','i','n','f') -#define FOURCC_dref GST_MAKE_FOURCC('d','r','e','f') -#define FOURCC_stbl GST_MAKE_FOURCC('s','t','b','l') -#define FOURCC_stsd GST_MAKE_FOURCC('s','t','s','d') -#define FOURCC_stts GST_MAKE_FOURCC('s','t','t','s') -#define FOURCC_stss GST_MAKE_FOURCC('s','t','s','s') -#define FOURCC_stps GST_MAKE_FOURCC('s','t','p','s') -#define FOURCC_stsc GST_MAKE_FOURCC('s','t','s','c') -#define FOURCC_stsz GST_MAKE_FOURCC('s','t','s','z') -#define FOURCC_stco GST_MAKE_FOURCC('s','t','c','o') -#define FOURCC_vide GST_MAKE_FOURCC('v','i','d','e') -#define FOURCC_soun GST_MAKE_FOURCC('s','o','u','n') -#define FOURCC_subp GST_MAKE_FOURCC('s','u','b','p') -#define FOURCC_strm GST_MAKE_FOURCC('s','t','r','m') -#define FOURCC_rtsp GST_MAKE_FOURCC('r','t','s','p') -#define FOURCC_co64 GST_MAKE_FOURCC('c','o','6','4') -#define FOURCC_cmov GST_MAKE_FOURCC('c','m','o','v') -#define FOURCC_dcom GST_MAKE_FOURCC('d','c','o','m') -#define FOURCC_cmvd GST_MAKE_FOURCC('c','m','v','d') -#define FOURCC_hint GST_MAKE_FOURCC('h','i','n','t') -#define FOURCC_mp4a GST_MAKE_FOURCC('m','p','4','a') -#define FOURCC_mp4v GST_MAKE_FOURCC('m','p','4','v') -#define FOURCC_wave GST_MAKE_FOURCC('w','a','v','e') -#define FOURCC_appl GST_MAKE_FOURCC('a','p','p','l') -#define FOURCC_esds GST_MAKE_FOURCC('e','s','d','s') -#define FOURCC_pasp GST_MAKE_FOURCC('p','a','s','p') -#define FOURCC_hnti GST_MAKE_FOURCC('h','n','t','i') -#define FOURCC_rtp_ GST_MAKE_FOURCC('r','t','p',' ') -#define FOURCC_sdp_ GST_MAKE_FOURCC('s','d','p',' ') -#define FOURCC_meta GST_MAKE_FOURCC('m','e','t','a') -#define FOURCC_ilst GST_MAKE_FOURCC('i','l','s','t') -#define FOURCC__nam GST_MAKE_FOURCC(0xa9,'n','a','m') -#define FOURCC__cmt GST_MAKE_FOURCC(0xa9,'c','m','t') -#define FOURCC__des GST_MAKE_FOURCC(0xa9,'d','e','s') -#define FOURCC__cpy GST_MAKE_FOURCC(0xa9,'c','p','y') -#define FOURCC__ART GST_MAKE_FOURCC(0xa9,'A','R','T') -#define FOURCC__wrt GST_MAKE_FOURCC(0xa9,'w','r','t') -#define FOURCC__grp GST_MAKE_FOURCC(0xa9,'g','r','p') -#define FOURCC__alb GST_MAKE_FOURCC(0xa9,'a','l','b') -#define FOURCC__day GST_MAKE_FOURCC(0xa9,'d','a','y') -#define FOURCC__req GST_MAKE_FOURCC(0xa9,'r','e','q') -#define FOURCC__enc GST_MAKE_FOURCC(0xa9,'e','n','c') -#define FOURCC__inf GST_MAKE_FOURCC(0xa9,'i','n','f') -#define FOURCC_cprt GST_MAKE_FOURCC('c','p','r','t') -#define FOURCC_gnre GST_MAKE_FOURCC('g','n','r','e') -#define FOURCC_disc GST_MAKE_FOURCC('d','i','s','c') -#define FOURCC_disk GST_MAKE_FOURCC('d','i','s','k') -#define FOURCC_trkn GST_MAKE_FOURCC('t','r','k','n') -#define FOURCC_cpil GST_MAKE_FOURCC('c','p','i','l') -#define FOURCC_tmpo GST_MAKE_FOURCC('t','m','p','o') -#define FOURCC_covr GST_MAKE_FOURCC('c','o','v','r') -#define FOURCC__too GST_MAKE_FOURCC(0xa9,'t','o','o') -#define FOURCC_____ GST_MAKE_FOURCC('-','-','-','-') -#define FOURCC_free GST_MAKE_FOURCC('f','r','e','e') -#define FOURCC_data GST_MAKE_FOURCC('d','a','t','a') -#define FOURCC_SVQ3 GST_MAKE_FOURCC('S','V','Q','3') -#define FOURCC_rmra GST_MAKE_FOURCC('r','m','r','a') -#define FOURCC_rmda GST_MAKE_FOURCC('r','m','d','a') -#define FOURCC_rdrf GST_MAKE_FOURCC('r','d','r','f') -#define FOURCC__gen GST_MAKE_FOURCC(0xa9, 'g', 'e', 'n') -#define FOURCC_rmdr GST_MAKE_FOURCC('r','m','d','r') -#define FOURCC_rmvc GST_MAKE_FOURCC('r','m','v','c') -#define FOURCC_qtim GST_MAKE_FOURCC('q','t','i','m') -#define FOURCC_drms GST_MAKE_FOURCC('d','r','m','s') -#define FOURCC_avc1 GST_MAKE_FOURCC('a','v','c','1') -#define FOURCC_avcC GST_MAKE_FOURCC('a','v','c','C') -#define FOURCC_VP31 GST_MAKE_FOURCC('V','P','3','1') -#define FOURCC_rle_ GST_MAKE_FOURCC('r','l','e',' ') -#define FOURCC_MAC6 GST_MAKE_FOURCC('M','A','C','6') -#define FOURCC_MAC3 GST_MAKE_FOURCC('M','A','C','3') -#define FOURCC_ima4 GST_MAKE_FOURCC('i','m','a','4') -#define FOURCC_ulaw GST_MAKE_FOURCC('u','l','a','w') -#define FOURCC_alaw GST_MAKE_FOURCC('a','l','a','w') -#define FOURCC_twos GST_MAKE_FOURCC('t','w','o','s') -#define FOURCC_sowt GST_MAKE_FOURCC('s','o','w','t') -#define FOURCC_raw_ GST_MAKE_FOURCC('r','a','w',' ') -#define FOURCC_in24 GST_MAKE_FOURCC('i','n','2','4') -#define FOURCC_enda GST_MAKE_FOURCC('e','n','d','a') -#define FOURCC_QDM2 GST_MAKE_FOURCC('Q','D','M','2') -#define FOURCC_alac GST_MAKE_FOURCC('a','l','a','c') -#define FOURCC_samr GST_MAKE_FOURCC('s','a','m','r') -#define FOURCC_sawb GST_MAKE_FOURCC('s','a','w','b') -#define FOURCC_mdat GST_MAKE_FOURCC('m','d','a','t') -#define FOURCC_wide GST_MAKE_FOURCC('w','i','d','e') -#define FOURCC_PICT GST_MAKE_FOURCC('P','I','C','T') -#define FOURCC_pnot GST_MAKE_FOURCC('p','n','o','t') -#define FOURCC_zlib GST_MAKE_FOURCC('z','l','i','b') -#define FOURCC_alis GST_MAKE_FOURCC('a','l','i','s') -#define FOURCC_url_ GST_MAKE_FOURCC('u','r','l',' ') -#define FOURCC_frma GST_MAKE_FOURCC('f','r','m','a') -#define FOURCC_ctts GST_MAKE_FOURCC('c','t','t','s') -#define FOURCC_keyw GST_MAKE_FOURCC('k','e','y','w') -#define FOURCC_kywd GST_MAKE_FOURCC('k','y','w','d') -#define FOURCC_agsm GST_MAKE_FOURCC('a','g','s','m') - -/* 3gpp asset meta data fourcc */ -#define FOURCC_titl GST_MAKE_FOURCC('t','i','t','l') -#define FOURCC_dscp GST_MAKE_FOURCC('d','s','c','p') -#define FOURCC_perf GST_MAKE_FOURCC('p','e','r','f') -#define FOURCC_auth GST_MAKE_FOURCC('a','u','t','h') -#define FOURCC_rtng GST_MAKE_FOURCC('r','t','n','g') -#define FOURCC_clsf GST_MAKE_FOURCC('c','l','s','f') -#define FOURCC_loci GST_MAKE_FOURCC('l','o','c','i') -#define FOURCC_albm GST_MAKE_FOURCC('a','l','b','m') -#define FOURCC_yrrc GST_MAKE_FOURCC('y','r','r','c') - -/* ISO Motion JPEG 2000 fourcc */ -#define FOURCC_mjp2 GST_MAKE_FOURCC('m','j','p','2') -#define FOURCC_jp2h GST_MAKE_FOURCC('j','p','2','h') -#define FOURCC_colr GST_MAKE_FOURCC('c','o','l','r') -#define FOURCC_fiel GST_MAKE_FOURCC('f','i','e','l') -#define FOURCC_jp2x GST_MAKE_FOURCC('j','p','2','x') -/* some buggy hardware's notion of mdhd */ -#define FOURCC_mhdr GST_MAKE_FOURCC('m','h','d','r') - -/* Xiph fourcc */ -#define FOURCC_XiTh GST_MAKE_FOURCC('X','i','T','h') -#define FOURCC_XdxT GST_MAKE_FOURCC('X','d','x','T') -#define FOURCC_tCtH GST_MAKE_FOURCC('t','C','t','H') -#define FOURCC_tCt_ GST_MAKE_FOURCC('t','C','t','#') -#define FOURCC_tCtC GST_MAKE_FOURCC('t','C','t','C') - -G_END_DECLS - -#endif /* __GST_QTDEMUX_FOURCC_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/qtdemux/qtdemux_types.c --- a/gst_plugins_good/gst/qtdemux/qtdemux_types.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,157 +0,0 @@ -/* GStreamer - * 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. - */ - -#include "qtdemux_types.h" -#include "qtdemux_dump.h" -#include "qtdemux_fourcc.h" - -static const QtNodeType qt_node_types[] = { - {FOURCC_moov, "movie", QT_FLAG_CONTAINER,}, - {FOURCC_mvhd, "movie header", 0, - qtdemux_dump_mvhd}, - {FOURCC_clip, "clipping", QT_FLAG_CONTAINER,}, - {FOURCC_trak, "track", QT_FLAG_CONTAINER,}, - {FOURCC_udta, "user data", QT_FLAG_CONTAINER,}, /* special container */ - {FOURCC_ctab, "color table", 0,}, - {FOURCC_tkhd, "track header", 0, - qtdemux_dump_tkhd}, - {FOURCC_crgn, "clipping region", 0,}, - {FOURCC_matt, "track matte", QT_FLAG_CONTAINER,}, - {FOURCC_kmat, "compressed matte", 0,}, - {FOURCC_edts, "edit", QT_FLAG_CONTAINER,}, - {FOURCC_elst, "edit list", 0, - qtdemux_dump_elst}, - {FOURCC_load, "track load settings", 0,}, - {FOURCC_tref, "track reference", QT_FLAG_CONTAINER,}, - {FOURCC_imap, "track input map", QT_FLAG_CONTAINER,}, - {FOURCC___in, "track input", 0,}, /* special container */ - {FOURCC___ty, "input type", 0,}, - {FOURCC_mdia, "media", QT_FLAG_CONTAINER}, - {FOURCC_mdhd, "media header", 0, - qtdemux_dump_mdhd}, - {FOURCC_hdlr, "handler reference", 0, - qtdemux_dump_hdlr}, - {FOURCC_minf, "media information", QT_FLAG_CONTAINER}, - {FOURCC_vmhd, "video media information", 0, - qtdemux_dump_vmhd}, - {FOURCC_smhd, "sound media information", 0}, - {FOURCC_gmhd, "base media information header", 0}, - {FOURCC_gmin, "base media info", 0}, - {FOURCC_dinf, "data information", QT_FLAG_CONTAINER}, - {FOURCC_dref, "data reference", 0, - qtdemux_dump_dref}, - {FOURCC_stbl, "sample table", QT_FLAG_CONTAINER}, - {FOURCC_stsd, "sample description", 0, - qtdemux_dump_stsd}, - {FOURCC_stts, "time-to-sample", 0, - qtdemux_dump_stts}, - {FOURCC_stps, "partial sync sample", 0, - qtdemux_dump_stps}, - {FOURCC_stss, "sync sample", 0, - qtdemux_dump_stss}, - {FOURCC_stsc, "sample-to-chunk", 0, - qtdemux_dump_stsc}, - {FOURCC_stsz, "sample size", 0, - qtdemux_dump_stsz}, - {FOURCC_stco, "chunk offset", 0, - qtdemux_dump_stco}, - {FOURCC_co64, "64-bit chunk offset", 0, - qtdemux_dump_co64}, - {FOURCC_vide, "video media", 0}, - {FOURCC_cmov, "compressed movie", QT_FLAG_CONTAINER}, - {FOURCC_dcom, "compressed data", 0, qtdemux_dump_dcom}, - {FOURCC_cmvd, "compressed movie data", 0, qtdemux_dump_cmvd}, - {FOURCC_hint, "hint", 0,}, - {FOURCC_mp4a, "mp4a", 0,}, - {FOURCC_mp4v, "mp4v", 0,}, - {FOURCC_mjp2, "mjp2", 0,}, - {FOURCC_mhdr, "mhdr", QT_FLAG_CONTAINER,}, - {FOURCC_jp2h, "jp2h", QT_FLAG_CONTAINER,}, - {FOURCC_colr, "colr", 0,}, - {FOURCC_fiel, "fiel", 0,}, - {FOURCC_jp2x, "jp2x", 0,}, - {FOURCC_wave, "wave", QT_FLAG_CONTAINER}, - {FOURCC_appl, "appl", QT_FLAG_CONTAINER}, - {FOURCC_esds, "esds", 0}, - {FOURCC_hnti, "hnti", QT_FLAG_CONTAINER}, - {FOURCC_rtp_, "rtp ", 0, qtdemux_dump_unknown}, - {FOURCC_sdp_, "sdp ", 0, qtdemux_dump_unknown}, - {FOURCC_meta, "meta", 0, qtdemux_dump_unknown}, - {FOURCC_ilst, "ilst", QT_FLAG_CONTAINER,}, - {FOURCC__nam, "Name", QT_FLAG_CONTAINER,}, - {FOURCC_titl, "Title", QT_FLAG_CONTAINER,}, - {FOURCC__ART, "Artist", QT_FLAG_CONTAINER,}, - {FOURCC_auth, "Author", QT_FLAG_CONTAINER,}, - {FOURCC_perf, "Performer", QT_FLAG_CONTAINER,}, - {FOURCC__wrt, "Writer", QT_FLAG_CONTAINER,}, - {FOURCC__grp, "Group", QT_FLAG_CONTAINER,}, - {FOURCC__alb, "Album", QT_FLAG_CONTAINER,}, - {FOURCC_albm, "Album", QT_FLAG_CONTAINER,}, - {FOURCC__day, "Date", QT_FLAG_CONTAINER,}, - {FOURCC__cpy, "Copyright", QT_FLAG_CONTAINER,}, - {FOURCC__cmt, "Comment", QT_FLAG_CONTAINER,}, - {FOURCC__des, "Description", QT_FLAG_CONTAINER,}, - {FOURCC_dscp, "Description", QT_FLAG_CONTAINER,}, - {FOURCC__req, "Requirement", QT_FLAG_CONTAINER,}, - {FOURCC__enc, "Encoder", QT_FLAG_CONTAINER,}, - {FOURCC_gnre, "Genre", QT_FLAG_CONTAINER,}, - {FOURCC_trkn, "Track Number", QT_FLAG_CONTAINER,}, - {FOURCC_disc, "Disc Number", QT_FLAG_CONTAINER,}, - {FOURCC_disk, "Disc Number", QT_FLAG_CONTAINER,}, - {FOURCC_cprt, "Copyright", QT_FLAG_CONTAINER,}, - {FOURCC_cpil, "cpil", QT_FLAG_CONTAINER,}, - {FOURCC_tmpo, "Tempo", QT_FLAG_CONTAINER,}, - {FOURCC_covr, "Cover", QT_FLAG_CONTAINER,}, - {FOURCC_keyw, "Keywords", QT_FLAG_CONTAINER,}, - {FOURCC_kywd, "Keywords", QT_FLAG_CONTAINER,}, - {FOURCC__too, "too", QT_FLAG_CONTAINER,}, - {FOURCC_____, "----", QT_FLAG_CONTAINER,}, - {FOURCC_data, "data", 0, qtdemux_dump_unknown}, - {FOURCC_free, "free", 0,}, - {FOURCC_SVQ3, "SVQ3", 0,}, - {FOURCC_rmra, "rmra", QT_FLAG_CONTAINER,}, - {FOURCC_rmda, "rmda", QT_FLAG_CONTAINER,}, - {FOURCC_rdrf, "rdrf", 0,}, - {FOURCC__gen, "Custom Genre", QT_FLAG_CONTAINER,}, - {FOURCC_ctts, "Composition time to sample", 0, qtdemux_dump_ctts}, - {FOURCC_XiTh, "XiTh", 0}, - {FOURCC_XdxT, "XdxT", 0}, - {FOURCC_loci, "loci", 0}, - {FOURCC_clsf, "clsf", 0}, - {0, "unknown", 0,}, -}; - -static const int n_qt_node_types = - sizeof (qt_node_types) / sizeof (qt_node_types[0]); - -const QtNodeType * -qtdemux_type_get (guint32 fourcc) -{ - int i; - - for (i = 0; i < n_qt_node_types; i++) { - if (G_UNLIKELY (qt_node_types[i].fourcc == fourcc)) - return qt_node_types + i; - } - - GST_WARNING ("unknown QuickTime node type %" GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (fourcc)); - - return qt_node_types + n_qt_node_types - 1; -} diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/qtdemux/qtdemux_types.h --- a/gst_plugins_good/gst/qtdemux/qtdemux_types.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* GStreamer - * 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. - */ - -#ifndef __GST_QTDEMUX_TYPES_H__ -#define __GST_QTDEMUX_TYPES_H__ - -#include - -#include "qtdemux.h" - -G_BEGIN_DECLS - -typedef void (*QtDumpFunc) (GstQTDemux * qtdemux, guint8 * buffer, int depth); - -typedef struct _QtNodeType QtNodeType; - -#define QT_UINT32(a) (GST_READ_UINT32_BE(a)) -#define QT_UINT24(a) (GST_READ_UINT32_BE(a) >> 8) -#define QT_UINT16(a) (GST_READ_UINT16_BE(a)) -#define QT_UINT8(a) (GST_READ_UINT8(a)) -#define QT_FP32(a) ((GST_READ_UINT32_BE(a))/65536.0) -#define QT_FP16(a) ((GST_READ_UINT16_BE(a))/256.0) -#define QT_FOURCC(a) (GST_READ_UINT32_LE(a)) -#define QT_UINT64(a) ((((guint64)QT_UINT32(a))<<32)|QT_UINT32(((guint8 *)a)+4)) - -typedef enum { - QT_FLAG_NONE = (0), - QT_FLAG_CONTAINER = (1 << 0) -} QtFlags; - -struct _QtNodeType { - guint32 fourcc; - const gchar *name; - QtFlags flags; - QtDumpFunc dump; -}; - -const QtNodeType *qtdemux_type_get (guint32 fourcc); - -G_END_DECLS - -#endif /* __GST_QTDEMUX_TYPES_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/qtdemux/qtpalette.h --- a/gst_plugins_good/gst/qtdemux/qtpalette.h Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -/* GStreamer - * 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. - */ - - -#ifndef __GST_QTPALLETE_H__ -#define __GST_QTPALLETE_H__ - -#include - -G_BEGIN_DECLS - -static const guint32 ff_qt_default_palette_2[2] = { - 0xffffff, 0x000000 -}; - -static const guint32 ff_qt_default_palette_4[4] = { - 0x93655e, 0xffffff, 0xdfd0ab, 0x000000 -}; - -static const guint32 ff_qt_default_palette_16[16] = { - 0xfffbff, 0xefd9bb, 0xe8c9b1, 0x93655e, - 0xfcdee8, 0x9d8891, 0xffffff, 0xffffff, - 0xffffff, 0x474837, 0x7a5e55, 0xdfd0ab, - 0xfffbf9, 0xe8cac5, 0x8a7c77, 0x000000 -}; -static const guint32 ff_qt_default_palette_256[256] = { - 0xFFFFFF, 0xFFFFCC, 0xFFFF99, 0xFFFF66, 0xFFFF33, 0xFFFF00, - 0xFFCCFF, 0xFFCCCC, 0xFFCC99, 0xFFCC66, 0xFFCC33, 0xFFCC00, - 0xFF99FF, 0xFF99CC, 0xFF9999, 0xFF9966, 0xFF9933, 0xFF9900, - 0xFF66FF, 0xFF66CC, 0xFF6699, 0xFF6666, 0xFF6633, 0xFF6600, - 0xFF33FF, 0xFF33CC, 0xFF3399, 0xFF3366, 0xFF3333, 0xFF3300, - 0xFF00FF, 0xFF00CC, 0xFF0099, 0xFF0066, 0xFF0033, 0xFF0000, - 0xCCFFFF, 0xCCFFCC, 0xCCFF99, 0xCCFF66, 0xCCFF33, 0xCCFF00, - 0xCCCCFF, 0xCCCCCC, 0xCCCC99, 0xCCCC66, 0xCCCC33, 0xCCCC00, - 0xCC99FF, 0xCC99CC, 0xCC9999, 0xCC9966, 0xCC9933, 0xCC9900, - 0xCC66FF, 0xCC66CC, 0xCC6699, 0xCC6666, 0xCC6633, 0xCC6600, - 0xCC33FF, 0xCC33CC, 0xCC3399, 0xCC3366, 0xCC3333, 0xCC3300, - 0xCC00FF, 0xCC00CC, 0xCC0099, 0xCC0066, 0xCC0033, 0xCC0000, - 0x99FFFF, 0x99FFCC, 0x99FF99, 0x99FF66, 0x99FF33, 0x99FF00, - 0x99CCFF, 0x99CCCC, 0x99CC99, 0x99CC66, 0x99CC33, 0x99CC00, - 0x9999FF, 0x9999CC, 0x999999, 0x999966, 0x999933, 0x999900, - 0x9966FF, 0x9966CC, 0x996699, 0x996666, 0x996633, 0x996600, - 0x9933FF, 0x9933CC, 0x993399, 0x993366, 0x993333, 0x993300, - 0x9900FF, 0x9900CC, 0x990099, 0x990066, 0x990033, 0x990000, - 0x66FFFF, 0x66FFCC, 0x66FF99, 0x66FF66, 0x66FF33, 0x66FF00, - 0x66CCFF, 0x66CCCC, 0x66CC99, 0x66CC66, 0x66CC33, 0x66CC00, - 0x6699FF, 0x6699CC, 0x669999, 0x669966, 0x669933, 0x669900, - 0x6666FF, 0x6666CC, 0x666699, 0x666666, 0x666633, 0x666600, - 0x6633FF, 0x6633CC, 0x663399, 0x663366, 0x663333, 0x663300, - 0x6600FF, 0x6600CC, 0x660099, 0x660066, 0x660033, 0x660000, - 0x33FFFF, 0x33FFCC, 0x33FF99, 0x33FF66, 0x33FF33, 0x33FF00, - 0x33CCFF, 0x33CCCC, 0x33CC99, 0x33CC66, 0x33CC33, 0x33CC00, - 0x3399FF, 0x3399CC, 0x339999, 0x339966, 0x339933, 0x339900, - 0x3366FF, 0x3366CC, 0x336699, 0x336666, 0x336633, 0x336600, - 0x3333FF, 0x3333CC, 0x333399, 0x333366, 0x333333, 0x333300, - 0x3300FF, 0x3300CC, 0x330099, 0x330066, 0x330033, 0x330000, - 0x00FFFF, 0x00FFCC, 0x00FF99, 0x00FF66, 0x00FF33, 0x00FF00, - 0x00CCFF, 0x00CCCC, 0x00CC99, 0x00CC66, 0x00CC33, 0x00CC00, - 0x0099FF, 0x0099CC, 0x009999, 0x009966, 0x009933, 0x009900, - 0x0066FF, 0x0066CC, 0x006699, 0x006666, 0x006633, 0x006600, - 0x0033FF, 0x0033CC, 0x003399, 0x003366, 0x003333, 0x003300, - 0x0000FF, 0x0000CC, 0x000099, 0x000066, 0x000033, 0xEE0000, - 0xDD0000, 0xBB0000, 0xAA0000, 0x880000, 0x770000, 0x550000, - 0x440000, 0x220000, 0x110000, 0x00EE00, 0x00DD00, 0x00BB00, - 0x00AA00, 0x008800, 0x007700, 0x005500, 0x004400, 0x002200, - 0x001100, 0x0000EE, 0x0000DD, 0x0000BB, 0x0000AA, 0x000088, - 0x000077, 0x000055, 0x000044, 0x000022, 0x000011, 0xEEEEEE, - 0xDDDDDD, 0xBBBBBB, 0xAAAAAA, 0x888888, 0x777777, 0x555555, - 0x444444, 0x222222, 0x111111, 0x000000 -}; - -static const guint32 ff_qt_grayscale_palette_16[16] = { - 0xffffff, 0xeeeeee, 0xdddddd, 0xcccccc, - 0xbbbbbb, 0xaaaaaa, 0x999999, 0x888888, - 0x777777, 0x666666, 0x555555, 0x444444, - 0x333333, 0x222222, 0x111111, 0x000000 -}; - -static const guint32 ff_qt_grayscale_palette_256[256] = { - 0xffffff, 0xfefefe, 0xfdfdfd, 0xfcfcfc, 0xfbfbfb, 0xfafafa, 0xf9f9f9, - 0xf8f8f8, 0xf7f7f7, 0xf6f6f6, 0xf5f5f5, 0xf4f4f4, 0xf3f3f3, 0xf2f2f2, - 0xf1f1f1, 0xf0f0f0, 0xefefef, 0xeeeeee, 0xededed, 0xececec, 0xebebeb, - 0xeaeaea, 0xe9e9e9, 0xe8e8e8, 0xe7e7e7, 0xe6e6e6, 0xe5e5e5, 0xe4e4e4, - 0xe3e3e3, 0xe2e2e2, 0xe1e1e1, 0xe0e0e0, 0xdfdfdf, 0xdedede, 0xdddddd, - 0xdcdcdc, 0xdbdbdb, 0xdadada, 0xd9d9d9, 0xd8d8d8, 0xd7d7d7, 0xd6d6d6, - 0xd5d5d5, 0xd4d4d4, 0xd3d3d3, 0xd2d2d2, 0xd1d1d1, 0xd0d0d0, 0xcfcfcf, - 0xcecece, 0xcdcdcd, 0xcccccc, 0xcbcbcb, 0xcacaca, 0xc9c9c9, 0xc8c8c8, - 0xc7c7c7, 0xc6c6c6, 0xc5c5c5, 0xc4c4c4, 0xc3c3c3, 0xc2c2c2, 0xc1c1c1, - 0xc0c0c0, 0xbfbfbf, 0xbebebe, 0xbdbdbd, 0xbcbcbc, 0xbbbbbb, 0xbababa, - 0xb9b9b9, 0xb8b8b8, 0xb7b7b7, 0xb6b6b6, 0xb5b5b5, 0xb4b4b4, 0xb3b3b3, - 0xb2b2b2, 0xb1b1b1, 0xb0b0b0, 0xafafaf, 0xaeaeae, 0xadadad, 0xacacac, - 0xababab, 0xaaaaaa, 0xa9a9a9, 0xa8a8a8, 0xa7a7a7, 0xa6a6a6, 0xa5a5a5, - 0xa4a4a4, 0xa3a3a3, 0xa2a2a2, 0xa1a1a1, 0xa0a0a0, 0x9f9f9f, 0x9e9e9e, - 0x9d9d9d, 0x9c9c9c, 0x9b9b9b, 0x9a9a9a, 0x999999, 0x989898, 0x979797, - 0x969696, 0x959595, 0x949494, 0x939393, 0x929292, 0x919191, 0x909090, - 0x8f8f8f, 0x8e8e8e, 0x8d8d8d, 0x8c8c8c, 0x8b8b8b, 0x8a8a8a, 0x898989, - 0x888888, 0x878787, 0x868686, 0x858585, 0x848484, 0x838383, 0x828282, - 0x818181, 0x808080, 0x7f7f7f, 0x7e7e7e, 0x7d7d7d, 0x7c7c7c, 0x7b7b7b, - 0x7a7a7a, 0x797979, 0x787878, 0x777777, 0x767676, 0x757575, 0x747474, - 0x737373, 0x727272, 0x717171, 0x707070, 0x6f6f6f, 0x6e6e6e, 0x6d6d6d, - 0x6c6c6c, 0x6b6b6b, 0x6a6a6a, 0x696969, 0x686868, 0x676767, 0x666666, - 0x656565, 0x646464, 0x636363, 0x626262, 0x616161, 0x606060, 0x5f5f5f, - 0x5e5e5e, 0x5d5d5d, 0x5c5c5c, 0x5b5b5b, 0x5a5a5a, 0x595959, 0x585858, - 0x575757, 0x565656, 0x555555, 0x545454, 0x535353, 0x525252, 0x515151, - 0x505050, 0x4f4f4f, 0x4e4e4e, 0x4d4d4d, 0x4c4c4c, 0x4b4b4b, 0x4a4a4a, - 0x494949, 0x484848, 0x474747, 0x464646, 0x454545, 0x444444, 0x434343, - 0x424242, 0x414141, 0x404040, 0x3f3f3f, 0x3e3e3e, 0x3d3d3d, 0x3c3c3c, - 0x3b3b3b, 0x3a3a3a, 0x393939, 0x383838, 0x373737, 0x363636, 0x353535, - 0x343434, 0x333333, 0x323232, 0x313131, 0x303030, 0x2f2f2f, 0x2e2e2e, - 0x2d2d2d, 0x2c2c2c, 0x2b2b2b, 0x2a2a2a, 0x292929, 0x282828, 0x272727, - 0x262626, 0x252525, 0x242424, 0x232323, 0x222222, 0x212121, 0x202020, - 0x1f1f1f, 0x1e1e1e, 0x1d1d1d, 0x1c1c1c, 0x1b1b1b, 0x1a1a1a, 0x191919, - 0x181818, 0x171717, 0x161616, 0x151515, 0x141414, 0x131313, 0x121212, - 0x111111, 0x101010, 0x0f0f0f, 0x0e0e0e, 0x0d0d0d, 0x0c0c0c, 0x0b0b0b, - 0x0a0a0a, 0x090909, 0x080808, 0x070707, 0x060606, 0x050505, 0x040404, - 0x030303, 0x020202, 0x010101, 0x000000 -}; - -G_END_DECLS - -#endif /* __GST_QTPALETTE_H__ */ diff -r bc39b352897e -r 69c7080681bf gst_plugins_good/gst/qtdemux/quicktime.c --- a/gst_plugins_good/gst/qtdemux/quicktime.c Fri Jul 09 16:26:45 2010 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * Copyright (C) <2003> David A. Schleef - * Copyright (C) <2006> Wim Taymans - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif -#include "gst/gst-i18n-plugin.h" - -#include "qtdemux.h" -#include "gstrtpxqtdepay.h" - -static gboolean -plugin_init (GstPlugin * plugin) -{ -#ifdef ENABLE_NLS - setlocale (LC_ALL, ""); - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); -#endif /* ENABLE_NLS */ - - /* ensure private tag is registered */ - gst_tag_register (GST_QT_DEMUX_PRIVATE_TAG, GST_TAG_FLAG_META, - GST_TYPE_BUFFER, "QT atom", "unparsed QT tag atom", - gst_tag_merge_use_first); - - gst_tag_register (GST_QT_DEMUX_CLASSIFICATION_TAG, GST_TAG_FLAG_META, - G_TYPE_STRING, GST_QT_DEMUX_CLASSIFICATION_TAG, "content classification", - gst_tag_merge_use_first); - - if (!gst_element_register (plugin, "qtdemux", - GST_RANK_PRIMARY, GST_TYPE_QTDEMUX)) - return FALSE; - - if (!gst_element_register (plugin, "rtpxqtdepay", - GST_RANK_MARGINAL, GST_TYPE_RTP_XQT_DEPAY)) - return FALSE; - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "quicktime", - "Quicktime support", - plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); - -#ifdef SYMBIAN -EXPORT_C GstPluginDesc* _GST_PLUGIN_DESC() -{ - return &gst_plugin_desc; -} - -#endif diff -r bc39b352897e -r 69c7080681bf gst_plugins_symbian/gst/devsound/devsoundsinkwrapper.cpp --- a/gst_plugins_symbian/gst/devsound/devsoundsinkwrapper.cpp Fri Jul 09 16:26:45 2010 -0500 +++ b/gst_plugins_symbian/gst/devsound/devsoundsinkwrapper.cpp Fri Aug 06 16:36:50 2010 -0500 @@ -284,6 +284,10 @@ int close_devsound(GstDevsoundSink *ds) { TRACE_PRN_FN_ENT; + CMMFDevSound *dev_sound = 0; + dev_sound = (STATIC_CAST(DevSoundWrapper*, ds->handle))->dev_sound; + dev_sound->Stop(); + delete dev_sound; g_list_foreach(ds->fmt, (GFunc) g_free, NULL); g_list_free(ds->fmt); diff -r bc39b352897e -r 69c7080681bf gst_plugins_symbian/gst/devsound/devsoundsrcwrapper.cpp --- a/gst_plugins_symbian/gst/devsound/devsoundsrcwrapper.cpp Fri Jul 09 16:26:45 2010 -0500 +++ b/gst_plugins_symbian/gst/devsound/devsoundsrcwrapper.cpp Fri Aug 06 16:36:50 2010 -0500 @@ -27,10 +27,11 @@ DevSoundWrapperSrc::DevSoundWrapperSrc() { - init_complete = 0; + //init_complete = 0; dev_sound = NULL; buffersize = 0; dev_count = 0; + speechbitrate = 0; caps.iRate = EMMFSampleRate8000Hz; caps.iEncoding = EMMFSoundEncoding16BitPCM; caps.iChannels = EMMFMono; @@ -48,15 +49,7 @@ TRACE_PRN_FN_ENT; TRequestStatus* stat = &(AL->iStatus); - if (aError == KErrNone) - { - init_complete = 1; - } - else - { - init_complete = 0; - } - + iCallbackError = aError; User::RequestComplete(stat, aError); TRACE_PRN_FN_EXT; } @@ -102,6 +95,16 @@ TRACE_PRN_FN_ENT; TRACE_PRN_N1(_L("DevSoundWrapperSrc::RecordError %d"),aError); iCallbackError = aError; + TRequestStatus* stat = &(AL->iStatus); + /// need to check this, error can occure before and after calling + /// the StartActiveScheduler and might and might not be waiting for + /// completing the request + if( AL->IsActive() ) + { + /// need to complete the request for coming out from blocking call. + User::RequestComplete(stat, aError); + iCallbackError = aError; + } TRACE_PRN_FN_EXT; } /**********************************************************/ @@ -176,39 +179,36 @@ int initialize_devsound(GstDevsoundSrc* ds) { TRACE_PRN_FN_ENT; - int ret = 0; + //int ret = 0; DevSoundWrapperSrc* handle = (DevSoundWrapperSrc*) ds->handle; handle->AL->InitialiseActiveListener(); - TRAP(ret, handle->dev_sound->InitializeL(*handle, handle->fourcc, EMMFStateRecording)); + TRAP(handle->iCallbackError, handle->dev_sound->InitializeL(*handle, handle->fourcc, EMMFStateRecording)); - if (ret) + if ( handle->iCallbackError ) { TRACE_PRN_FN_EXT; - return ret; + return handle->iCallbackError; } handle->AL->StartActiveScheduler(); - if (handle->init_complete == 1) + if (KErrNone == handle->iCallbackError ) { TMMFPrioritySettings temp; temp.iPref = (TMdaPriorityPreference) ds->preference; temp.iPriority = ds->priority; handle->dev_sound->SetPrioritySettings(temp); - SetConfigurations(handle); - ret = KErrNone; - } - else - { - ret = KErrNotFound; + handle->iCallbackError = SetConfigurations(handle); + } - TRACE_PRN_IF_ERR(ret); + + TRACE_PRN_IF_ERR(handle->iCallbackError); TRACE_PRN_FN_EXT; - return ret; + return handle->iCallbackError; } /*********************************************************/ @@ -225,15 +225,7 @@ { TRACE_PRN_FN_ENT; DevSoundWrapperSrc* handle = (DevSoundWrapperSrc*) ds->handle; - if(handle->dev_sound->IsResumeSupported()) - { handle->dev_sound->Pause(); - } - else - { - handle->iSamplesRecorded = handle->dev_sound->SamplesRecorded(); - handle->dev_sound->Stop(); - } TRACE_PRN_FN_EXT; return 0; } @@ -244,12 +236,13 @@ DevSoundWrapperSrc* handle = (DevSoundWrapperSrc*) ds->handle; if(handle->dev_sound->IsResumeSupported()) { - handle->dev_sound->Resume(); + + handle->iCallbackError = handle->dev_sound->Resume(); } else { - recordinit(handle); - initproperties(ds); + if( KErrNone == recordinit(handle) ) + initproperties(ds); } TRACE_PRN_FN_EXT; return 0; @@ -257,7 +250,7 @@ int open_device(DevSoundWrapperSrc **handle) { - int retcode = KErrNone; + (*handle)->iCallbackError = KErrNone; TRACE_PRN_FN_ENT; (*handle)->dev_count++; @@ -276,24 +269,26 @@ (*handle)->AL = new CActiveListener; ((*handle)->AL)->asw = new CActiveSchedulerWait(); - TRAP( retcode,(*handle)->dev_sound = CMMFDevSound::NewL() ); + TRAP( (*handle)->iCallbackError,(*handle)->dev_sound = CMMFDevSound::NewL() ); if (!(*handle)->AL || !((*handle)->AL)->asw || !(*handle)->dev_sound || !(*handle)->as) { - retcode = KErrNoMemory; + return KErrNoMemory; } - TRAP(retcode ,(*handle)->iAudoInputRecord = CAudioInput::NewL(*(*handle)->dev_sound)); - RArray inputArray; + TRAP((*handle)->iCallbackError ,(*handle)->iAudoInputRecord = CAudioInput::NewL(*(*handle)->dev_sound)); + if ( KErrNone == (*handle)->iCallbackError ) + { + RArray inputArray; inputArray.Append( CAudioInput::EDefaultMic ); // Set Audio Input (*handle)->iAudoInputRecord->SetAudioInputL( inputArray.Array( ) ); inputArray.Close(); - + } TRACE_PRN_FN_EXT; - return retcode; + return (*handle)->iCallbackError; } /*********************************************************/ @@ -301,7 +296,9 @@ int close_devsound(GstDevsoundSrc *ds) { TRACE_PRN_FN_ENT; - (STATIC_CAST(DevSoundWrapperSrc*, ds->handle))->dev_sound->Stop(); + CMMFDevSound *dev_sound= 0; + dev_sound = (STATIC_CAST(DevSoundWrapperSrc*, ds->handle))->dev_sound; + dev_sound->Stop(); g_list_foreach(ds->supportedbitrates, (GFunc) g_free, NULL); g_list_free(ds->supportedbitrates); @@ -309,11 +306,17 @@ g_list_free(ds->fmt); ds->fmt = NULL; delete (STATIC_CAST(DevSoundWrapperSrc*, ds->handle))->iAudoInputRecord; + delete dev_sound; delete ds->handle; TRACE_PRN_FN_EXT; return 0; } /************************************************************/ +void update_devsound_speech_bitrate(DevSoundWrapperSrc *handle, TUint bitrate) + { + handle->speechbitrate = bitrate; + } +/************************************************************/ int SetConfigurations(DevSoundWrapperSrc *handle) { @@ -326,15 +329,7 @@ handle->gain = (handle->dev_sound)->MaxGain(); (handle->dev_sound)->SetGain(handle->gain); handle->caps.iBufferSize = temp_caps.iBufferSize; - - TRAP(ret, (handle->dev_sound)->SetConfigL(handle->caps) ); - if (ret) - { - return ret; - } - - (handle->caps) = (handle->dev_sound)->Config(); - + switch (handle->fourcc) { case KMccFourCCIdG711: @@ -373,13 +368,33 @@ } } + if (ret) + return ret; + if (!handle->iSpeechEncoderConfig && handle->fourcc != KMMFFourCCCodePCM16) { TRAP(ret, handle->iSpeechEncoderConfig = CSpeechEncoderConfig::NewL(*handle->dev_sound)); + if (ret) + return ret; + + if(handle->speechbitrate > 0) + { + ret = set_speech_encoder_bit_rate(handle,handle->speechbitrate); + if(ret) + return ret; + } } + + TRAP(ret, (handle->dev_sound)->SetConfigL(handle->caps) ); + if (ret) + { + return ret; + } + + (handle->caps) = (handle->dev_sound)->Config(); TRACE_PRN_FN_EXT; return ret; @@ -621,27 +636,18 @@ int recordinit(DevSoundWrapperSrc *handle) { TRACE_PRN_FN_ENT; - int ret = 0; + ((handle)->AL)->InitialiseActiveListener(); handle->iCallbackError = KErrNone; - TRAP(ret, (handle->dev_sound)->RecordInitL() ); + TRAP(handle->iCallbackError, (handle->dev_sound)->RecordInitL() ); - if (ret) + if (!handle->iCallbackError) { - TRACE_PRN_FN_EXT; - return ret; - } - ((handle)->AL)->StartActiveScheduler(); - - if ((handle->iCallbackError) != KErrNone) - { - TRACE_PRN_FN_EXT; - return (handle->iCallbackError); + ((handle)->AL)->StartActiveScheduler(); } TRACE_PRN_FN_EXT; - return KErrNone; - + return handle->iCallbackError; } /*******************************************************************/ @@ -662,9 +668,8 @@ int pre_init_setconf(GstDevsoundSrc *ds) { TRACE_PRN_FN_ENT; - int ret = 0; DevSoundWrapperSrc* dsPtr = STATIC_CAST(DevSoundWrapperSrc*, ds->handle); - + dsPtr->iCallbackError = 0; // NOTE: it is too late for setting prio/pref here if (ds->pending.preferenceupdate == 1 || ds->pending.priorityupdate == 1) { @@ -681,13 +686,13 @@ == 1) { - TRAP( ret, (dsPtr->dev_sound)->SetRecordBalanceL(ds->leftbalance, + TRAP( dsPtr->iCallbackError, (dsPtr->dev_sound)->SetRecordBalanceL(ds->leftbalance, ds->rightbalance) ); ds->pending.leftbalanceupdate = FALSE; ds->pending.rightbalanceupdate = FALSE; } TRACE_PRN_FN_EXT; - return ret; + return dsPtr->iCallbackError; } /*********************************************************/ void getsupporteddatatypes(GstDevsoundSrc *ds) @@ -745,3 +750,10 @@ TRACE_PRN_FN_EXT; } +int call_back_error(DevSoundWrapperSrc* dsPtr) + { + TRACE_PRN_FN_ENT; + return dsPtr->iCallbackError; + TRACE_PRN_FN_EXT; + } + diff -r bc39b352897e -r 69c7080681bf gst_plugins_symbian/gst/devsound/devsoundsrcwrapper.h --- a/gst_plugins_symbian/gst/devsound/devsoundsrcwrapper.h Fri Jul 09 16:26:45 2010 -0500 +++ b/gst_plugins_symbian/gst/devsound/devsoundsrcwrapper.h Fri Aug 06 16:36:50 2010 -0500 @@ -87,7 +87,7 @@ public: CActiveListener *AL; CActiveScheduler *as; - TInt init_complete; + //TInt init_complete; CMMFBuffer *buffer; CMMFDevSound *dev_sound; TMMFCapabilities caps; @@ -99,6 +99,7 @@ int bufferreadpos; guint* supportedbitrates; int iSamplesRecorded; + TUint speechbitrate; CSpeechEncoderConfig* iSpeechEncoderConfig; CG711EncoderIntfc* iG711EncoderIntfc; CG729EncoderIntfc* iG729EncoderIntfc; @@ -177,7 +178,10 @@ int set_ilbc_encoder_mode(DevSoundWrapperSrc *handle,enum TIlbcEncodeMode aEncodeMode); int set_ilbc_vad_mode(DevSoundWrapperSrc *handle,gboolean aVadMode); int get_ilbc_vad_mode(DevSoundWrapperSrc *handle,gboolean* aVadMode); - + void update_devsound_speech_bitrate(DevSoundWrapperSrc *handle, TUint bitrate); + + /// getting the call back error + int call_back_error(DevSoundWrapperSrc* dsPtr); #ifdef __cplusplus }//extern c diff -r bc39b352897e -r 69c7080681bf gst_plugins_symbian/gst/devsound/gstdevsoundsrc.c --- a/gst_plugins_symbian/gst/devsound/gstdevsoundsrc.c Fri Jul 09 16:26:45 2010 -0500 +++ b/gst_plugins_symbian/gst/devsound/gstdevsoundsrc.c Fri Aug 06 16:36:50 2010 -0500 @@ -23,7 +23,8 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif - +#include +#include #include #include "common.h" #include "gstdevsoundsrc.h" @@ -92,7 +93,7 @@ static gint gst_set_speech_encoder_bit_rate(guint aBitrate); static gint gst_set_speech_encoder_vad_mode(gboolean aVadMode); static void gst_Apply_SpeechEncoder_Update(GstDevsoundSrc *devsoundsrc ); - +static void gst_update_devsound_speech_bitrate(GstDevsoundSrc *devsoundsrc ); /************************* * G711 Encoder Interface @@ -181,7 +182,7 @@ CLOSE }; enum command_to_consumer_thread_enum cmd; - +int return_error; enum { LAST_SIGNAL @@ -213,23 +214,11 @@ "signed = (boolean) TRUE, " "width = (int) 16, " "depth = (int) 16, " - "rate = (int) [ 8000, 48000 ]," + "rate = (int) { 8000, 16000, 24000, 32000, 48000 }," "channels = (int) [ 1, 2 ]; " "audio/amr, " - "rate = (int) [ 8000, 48000 ], " - "channels = (int) [ 1, 2 ]; " - "audio/x-alaw, " - "rate = (int) [ 8000, 48000 ], " - "channels = (int) [ 1, 2 ]; " - "audio/g729, " - "rate = (int) [ 8000, 48000 ], " - "channels = (int) [ 1, 2 ]; " - "audio/ilbc, " - "rate = (int) [ 8000, 48000 ], " - "channels = (int) [ 1, 2 ]; " - "audio/x-mulaw, " - "rate = (int) [ 8000, 48000 ], " - "channels = (int) [ 1, 2 ]") + "rate = (int) 8000, " + "channels = (int) [ 1, 2 ]; ") ); static GstElementClass *parent_class= NULL; @@ -407,7 +396,17 @@ TUint8* gBuffer; GstBuffer* pushBuffer= NULL; //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "StartDevSoundThread ",NULL); - open_devsound(&(devsoundsrc->handle)); + int ret = open_devsound(&(devsoundsrc->handle)); + + if( 0 != ret ) + { + pthread_mutex_lock(&(create_mutex1)); + return_error = ret; + pthread_cond_signal(&(create_condition1)); + pthread_mutex_unlock(&(create_mutex1)); + //return_error = ret; + pthread_exit(NULL); + } getsupporteddatatypes(devsoundsrc); @@ -419,6 +418,7 @@ //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) devsoundsrc, "After Record Init ",NULL); pthread_mutex_lock(&(create_mutex1)); + return_error = ret; pthread_cond_signal(&(create_condition1)); pthread_mutex_unlock(&(create_mutex1)); @@ -435,10 +435,28 @@ // without putting it to play state if ( cmd != CLOSE ) { - initialize_devsound(devsoundsrc); - - recordinit(devsoundsrc->handle); - initproperties(devsoundsrc); + gst_update_devsound_speech_bitrate(devsoundsrc); + ret = initialize_devsound(devsoundsrc); + if( 0 == ret ) + { + ret = recordinit(devsoundsrc->handle); + if( 0 == ret ) + initproperties(devsoundsrc); + + } + /// if initialization of devsound failed, return error, + /// on return other thread will send CLOSE cmd to exit from thread. + if( ret ) + { + pthread_mutex_lock(&(create_mutex1)); + return_error = ret; + pthread_cond_signal(&(create_condition1)); + pthread_mutex_unlock(&(create_mutex1)); + + pthread_mutex_lock(&create_mutex1); + pthread_cond_wait(&create_condition1, &create_mutex1); + pthread_mutex_unlock(&create_mutex1); + } } while (TRUE) @@ -460,7 +478,7 @@ case RECORDING: { pre_init_setconf(devsoundsrc); - gst_Apply_SpeechEncoder_Update(devsoundsrc); +// gst_Apply_SpeechEncoder_Update(devsoundsrc); gst_Apply_G711Encoder_Update(devsoundsrc); gst_Apply_G729Encoder_Update(devsoundsrc ); gst_Apply_IlbcEncoder_Update(devsoundsrc ); @@ -510,6 +528,7 @@ break; } pthread_mutex_lock(&(create_mutex1)); + return_error = call_back_error(devsoundsrc->handle); pthread_cond_signal(&(create_condition1)); pthread_mutex_unlock(&(create_mutex1)); @@ -687,6 +706,7 @@ static gboolean gst_devsound_src_start(GstBaseSrc * bsrc) { GstBuffer *tmp_gstbuffer=NULL; + gboolean ret = TRUE; GstDevsoundSrc *src= GST_DEVSOUND_SRC(bsrc); //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "gst_devsound_src_start ENTER ",NULL); pthread_mutex_init(&create_mutex1, NULL); @@ -710,6 +730,7 @@ consumer_thread_state = CONSUMER_THREAD_INITIALIZING; cmd = OPEN; + return_error = 0; //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "Before Thread Create ",NULL); pthread_create(&ds_thread, NULL, StartDevSoundThread, (void *)src); //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "After Thread Create ",NULL); @@ -718,11 +739,12 @@ { pthread_mutex_lock(&create_mutex1); pthread_cond_wait(&create_condition1, &create_mutex1); + ret = !return_error; // should be TRUE on no Error, and FALSE at ERROR. pthread_mutex_unlock(&create_mutex1); } //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "AFter Mutex Wait in START ",NULL); //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) src, "gst_devsound_src_start EXIT ",NULL); - return TRUE; + return ret; /* ERRORS */ } @@ -800,6 +822,7 @@ { GstDevsoundSrc *dsrc= GST_DEVSOUND_SRC(src); int bufferpos=0; + int ret = 0; if(!g_queue_get_length(dataqueue) && (dsrc->eosreceived == TRUE)) { @@ -865,26 +888,41 @@ else { cmd = RECORDING; + return_error = 0; pthread_mutex_lock(&(create_mutex1)); pthread_cond_signal(&(create_condition1)); pthread_mutex_unlock(&(create_mutex1)); pthread_mutex_lock(&(create_mutex1)); pthread_cond_wait(&(create_condition1), &(create_mutex1)); + ret = return_error; pthread_mutex_unlock(&(create_mutex1)); } //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "AFTER WAIT in CREATE ",NULL); } - + if( KErrInUse == ret || KErrDied == ret || KErrAccessDenied == ret ) + { + // post error as pre-emption + GST_ELEMENT_ERROR (src, RESOURCE, BUSY, + (("Pre-emption error.")), + ("streaming paused because higher priority app requested resource, Err(%d)", ret)); + + return GST_FLOW_UNEXPECTED; + } + else if( KErrNone != ret ) + { + // no need to post error as base src will post error. + return GST_FLOW_ERROR; + } //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "Before POP in CREATE ",NULL); GST_OBJECT_LOCK(dsrc); popBuffer = (GstBuffer*)g_queue_pop_tail(dataqueue); GST_OBJECT_UNLOCK(dsrc); - //gst_debug_log(devsound_debug, GST_LEVEL_LOG, "", "", 0, (GObject *) dsrc, "AFTER POP in CREATE ",NULL); - if(!popBuffer) - { - return GST_FLOW_UNEXPECTED; - } + + if(!popBuffer ) + { + return GST_FLOW_UNEXPECTED; + } if(dsrc->firstTimeInit != kPlayed) { dsrc->prevbuffersize = gst_base_src_get_blocksize(src); @@ -952,12 +990,15 @@ if(cmd == PAUSE) { cmd = RESUME; + return_error = 0; pthread_mutex_lock(&create_mutex1); pthread_cond_signal(&create_condition1); pthread_mutex_unlock(&create_mutex1); pthread_mutex_lock(&create_mutex1); pthread_cond_wait(&create_condition1, &create_mutex1); + if( return_error ) + ret = GST_STATE_CHANGE_FAILURE; pthread_mutex_unlock(&create_mutex1); } break; @@ -973,12 +1014,15 @@ case GST_STATE_CHANGE_PLAYING_TO_PAUSED: cmd = PAUSE; + return_error = 0; pthread_mutex_lock(&create_mutex1); pthread_cond_signal(&create_condition1); pthread_mutex_unlock(&create_mutex1); pthread_mutex_lock(&create_mutex1); pthread_cond_wait(&create_condition1, &create_mutex1); + if( return_error ) + ret = GST_STATE_CHANGE_FAILURE; pthread_mutex_unlock(&create_mutex1); break; default: @@ -1052,7 +1096,14 @@ return 0; } - +static void gst_update_devsound_speech_bitrate(GstDevsoundSrc *devsoundsrc ) + { + if(customInfaceUpdate.speechbitrateupdate == TRUE) + { + update_devsound_speech_bitrate(devsoundsrc->handle,speechbitrate); + customInfaceUpdate.speechbitrateupdate = FALSE; + } + } static void gst_Apply_SpeechEncoder_Update(GstDevsoundSrc *devsoundsrc ) { if(customInfaceUpdate.speechbitrateupdate == TRUE) @@ -1251,6 +1302,7 @@ //reset_devsound(sink->handle); src->eosreceived = TRUE; cmd = STOP; + return_error = 0; pthread_mutex_lock(&create_mutex1); pthread_cond_signal(&create_condition1); pthread_mutex_unlock(&create_mutex1); diff -r bc39b352897e -r 69c7080681bf gst_plugins_symbian/tsrc/gstreamertestmodule/group/bld.inf --- a/gst_plugins_symbian/tsrc/gstreamertestmodule/group/bld.inf Fri Jul 09 16:26:45 2010 -0500 +++ b/gst_plugins_symbian/tsrc/gstreamertestmodule/group/bld.inf Fri Aug 06 16:36:50 2010 -0500 @@ -27,25 +27,9 @@ PRJ_TESTEXPORTS #ifdef FF_GSTREAMER -/epoc32/release/winscw/udeb/libgstcoreelements.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstcoreelements.dll -/epoc32/release/winscw/udeb/libgstcoreindexers.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstcoreindexers.dll -/epoc32/release/winscw/udeb/libgstwavparse.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstwavparse.dll -/epoc32/release/winscw/udeb/libgstwavenc.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstwavenc.dll -/epoc32/release/winscw/udeb/libgstdevsoundsink.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstdevsoundsink.dll -/epoc32/release/winscw/udeb/libgstdevsoundsrc.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstdevsoundsrc.dll -/epoc32/release/winscw/udeb/libgstaudioconvert.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstaudioconvert.dll -/epoc32/release/winscw/udeb/libgstaudioresample.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstaudioresample.dll -/epoc32/release/winscw/udeb/libgstaudiotestsrc.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstaudiotestsrc.dll -/epoc32/release/winscw/udeb/libgstdecodebin.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstdecodebin.dll -/epoc32/release/winscw/udeb/libgstdecodebin2.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstdecodebin2.dll -/epoc32/release/winscw/udeb/libgstplaybin.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstplaybin.dll -/epoc32/release/winscw/udeb/libgsttypefindfunctions.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgsttypefindfunctions.dll -/epoc32/release/winscw/udeb/libgstqueue2.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstlibgstqueue2.dll -/epoc32/release/winscw/udeb/libgstaudiorate.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstaudiorate.dll -/epoc32/release/winscw/udeb/libgstautodetect.dll /epoc32/release/winscw/udeb/z/sys/bin/plugins/libgstautodetect.dll - ../conf/GStreamerTestClass.cfg /epoc32/winscw/c/TestFramework/GStreamerTestClass.cfg ../init/GStreamerTestClass.ini /epoc32/winscw/c/TestFramework/GStreamerTestClass.ini +../init/TestFramework.ini /epoc32/winscw/c/TestFramework/TestFramework.ini #endif PRJ_TESTMMPFILES diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/examples/aac_record/group/aacrecord.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/examples/aac_record/group/aacrecord.mmp Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,82 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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. +* +* Description: +* +*/ + +#include + +TARGET aac_record.exe +TARGETTYPE EXE +UID 0 0x055301c3 + +EPOCHEAPSIZE 0x10000 0x100000 +#ifdef EKA2 +LANG SC +CAPABILITY All -Tcb +VENDORID VID_DEFAULT + +#endif + + + +MACRO HAVE_CONFIG_H + + +USERINCLUDE .. +USERINCLUDE ../libs/gst/base +USERINCLUDE ../gst +USERINCLUDE ../libs/gst/base +USERINCLUDE ../gst +USERINCLUDE ../../../../.. +USERINCLUDE ../../../../libs/gst/check +USERINCLUDE ../../../../gst +USERINCLUDE ../../../.. +USERINCLUDE ../../../../libs + +MW_LAYER_SYSTEMINCLUDE +OS_LAYER_LIBC_SYSTEMINCLUDE + +OS_LAYER_GLIB_SYSTEMINCLUDE +MW_LAYER_GSTREAMER_SYSTEMINCLUDE + + + +SOURCEPATH ../src + +SOURCE aacrecord.c + + +LIBRARY euser.lib libc.lib +LIBRARY libpthread.lib +LIBRARY libdl.lib +LIBRARY libglib.lib +LIBRARY libgmodule.lib + +LIBRARY libgobject.lib +LIBRARY libgthread.lib +LIBRARY libm.lib +LIBRARY libz.lib +LIBRARY libgstreamer.lib +LIBRARY libgstbase.lib +LIBRARY libgstcontroller.lib + +STATICLIBRARY libcrt0.lib +//VENDORID VID_DEFAULT +SMPSAFE diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/examples/aac_record/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/examples/aac_record/group/bld.inf Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,27 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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. +* +* Description: +* +*/ + +PRJ_PLATFORMS +DEFAULT + +PRJ_TESTMMPFILES +aacrecord.mmp diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/examples/aac_record/src/aacrecord.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/examples/aac_record/src/aacrecord.c Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,313 @@ + +#include +#include +#include +#include +#include +#define LOG_FILE "c:\\logs\\launch_logs.txt" +#include "std_log_result.h" +#define LOG_FILENAME_LINE __FILE__, __LINE__ + +static guint _bitrate = 128000; +static guint _channels = 1; +static guint _sample_rate = 8000; +static guint _aac_profile = 2; // default is LC +static guint _enable_logs = 1; +static guint _record_duration = 10000; // recording duration +#define REC_FILENAME_LEN 256 +static char rec_filename[REC_FILENAME_LEN]; + +GstElement *pipeline; + +#define ENABLE_LOGS + +#ifdef ENABLE_LOGS +#define RET_GST_ERR_STR(var, level, str) \ + if ( level == var )\ +return str; + +static inline const char* _gst_err_cat( GstDebugLevel level) +{ + + RET_GST_ERR_STR(level,GST_LEVEL_NONE,""); + RET_GST_ERR_STR(level,GST_LEVEL_ERROR,"E "); + RET_GST_ERR_STR(level,GST_LEVEL_WARNING,"W "); + RET_GST_ERR_STR(level,GST_LEVEL_INFO,"I "); + RET_GST_ERR_STR(level,GST_LEVEL_DEBUG,"D "); + RET_GST_ERR_STR(level,GST_LEVEL_LOG, "L "); + RET_GST_ERR_STR(level,GST_LEVEL_FIXME, "F "); + RET_GST_ERR_STR(level,GST_LEVEL_MEMDUMP, "M "); + return ""; +} +static inline const char* _str_aac_profile() +{ + if ( _aac_profile == 0) return "auto"; + if ( _aac_profile == 2) return "lc"; + if ( _aac_profile == 5) return "he"; + return "unknown"; +} + +static FILE* log_fp = 0; + +static void open_log_fp() +{ + if (!log_fp) + { + snprintf(rec_filename, REC_FILENAME_LEN, "C://Data//gst_br%d_c%d_sr%d_%s.log", _bitrate, _channels, _sample_rate, _str_aac_profile()); + + log_fp = fopen(rec_filename, "w"); + if (!log_fp) + return; + } +} + + +static void _gstLogFunction (GstDebugCategory *category, + GstDebugLevel level, + const gchar *file, + const gchar *function, + gint line, + GObject *object, + GstDebugMessage *message, + gpointer data) +{ + + // if ( (level != GST_LEVEL_ERROR) /*&& (level != GST_LEVEL_DEBUG)*/ && (level != GST_LEVEL_WARNING) ) + // return; + + open_log_fp(); + + fprintf(log_fp, "%s : %s \n", _gst_err_cat(level), gst_debug_message_get(message)); + fflush(log_fp); + +} +#endif // ENABLE_LOGS + +// Local Functions +static gboolean +bus_call (GstBus *bus, + GstMessage *msg, + gpointer data) +{ + + GMainLoop *loop = (GMainLoop *) data; + + open_log_fp(); + + fprintf(log_fp,"[msg] %s from %s\n", GST_MESSAGE_TYPE_NAME(msg), GST_MESSAGE_SRC_NAME (msg)); + + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_EOS: + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (GST_OBJECT (pipeline)); + g_main_loop_quit(loop); + break; + case GST_MESSAGE_ERROR: { + gchar *debug; + GError *err; + gst_message_parse_error (msg, &err, &debug); + fprintf(log_fp, "[ERROR] %s\n", debug); + g_free (debug); + g_error_free (err); + g_main_loop_quit(loop); + break; + } +#if 0 + case GST_MESSAGE_STATE_CHANGED: + { + GstState state; + // gst_element_get_state (GstElement * element, + // GstState * state, + // GstState * pending, + // GstClockTime timeout); + + gst_element_get_state(GST_ELEMENT(pipeline),&state,NULL,-1); + if(state == GST_STATE_PLAYING) + { + + } + + } + break; +#endif + default: + break; + } + + return TRUE; +} + + static gboolean +quit_loop (gpointer data) +{ + GST_DEBUG("quiting loop"); + gst_element_send_event (pipeline, gst_event_new_eos ()); + return TRUE; +} + + +static void parse_args(int argc, char** argv) +{ + + gint cur = 1; + while ( argv[cur] && cur < argc ) + { + if( !strcmp(argv[cur],"-br") ) _bitrate = atoi(argv[cur+1]); + else if( !strcmp(argv[cur],"-c") ) _channels = atoi(argv[cur+1]); + else if( !strcmp(argv[cur],"-sr") ) _sample_rate = atoi(argv[cur+1]); + else if( !strcmp(argv[cur],"-p") ) _aac_profile = atoi(argv[cur+1]); + else if( !strcmp(argv[cur],"-l") ) _enable_logs = atoi(argv[cur+1]); + else if( !strcmp(argv[cur],"-d") ) _record_duration = atoi(argv[cur+1]); + + cur+=2; + } +} + +// Currently unused, TODO merge all recording usecases in this app. +#if 0 +char gst_pipeline[4096]; + +static inline GstElement* __parse_wav_pipeline() +{ + snprintf(gst_pipeline, 4096, "devsoundsrc ! audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int)16, depth=(int)16, rate=(int)%d, channels=(int)%d, endianness=(int)1234 ! wavenc ! filesink location=C://Data//wav_c%d_sr%d.wav", + _sample_rate, _channels , _channels, _sample_rate ); + pipeline = gst_parse_launch( gst_pipeline,0); + return pipeline; +} +static inline GstElement* __get_wav_pipeline() +{ + GstCaps* caps; + GstElement *devsoundsrc,*filesink,*wavenc; + GError *error = NULL; + + pipeline = gst_pipeline_new ("pipeline"); + devsoundsrc = gst_element_factory_make ("devsoundsrc", "devsoundsrc"); + wavenc = gst_element_factory_make ("wavenc", "wavenc"); + filesink = gst_element_factory_make ("filesink", "filesink"); + + snprintf(rec_filename, REC_FILENAME_LEN, "C:\\\\data\\\\wav_c%d_sr%d.wav", _channels, _sample_rate); + g_object_set (G_OBJECT (filesink), "location", rec_filename, NULL); + + + GST_DEBUG("filtered linking..."); + + caps = gst_caps_new_simple ("audio/x-raw-int", + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, + "signed",G_TYPE_BOOLEAN, TRUE, + "endianness",G_TYPE_INT, G_BYTE_ORDER, + "rate", G_TYPE_INT, _sample_rate, + "channels", G_TYPE_INT, _channels, NULL); + + gst_bin_add_many (GST_BIN (pipeline), devsoundsrc, wavenc, filesink, NULL); + gst_element_link_filtered (devsoundsrc, wavenc, caps); + + + gst_element_link (wavenc, filesink); + gst_caps_unref (caps); + + return pipeline; + +} +#endif + +static inline GstElement* __get_aac_pipeline() +{ + GstCaps* caps; + GstElement *devsoundsrc,*filesink,*nokiaaacenc,*mp4mux; + GstPad *qtsinkpad,*aacencsrcpad; + + pipeline = gst_pipeline_new ("pipeline"); + devsoundsrc = gst_element_factory_make ("devsoundsrc", "devsoundsrc"); + nokiaaacenc = gst_element_factory_make ("nokiaaacenc", "nokiaaacenc"); + mp4mux = gst_element_factory_make ("mp4mux", "mp4mux"); + filesink = gst_element_factory_make ("filesink", "filesink"); + + snprintf(rec_filename, REC_FILENAME_LEN, "C:\\\\data\\\\rec-aac_br%d_c%d_sr%d_%s.mp4", _bitrate, _channels, _sample_rate, + _str_aac_profile()); + g_object_set (G_OBJECT (filesink), "location", rec_filename, NULL); + + //GST_DEBUG("set bitrate on aacenc"); + g_object_set (G_OBJECT (nokiaaacenc), "bitrate", _bitrate, NULL); + + //if ( _aac_profile ) + g_object_set (G_OBJECT (nokiaaacenc), "profile", _aac_profile, NULL); + + + GST_DEBUG("filtered linking..."); + + caps = gst_caps_new_simple ("audio/x-raw-int", + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, + "signed",G_TYPE_BOOLEAN, TRUE, + "endianness",G_TYPE_INT, G_BYTE_ORDER, + "rate", G_TYPE_INT, _sample_rate, + "channels", G_TYPE_INT, _channels, NULL); + + gst_bin_add_many (GST_BIN (pipeline), devsoundsrc, nokiaaacenc, mp4mux, filesink, NULL); + gst_element_link_filtered (devsoundsrc, nokiaaacenc, caps); + + qtsinkpad = gst_element_get_request_pad( mp4mux, "audio_%d"); + aacencsrcpad = gst_element_get_pad( nokiaaacenc, "src"); + if (gst_pad_link (aacencsrcpad,qtsinkpad) != GST_PAD_LINK_OK) { + + GST_ERROR("gst_pad_link (aacencsrcpad,qtsinkpad) failed"); + return NULL; + } + gst_element_link (mp4mux, filesink); + gst_caps_unref (caps); + + return pipeline; +} + +int main (int argc, char *argv[]) +{ + GMainLoop *loop; + + +#ifdef ENABLE_LOGS + if ( _enable_logs ) + setenv("GST_DEBUG","2",1); +#endif // ENABLE_LOGS + + gst_init (NULL, NULL); + + parse_args(argc, argv); + +#ifdef ENABLE_LOGS + if ( _enable_logs ) + gst_debug_add_log_function( _gstLogFunction, 0); +#endif // ENABLE_LOGS + + GST_DEBUG("args : br %d chans %d sr %d ", _bitrate, _channels, _sample_rate); + + loop = g_main_loop_new (NULL, FALSE); + + + //pipeline = __get_wav_pipeline(); + //pipeline = __parse_wav_pipeline(); + pipeline = __get_aac_pipeline(); + + + /* start playing */ + gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)), bus_call, loop); + // watchdog timer + //g_timeout_add (_record_duration * 1.5, quit_program, 0); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + g_timeout_add (_record_duration, quit_loop, loop); + + + g_main_loop_run (loop); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (GST_OBJECT (pipeline)); + +#ifdef ENABLE_LOGS + if ( _enable_logs ) + fclose(log_fp); +#endif // ENABLE_LOGS +} + + diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/examples/amr_record/group/amr_record.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/examples/amr_record/group/amr_record.mmp Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,84 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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. +* +* Description: +* +*/ + +#include + +TARGET amr_record.exe +TARGETTYPE EXE +UID 0 0x0AB22A00 + +EPOCHEAPSIZE 0x10000 0x100000 +#ifdef EKA2 +LANG SC +CAPABILITY All -Tcb +VENDORID VID_DEFAULT + +#endif + + + +MACRO HAVE_CONFIG_H + +USERINCLUDE /sf/mw/gstreamer/gst_plugins_symbian/gst/devsound +USERINCLUDE .. +USERINCLUDE ../libs/gst/base +USERINCLUDE ../gst +USERINCLUDE ../libs/gst/base +USERINCLUDE ../gst +USERINCLUDE ../../../../.. +USERINCLUDE ../../../../libs/gst/check +USERINCLUDE ../../../../gst +USERINCLUDE ../../../.. +USERINCLUDE ../../../../libs + +MW_LAYER_SYSTEMINCLUDE +OS_LAYER_LIBC_SYSTEMINCLUDE + +OS_LAYER_GLIB_SYSTEMINCLUDE +MW_LAYER_GSTREAMER_SYSTEMINCLUDE + + + +SOURCEPATH ../src + +SOURCE amr_record.c + + +LIBRARY euser.lib libc.lib +LIBRARY libpthread.lib +LIBRARY libdl.lib +LIBRARY libglib.lib +LIBRARY libgmodule.lib + +LIBRARY libgobject.lib +LIBRARY libgthread.lib +LIBRARY libm.lib +LIBRARY libz.lib +LIBRARY libgstreamer.lib +LIBRARY libgstbase.lib +LIBRARY libgstcontroller.lib +LIBRARY libgstdevsoundext.lib +LIBRARY SpeechEncoderConfig.lib + +STATICLIBRARY libcrt0.lib +//VENDORID VID_DEFAULT +SMPSAFE diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/examples/amr_record/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/examples/amr_record/group/bld.inf Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,33 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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. +* +* Description: +* +*/ + +PRJ_PLATFORMS +DEFAULT + +PRJ_TESTEXPORTS + + +PRJ_TESTMMPFILES +amr_record.mmp + + + diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/examples/amr_record/src/amr_record.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/examples/amr_record/src/amr_record.c Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,240 @@ + +#include +#include +#include +#include +#include +#define LOG_FILE "c:\\logs\\amr_record_logs.txt" +#include "std_log_result.h" +#include +#define LOG_FILENAME_LINE __FILE__, __LINE__ +#define LOG_FILENAME_LEN 256 +#define _DEBUG 1 + +static char log_filename[LOG_FILENAME_LEN]; + +static guint bitrate = 0; +static guint record_duration = 10000; +static guint _enable_logs = 0; + +static GstSpeechEncoderConfigIntfc* iface; + + +#define ENABLE_LOGS + +#ifdef ENABLE_LOGS +#define RET_GST_ERR_STR(var, level, str) \ + if ( level == var )\ +return str; + +static inline const char* _gst_err_cat( GstDebugLevel level) +{ + + RET_GST_ERR_STR(level,GST_LEVEL_NONE,""); + RET_GST_ERR_STR(level,GST_LEVEL_ERROR,"E "); + RET_GST_ERR_STR(level,GST_LEVEL_WARNING,"W "); + RET_GST_ERR_STR(level,GST_LEVEL_INFO,"I "); + RET_GST_ERR_STR(level,GST_LEVEL_DEBUG,"D "); + RET_GST_ERR_STR(level,GST_LEVEL_LOG, "L "); + RET_GST_ERR_STR(level,GST_LEVEL_FIXME, "F "); + RET_GST_ERR_STR(level,GST_LEVEL_MEMDUMP, "M "); + return ""; +} + +static FILE* log_fp = 0; + +static void open_log_fp() +{ + if (!log_fp) + { + snprintf(log_filename, LOG_FILENAME_LEN, "C:\\logs\\testframework\\gst_amr_br%d.log", bitrate); + + log_fp = fopen(log_filename, "w"); + if (!log_fp) + return; + } +} + + +static void _gstLogFunction (GstDebugCategory *category, + GstDebugLevel level, + const gchar *file, + const gchar *function, + gint line, + GObject *object, + GstDebugMessage *message, + gpointer data) +{ + open_log_fp(); + + fprintf(log_fp, "%s : %s \n", _gst_err_cat(level), gst_debug_message_get(message)); + fflush(log_fp); + +} +#endif // ENABLE_LOGS + +static void parse_args(int argc, char** argv) +{ + + gint cur = 1; + while ( argv[cur] && cur < argc ) + { + GST_WARNING("br:%d, record_duration:%d \n",bitrate,record_duration); + if( !strcmp(argv[cur],"-br") ) bitrate = atoi(argv[cur+1]); + else if( !strcmp(argv[cur],"-l") ) _enable_logs = atoi(argv[cur+1]); + else if( !strcmp(argv[cur],"-d") ) record_duration = atoi(argv[cur+1]); + + cur+=2; + } +} + + +GstElement *pipeline, *source, *amrmux,*sink; +GstBus *bus; +GMainLoop *loop; + +static gboolean +bus_call (GstBus *bus, + GstMessage *msg, + gpointer data) + { +#ifdef ENABLE_LOGS + if(_enable_logs) + { + open_log_fp(); + fprintf(log_fp,"[msg] %s from %s\n", GST_MESSAGE_TYPE_NAME(msg), GST_MESSAGE_SRC_NAME (msg)); + } +#endif + + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_EOS: + gst_element_set_state (pipeline, GST_STATE_NULL); + g_main_loop_quit(loop); + gst_object_unref (GST_OBJECT (pipeline)); + break; + + case GST_MESSAGE_ERROR: { + gchar *debug; + GError *err; + gst_message_parse_error (msg, &err, &debug); + g_free (debug); + g_print ("Error: %s\n", err->message); + g_error_free (err); + break; + } + default: + break; + } + + return TRUE; + } + +static gboolean +quit_loop (gpointer data) +{ + GST_WARNING("Sending EOS\n"); + gst_element_send_event (pipeline, gst_event_new_eos ()); + return TRUE; +} + +int main (int argc, char *argv[]) +{ + char filename[1024]; + GstCaps* caps; +#ifdef ENABLE_LOGS + if ( _enable_logs ) + setenv("GST_DEBUG","2",1); +#endif // ENABLE_LOGS + + parse_args(argc,argv); + + gst_init (&argc, &argv); +#ifdef ENABLE_LOGS + if ( _enable_logs ) + gst_debug_add_log_function( _gstLogFunction, 0); +#endif // ENABLE_LOGS + + loop = g_main_loop_new (NULL, FALSE); + + /* create elements */ + pipeline = gst_pipeline_new ("audio-player"); + source = gst_element_factory_make ("devsoundsrc", "audio-source"); + amrmux = gst_element_factory_make ("amrmux", "amrmux"); + sink = gst_element_factory_make ("filesink", "sink"); + + if (!pipeline || !source || !amrmux || !sink) { + g_print ("One element could not be created\n"); + GST_ERROR("One element could not be created\n"); + return -1; + } + if(bitrate > 0) + { + snprintf(filename, 1024, "C:\\data\\amr_record_%d.amr", bitrate ); + } + else + { + snprintf(filename, 1024, "C:\\data\\amr_record.amr" ); + } + + /* set filename property on the file source. Also add a message handler. */ + g_object_set (G_OBJECT (sink), "location", filename, NULL); + /* put all elements in a bin */ + gst_bin_add_many (GST_BIN (pipeline),source, amrmux,sink, NULL); + + caps = gst_caps_new_simple ("audio/amr", + "width", G_TYPE_INT, 8, + "depth", G_TYPE_INT, 8, + "signed",G_TYPE_BOOLEAN, TRUE, + "endianness",G_TYPE_INT, G_BYTE_ORDER, + "rate", G_TYPE_INT, 8000, + "channels", G_TYPE_INT, 1, NULL); + + if(!gst_element_link_filtered (source, amrmux, caps)) + { + GST_ERROR("Linking source, amrmux failed\n"); + return -1; + } + + if(!gst_element_link (amrmux, sink)) + { + GST_ERROR("Linking amrmux,sink failed\n"); + return -1; + } + + gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)), bus_call, loop); + iface = GST_SPEECH_ENCODER_CONFIG_GET_IFACE(source); + if(!iface) + { + GST_ERROR("Speech Encoder Interface NULL \n"); + return -1; + } + if (bitrate > 0) + { + GST_WARNING("Setting bitrate %d \n",bitrate); + iface->SetBitrate(bitrate); + } + + /* Now set to playing and iterate. */ + g_print ("Setting to PLAYING\n"); + GST_WARNING("Setting to Playing \n"); + gst_element_set_state (pipeline, GST_STATE_PLAYING); + iface->GetBitrate(&bitrate); + + g_timeout_add (record_duration, quit_loop, loop); + + g_main_loop_run (loop); + /* clean up nicely */ + GST_WARNING("Returned, stopping playback\n"); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (GST_OBJECT (pipeline)); + +#ifdef ENABLE_LOGS + if ( _enable_logs ) + fclose(log_fp); +#endif // ENABLE_LOGS + + g_print ("completed playing audio\n"); + return 0; +} + diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/examples/group/bld.inf --- a/gstreamer_core/tsrc/examples/group/bld.inf Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_core/tsrc/examples/group/bld.inf Fri Aug 06 16:36:50 2010 -0500 @@ -19,7 +19,10 @@ * Description: * */ +#include "../amr_record/group/bld.inf" +#include "../wav_record/group/bld.inf" +#include "../aac_record/group/bld.inf" #include "../gstseek/group/bld.inf" #include "../helloworld/group/bld.inf" #include "../controller/group/bld.inf" diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/examples/gstseek/src/gstseek.c --- a/gstreamer_core/tsrc/examples/gstseek/src/gstseek.c Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_core/tsrc/examples/gstseek/src/gstseek.c Fri Aug 06 16:36:50 2010 -0500 @@ -62,6 +62,26 @@ return TRUE; } +static gboolean cb_autoplug( GstBin * *bin, + GstPad *pad, + GstCaps *caps, + gpointer user_data) +{ + GstCaps* sinkcaps = NULL; + gboolean supported = FALSE; + + GstPad* sinkpad = gst_element_get_pad( sink, "sink"); + sinkcaps = gst_pad_get_caps( sinkpad ); + supported = gst_caps_is_subset( caps, sinkcaps ); + + if( supported ) + { + //link_with_devsoundsink = TRUE; + return FALSE; + } + return TRUE; +} + static void cb_newpad (GstElement *decodebin, GstPad *pad, @@ -191,7 +211,7 @@ gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)), bus_call, loop); g_signal_connect (decoder, "new-decoded-pad", G_CALLBACK (cb_newpad), NULL); - //g_signal_connect (decoder, "autoplug-continue", G_CALLBACK (cb_autoplug), NULL); + g_signal_connect (decoder, "autoplug-continue", G_CALLBACK (cb_autoplug), NULL); g_timeout_add (1000/*in mili sec*/, (GSourceFunc) cb_get_position, NULL); diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/examples/wav_record/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/examples/wav_record/group/bld.inf Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,33 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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. +* +* Description: +* +*/ + +PRJ_PLATFORMS +DEFAULT + +PRJ_TESTEXPORTS + + +PRJ_TESTMMPFILES +wav_record.mmp + + + diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/examples/wav_record/group/wav_record.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/examples/wav_record/group/wav_record.mmp Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,82 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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. +* +* Description: +* +*/ + +#include + +TARGET wav_record.exe +TARGETTYPE EXE +UID 0 0x055311c3 + +EPOCHEAPSIZE 0x10000 0x100000 +#ifdef EKA2 +LANG SC +CAPABILITY All -Tcb +VENDORID VID_DEFAULT + +#endif + + + +MACRO HAVE_CONFIG_H + + +USERINCLUDE .. +USERINCLUDE ../libs/gst/base +USERINCLUDE ../gst +USERINCLUDE ../libs/gst/base +USERINCLUDE ../gst +USERINCLUDE ../../../../.. +USERINCLUDE ../../../../libs/gst/check +USERINCLUDE ../../../../gst +USERINCLUDE ../../../.. +USERINCLUDE ../../../../libs + +MW_LAYER_SYSTEMINCLUDE +OS_LAYER_LIBC_SYSTEMINCLUDE + +OS_LAYER_GLIB_SYSTEMINCLUDE +MW_LAYER_GSTREAMER_SYSTEMINCLUDE + + + +SOURCEPATH ../src + +SOURCE wav_record.c + + +LIBRARY euser.lib libc.lib +LIBRARY libpthread.lib +LIBRARY libdl.lib +LIBRARY libglib.lib +LIBRARY libgmodule.lib + +LIBRARY libgobject.lib +LIBRARY libgthread.lib +LIBRARY libm.lib +LIBRARY libz.lib +LIBRARY libgstreamer.lib +LIBRARY libgstbase.lib +LIBRARY libgstcontroller.lib + +STATICLIBRARY libcrt0.lib +//VENDORID VID_DEFAULT +SMPSAFE diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/examples/wav_record/src/wav_record.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/examples/wav_record/src/wav_record.c Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,148 @@ + +#include +#include +#include +#include +#include +#define LOG_FILE "c:\\logs\\wav_record_logs.txt" +#include "std_log_result.h" +#define LOG_FILENAME_LINE __FILE__, __LINE__ + +void create_xml(int result) +{ + + if(result) + { + assert_failed = 1; + } + + testResultXml(xmlfile); + close_log_file(); + + if(result) + { + exit (-1); + } + +} + +GstElement *pipeline, *source, *wavenc,*sink; +GstBus *bus; +GMainLoop *loop; + +static gboolean +bus_call (GstBus *bus, + GstMessage *msg, + gpointer data) +{ + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_EOS: + gst_element_set_state (pipeline, GST_STATE_NULL); + g_main_loop_quit(loop); + gst_object_unref (GST_OBJECT (pipeline)); + //std_log(LOG_FILENAME_LINE, "Test Successful"); + create_xml(0); + break; + case GST_MESSAGE_ERROR: { + gchar *debug; + GError *err; + gst_message_parse_error (msg, &err, &debug); + g_free (debug); + g_print ("Error: %s\n", err->message); + g_error_free (err); + //std_log(LOG_FILENAME_LINE, "Test Failed"); + create_xml(1); + break; + } + default: + break; + } + + return TRUE; +} + +static gboolean +quit_loop (gpointer data) +{ + gst_element_send_event (pipeline, gst_event_new_eos ()); + +} + + +/// exe name record_duration sampling_rate chans width +int main (int argc, char *argv[]) +{ + char filename[1024]; + GstCaps* caps; + int sampling_rate = 8000; + int chans = 1; + int width = 16; + guint record_duration = 10000; + + if (argc > 1) { + record_duration = (guint) atoi( argv[1] ) * 1000; + } + + if (argc > 2) { + sampling_rate = (int) atoi( argv[2] ); + } + + if (argc > 3) { + chans = (int) atoi( argv[3] ); + } + + if (argc > 4) { + width = (int) atoi( argv[4] ); + } + + + gst_init (&argc, &argv); + loop = g_main_loop_new (NULL, FALSE); + + /* create elements */ + pipeline = gst_pipeline_new ("audio-player"); + source = gst_element_factory_make ("devsoundsrc", "audio-source"); + wavenc = gst_element_factory_make ("wavenc", "mp3parse"); + sink = gst_element_factory_make ("filesink", "sink"); + + if (!pipeline || !source || !wavenc || !sink) { + g_print ("One element could not be created\n"); + return -1; + } + snprintf(filename, 1024, "C:\\data\\wav_record_samp-%d-chans-%d-duration-%dsec.wav", + sampling_rate, chans,record_duration/1000 ); + + /* set filename property on the file source. Also add a message handler. */ + g_object_set (G_OBJECT (sink), "location", filename, NULL); + /* put all elements in a bin */ + gst_bin_add_many (GST_BIN (pipeline),source, wavenc,sink, NULL); + + caps = gst_caps_new_simple ("audio/x-raw-int", + "width", G_TYPE_INT, width, + "depth", G_TYPE_INT, width, + "signed",G_TYPE_BOOLEAN, TRUE, + "endianness",G_TYPE_INT, G_BYTE_ORDER, + "rate", G_TYPE_INT, sampling_rate, + "channels", G_TYPE_INT, chans, NULL); + + gst_element_link_filtered (source, wavenc, caps); + gst_element_link (wavenc, sink); + + gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)), bus_call, loop); + //g_signal_connect (decoder, "pad-added", G_CALLBACK (new_pad_cb),pipeline); + /* Now set to playing and iterate. */ + g_print ("Setting to PLAYING\n"); + gst_element_set_state (pipeline, GST_STATE_PLAYING); + g_timeout_add (record_duration, quit_loop, loop); + g_print ("Running\n"); + g_main_loop_run (loop); + /* clean up nicely */ + g_print ("Returned, stopping playback\n"); + gst_element_set_state (pipeline, GST_STATE_NULL); + g_print ("Deleting pipeline\n"); + gst_object_unref (GST_OBJECT (pipeline)); + + g_print ("completed palying audio\n"); + return 0; +} + diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/group/bld.inf --- a/gstreamer_core/tsrc/group/bld.inf Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_core/tsrc/group/bld.inf Fri Aug 06 16:36:50 2010 -0500 @@ -26,6 +26,6 @@ //#include "../gstreamertestcases_suite1/group/bld.inf" //#include "../gstreamertestcases_suite2/group/bld.inf" //#include "../gstreamertestcases_suite3/group/bld.inf" - +//#include "../gstreamertestcases_suite4/group/bld.inf" // End of File diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases/group/bld.inf --- a/gstreamer_core/tsrc/gstreamertestcases/group/bld.inf Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_core/tsrc/gstreamertestcases/group/bld.inf Fri Aug 06 16:36:50 2010 -0500 @@ -32,7 +32,7 @@ // 'abld test export' ../conf/GstreamerTestCases.cfg /epoc32/winscw/c/TestFramework/GstreamerTestCases.cfg -../init/GstreamerTestCases.ini /epoc32/winscw/c/TestFramework/GstreamerTestCases.ini +../init/gstreamertestcases.ini /epoc32/winscw/c/TestFramework/gstreamertestcases.ini ../init/testframework.ini /epoc32/winscw/c/TestFramework/testframework.ini PRJ_EXPORTS diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite3/conf/gstreamertestcases_suite3.cfg --- a/gstreamer_core/tsrc/gstreamertestcases_suite3/conf/gstreamertestcases_suite3.cfg Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_core/tsrc/gstreamertestcases_suite3/conf/gstreamertestcases_suite3.cfg Fri Aug 06 16:36:50 2010 -0500 @@ -183,7 +183,7 @@ /* playback testing */ - +/* [Test] title launch.exe AAC_8k_64kbps_mono_Queen.aac create gstreamertestcases_suite3 foobar @@ -379,7 +379,6 @@ [Endtest] -/* [Test] title launch.exe f:\data\MP3_11.025k_40kbps_mono_Test2.mp3 create gstreamertestcases_suite3 foobar @@ -642,7 +641,7 @@ foobar SetTimeout 20 delete foobar [Endtest] - +*/ /* file is not proper so commented. [Test] @@ -653,7 +652,7 @@ delete foobar [Endtest] */ - +/* [Test] title launch.exe EAAC Reliabity testcase create gstreamertestcases_suite3 foobar diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite4/Bwins/gstreamertestcases_suite4u.def --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/gstreamertestcases_suite4/Bwins/gstreamertestcases_suite4u.def Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,3 @@ +EXPORTS + ?LibEntryL@@YAPAVCScriptBase@@AAVCTestModuleIf@@@Z @ 1 NONAME ; class CScriptBase * LibEntryL(class CTestModuleIf &) + diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite4/EABI/gstreamertestcases_suite4u.def --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/gstreamertestcases_suite4/EABI/gstreamertestcases_suite4u.def Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,3 @@ +EXPORTS + _Z9LibEntryLR13CTestModuleIf @ 1 NONAME + diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite4/conf/gstreamertestcases_suite4.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/gstreamertestcases_suite4/conf/gstreamertestcases_suite4.cfg Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,280 @@ +/* +[Test] +title aac rec 16Kbps 8KHz +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 16000 -sr 8000 +delete foobar +[Endtest] + +[Test] +title aac rec 32Kbps 8KHz LC 20Secs +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 32000 -sr 8000 -p 2 -l 0 -d 20000 +delete foobar +[Endtest] + +[Test] +title aac rec 128Kbps 8KHz Auto 10Secs +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 128000 -sr 8000 -p 0 -l 0 -d 10000 +delete foobar +[Endtest] + +[Test] +title aac rec 128Kbps 11025Hz LC +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 128000 -sr 11025 -p 2 -l 0 +delete foobar +[Endtest] + +[Test] +title aac rec 64Kbps 16KHz LC 40Secs +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 64000 -sr 16000 -p 2 -l 0 -d 40000 +delete foobar +[Endtest] + +[Test] +title aac rec 96Kbps 16KHz Auto 20Secs +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 96000 -sr 16000 -p 0 -l 0 -d 20000 +delete foobar +[Endtest] + +[Test] +title aac rec 256Kbps 16KHz HE +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 256000 -sr 16000 -p 5 -l 0 +delete foobar +[Endtest] + +[Test] +title aac rec 128Kbps 22050Hz LC +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 128000 -sr 22050 -p 2 -l 0 +delete foobar +[Endtest] + +[Test] +title aac rec 128Kbps 32KHz LC +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 128000 -sr 32000 -p 2 -l 0 +delete foobar +[Endtest] + +[Test] +title aac rec 160Kbps 32KHz Auto +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 160000 -sr 32000 -p 0 -l 0 +delete foobar +[Endtest] + +[Test] +title aac rec 224Kbps 32KHz HE 30Secs +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 224000 -sr 32000 -p 5 -l 0 -d 30000 +delete foobar +[Endtest] + +[Test] +title aac rec 256Kbps 44100Hz 2 chan Auto +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 256000 -sr 44100 -c 2 -p 0 -l 0 +delete foobar +[Endtest] + +[Test] +title aac rec 224Kbps 48KHz 2chan LC +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 224000 -sr 48000 -c 2 -p 2 -l 0 +delete foobar +[Endtest] + +[Test] +title aac rec 128Kbps 48KHz 2chan HE +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 128000 -sr 48000 -c 2 -p 5 -l 0 +delete foobar +[Endtest] + +[Test] +title aac rec 192Kbps 48KHz HE +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 192000 -sr 48000 -p 5 -l 0 +delete foobar +[Endtest] + +[Test] +title aac rec 160Kbps 32KHz HE +create gstreamertestcases_suite4 foobar +foobar Example aac_record.exe -br 160000 -sr 32000 -p 5 -l 0 +delete foobar +[Endtest] + +[Test] +title amr_record default +create gstreamertestcases_suite4 foobar +foobar Example amr_record.exe +delete foobar +[Endtest] + +[Test] +title amr_record 4.75Kbps 20sec +create gstreamertestcases_suite4 foobar +foobar Example amr_record.exe -br 4750 -l 0 -d 20000 +delete foobar +[Endtest] + +[Test] +title amr_record 5.15Kbps 20sec +create gstreamertestcases_suite4 foobar +foobar Example amr_record.exe -br 5150 -l 0 -d 20000 +delete foobar +[Endtest] + +[Test] +title amr_record 5.9Kbps 20sec +create gstreamertestcases_suite4 foobar +foobar Example amr_record.exe -br 5900 -l 0 -d 20000 +delete foobar +[Endtest] + +[Test] +title amr_record 6.7Kbps 20sec +create gstreamertestcases_suite4 foobar +foobar Example amr_record.exe -br 6700 -l 0 -d 20000 +delete foobar +[Endtest] + +[Test] +title amr_record 7.4Kbps 20sec +create gstreamertestcases_suite4 foobar +foobar Example amr_record.exe -br 7400 -l 0 -d 20000 +delete foobar +[Endtest] + +[Test] +title amr_record 7.95Kbps 20sec +create gstreamertestcases_suite4 foobar +foobar Example amr_record.exe -br 7950 -l 0 -d 20000 +delete foobar +[Endtest] + +[Test] +title amr_record 10.2Kbps 20sec +create gstreamertestcases_suite4 foobar +foobar Example amr_record.exe -br 10200 -l 0 -d 20000 +delete foobar +[Endtest] + +[Test] +title amr_record 12.2Kbps 20sec +create gstreamertestcases_suite4 foobar +foobar Example amr_record.exe -br 12200 -l 0 -d 20000 +delete foobar +[Endtest] + +[Test] +title amr_record 5Kbps 20sec +create gstreamertestcases_suite4 foobar +foobar Example amr_record.exe -br 5000 -l 0 -d 20000 +delete foobar +[Endtest] + +[Test] +title amr_record 8Kbps 20sec +create gstreamertestcases_suite4 foobar +foobar Example amr_record.exe -br 8000 -l 0 -d 20000 +delete foobar +[Endtest] + +[Test] +title wav_record.exe default +create gstreamertestcases_suite4 foobar +foobar Example wav_record.exe +delete foobar +[Endtest] + +[Test] +title wav_record.exe 10 8000 1 16 +create gstreamertestcases_suite4 foobar +foobar Example wav_record.exe 10 8000 1 16 +delete foobar +[Endtest] + +[Test] +title wav_record.exe 10 8000 2 16 +create gstreamertestcases_suite4 foobar +foobar Example wav_record.exe 10 8000 2 16 +delete foobar +[Endtest] +*/ + +/*[Test] +title wav_record.exe 10 16000 1 16 +create gstreamertestcases_suite4 foobar +foobar Example wav_record.exe 10 16000 1 16 +delete foobar +[Endtest] + + +[Test] +title wav_record.exe 10 16000 2 16 +create gstreamertestcases_suite4 foobar +foobar Example wav_record.exe 10 16000 2 16 +delete foobar +[Endtest] +*/ +/* +[Test] +title wav_record.exe 10 24000 1 16 +create gstreamertestcases_suite4 foobar +foobar Example wav_record.exe 10 24000 1 16 +delete foobar +[Endtest] + + +[Test] +title wav_record.exe 10 24000 2 16 +create gstreamertestcases_suite4 foobar +foobar Example wav_record.exe 10 24000 2 16 +delete foobar +[Endtest] + + +[Test] +title wav_record.exe 10 32000 1 16 +create gstreamertestcases_suite4 foobar +foobar Example wav_record.exe 10 32000 1 16 +delete foobar +[Endtest] + + +[Test] +title wav_record.exe 10 32000 2 16 +create gstreamertestcases_suite4 foobar +foobar Example wav_record.exe 10 32000 2 16 +delete foobar +[Endtest] + + +[Test] +title wav_record.exe 10 48000 1 16 +create gstreamertestcases_suite4 foobar +foobar Example wav_record.exe 10 48000 1 16 +delete foobar +[Endtest] + + +[Test] +title wav_record.exe 10 48000 2 16 +create gstreamertestcases_suite4 foobar +foobar Example wav_record.exe 10 48000 2 16 +delete foobar +[Endtest] + + +*/ + + + diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite4/data/khuda.wav Binary file gstreamer_core/tsrc/gstreamertestcases_suite4/data/khuda.wav has changed diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite4/group/GstreamerTestCases_DoxyFile.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/gstreamertestcases_suite4/group/GstreamerTestCases_DoxyFile.txt Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,246 @@ +# +# +# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser 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. +# +# Description: +# +# +# + +# Doxyfile 1.4.1 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = GstreamerTestCases +PROJECT_NUMBER = +OUTPUT_DIRECTORY = \GstreamerTestCases\ +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = YES +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = YES +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = NO +GENERATE_TESTLIST = NO +GENERATE_BUGLIST = NO +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = \GstreamerTestCases\ +FILE_PATTERNS = *.h \ + *.rh \ + *.hrh +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = NO +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = YES +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = YES +TOC_EXPAND = YES +DISABLE_INDEX = YES +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = YES +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = YES +RTF_OUTPUT = Doc +COMPACT_RTF = YES +RTF_HYPERLINKS = YES +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = NONSHARABLE_CLASS +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite4/group/GstreamerTestCases_suite4.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/gstreamertestcases_suite4/group/GstreamerTestCases_suite4.mmp Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,81 @@ +/*TYPE TESTCLASS*/ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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. +* +* Description: +* +*/ + + +#include + +TARGET gstreamertestcases_suite4.dll +TARGETTYPE dll +UID 0x1000008D 0x101FB7E7 + +CAPABILITY ALL -TCB + +/* Remove comments and replace 0x00000000 with correct vendor id */ +// VENDORID 0x00000000 +/* Remove comments and replace 0x00000000 with correct secure id */ +// SECUREID 0x00000000 + +//TARGETPATH ?target_path +//DEFFILE GstreamerTestCases.def + +USERINCLUDE ../inc + +OS_LAYER_SYSTEMINCLUDE + +SOURCEPATH ../src + +SOURCE GstreamerTestCases.cpp +SOURCE GstreamerTestCasesBlocks.cpp + +//RESOURCE resource_file +//RESOURCE resource_file2 + +LIBRARY euser.lib +LIBRARY stiftestinterface.lib +LIBRARY stiftestengine.lib + +LANG SC + +/* +START WINS +?wins_specific_information +END + +START MARM +?marm_specific_information +END +*/ +// Other possible keywords: + +// DOCUMENT ?file, that is not compiled, but added to MSVC project workspace (i.e. release notes) +/* +START BITMAP ?target +TARGETPATH ?emulated_path_on_target_machine +HEADER +SOURCE ?color_depth ?source_bitmap +END +*/ +// DEFFILE ?filename +// AIF ?filename + +// End of File diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite4/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/gstreamertestcases_suite4/group/bld.inf Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,66 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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. +* +* Description: +* +*/ + + +PRJ_PLATFORMS +// specify the platforms your component needs to be built for here +// defaults to WINS MARM so you can ignore this if you just build these + + DEFAULT + +PRJ_TESTEXPORTS +// NOTE: If using ARS requirements all export operations should be done under this. +// 'abld test export' +../conf/gstreamertestcases_suite4.cfg /epoc32/winscw/c/TestFramework/gstreamertestcases_suite4.cfg +../init/gstreamertestcases_suite4.ini /epoc32/winscw/c/TestFramework/gstreamertestcases_suite4.ini +../init/testframework.ini /epoc32/winscw/c/TestFramework/testframework.ini + + + + +PRJ_EXPORTS +// Specify the source file followed by its destination here +// copy will be used to copy the source file to its destination +// If there's no destination then the source file will be copied +// to the same name in /epoc32/include +// Example: + + +PRJ_TESTMMPFILES + + GstreamerTestCases_suite4.mmp + +PRJ_MMPFILES +//GstreamerTestCases_suite4.mmp + + // GstreamerTestCases_nrm.mmp + +// Specify the .mmp files required for building the important component +// releasables. +// +// Specify "tidy" if the component you need to build doesn't need to be +// released. Specify "ignore" if the MMP file exists but should be +// ignored. +// Example: + + +// End of File diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite4/group/gstreamer_testcases.pkg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/gstreamertestcases_suite4/group/gstreamer_testcases.pkg Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,169 @@ +; ============================================================================ +; Name : gstreamer_testcases.pkg +; Part of : Gstreamer project +; Description : Package file for all gstreamer test binaries +; +; Version : %version: bh1mmcf#3 % +; +; Copyright © 2002-2006 Nokia. All rights reserved. +; This material, including documentation and any related computer +; programs, is protected by copyright controlled by Nokia. All +; rights are reserved. Copying, including reproducing, storing, +; adapting or translating, any or all of this material requires the +; prior written consent of Nokia. This material also contains +; confidential information which may not be disclosed to others +; without the prior written consent of Nokia. +; ============================================================================ + +;Languages +&EN + +;Header +#{"gstreamer_testcases.pkg"},(0x2001F45C),1,0,0, TYPE=SU + +;Supports S60 3.0 +[0x101F7961], 0, 0, 0, {"S60ProductID"} + +;Localised Vendor name +%{"Nokia Testing EN"} + +;Unique Vendor name +:"Vendor" + + +;gstreamer dll + +"\epoc32\winscw\c\gstreamer\plugins_list\gst_dll_2001F41F.txt" - "c:\gstreamer\plugins_list\gst_dll_2001F41F.txt" +"\epoc32\release\armv5\urel\gstreamertestcases_suite4.dll"-"!:\sys\bin\gstreamertestcases_suite4.dll" + +;gstregistry exe + +"\epoc32\release\armv5\urel\GSTRegistryGenerator.exe" -"!:\sys\bin\GSTRegistryGenerator.exe",FR,RI + +;gstreamer-core test exe's + +"\epoc32\release\armv5\urel\cleanup.exe"-"!:\sys\bin\cleanup.exe" +"\epoc32\release\armv5\urel\createelementcore.exe"-"!:\sys\bin\createelementcore.exe" +"\epoc32\release\armv5\urel\element_gstfakesink.exe"-"!:\sys\bin\element_gstfakesink.exe" +"\epoc32\release\armv5\urel\element_gstfakesrc.exe"-"!:\sys\bin\element_gstfakesrc.exe" +"\epoc32\release\armv5\urel\element_gstfdsrc.exe"-"!:\sys\bin\element_gstfdsrc.exe" +"\epoc32\release\armv5\urel\element_gstfilesink.exe"-"!:\sys\bin\element_gstfilesink.exe" +"\epoc32\release\armv5\urel\element_gstfilesrc.exe"-"!:\sys\bin\element_gstfilesrc.exe" +"\epoc32\release\armv5\urel\element_gstidentity.exe"-"!:\sys\bin\element_gstidentity.exe" +"\epoc32\release\armv5\urel\element_gstmultiqueue.exe"-"!:\sys\bin\element_gstmultiqueue.exe" +"\epoc32\release\armv5\urel\element_gstqueue.exe"-"!:\sys\bin\element_gstqueue.exe" +"\epoc32\release\armv5\urel\element_gsttee.exe"-"!:\sys\bin\element_gsttee.exe" +"\epoc32\release\armv5\urel\gst.exe"-"!:\sys\bin\gst.exe" +"\epoc32\release\armv5\urel\gstadapter.exe"-"!:\sys\bin\gstadapter.exe" +"\epoc32\release\armv5\urel\gstbasesrc.exe"-"!:\sys\bin\gstbasesrc.exe" +"\epoc32\release\armv5\urel\gstbin.exe"-"!:\sys\bin\gstbin.exe" +"\epoc32\release\armv5\urel\gstbuffer.exe"-"!:\sys\bin\gstbuffer.exe" +"\epoc32\release\armv5\urel\gstbus.exe"-"!:\sys\bin\gstbus.exe" +"\epoc32\release\armv5\urel\gstcaps.exe"-"!:\sys\bin\gstcaps.exe" +"\epoc32\release\armv5\urel\gstcollectpads.exe"-"!:\sys\bin\gstcollectpads.exe" +"\epoc32\release\armv5\urel\gstcontroller.exe"-"!:\sys\bin\gstcontroller.exe" +"\epoc32\release\armv5\urel\gstelement.exe"-"!:\sys\bin\gstelement.exe" +"\epoc32\release\armv5\urel\gstevent.exe"-"!:\sys\bin\gstevent.exe" +"\epoc32\release\armv5\urel\gstgdp.exe"-"!:\sys\bin\gstgdp.exe" +"\epoc32\release\armv5\urel\gstghostpad.exe"-"!:\sys\bin\gstghostpad.exe" +"\epoc32\release\armv5\urel\gstgstnetclientclock.exe"-"!:\sys\bin\gstgstnetclientclock.exe" +"\epoc32\release\armv5\urel\gstgstnettimeprovider.exe"-"!:\sys\bin\gstgstnettimeprovider.exe" +"\epoc32\release\armv5\urel\gstindex.exe"-"!:\sys\bin\gstindex.exe" +"\epoc32\release\armv5\urel\gstinterface.exe"-"!:\sys\bin\gstinterface.exe" +"\epoc32\release\armv5\urel\gstiterator.exe"-"!:\sys\bin\gstiterator.exe" +"\epoc32\release\armv5\urel\gstlibsabi.exe"-"!:\sys\bin\gstlibsabi.exe" +"\epoc32\release\armv5\urel\gstmessage.exe"-"!:\sys\bin\gstmessage.exe" +"\epoc32\release\armv5\urel\gstminiobject.exe"-"!:\sys\bin\gstminiobject.exe" +"\epoc32\release\armv5\urel\gstobject.exe"-"!:\sys\bin\gstobject.exe" +"\epoc32\release\armv5\urel\gstpad.exe"-"!:\sys\bin\gstpad.exe" +"\epoc32\release\armv5\urel\gstparamspecs.exe"-"!:\sys\bin\gstparamspecs.exe" +"\epoc32\release\armv5\urel\gstpipeline.exe"-"!:\sys\bin\gstpipeline.exe" +"\epoc32\release\armv5\urel\gstplugin.exe"-"!:\sys\bin\gstplugin.exe" +"\epoc32\release\armv5\urel\gstpoll.exe"-"!:\sys\bin\gstpoll.exe" +"\epoc32\release\armv5\urel\gstquery.exe"-"!:\sys\bin\gstquery.exe" +"\epoc32\release\armv5\urel\gstregistry.exe"-"!:\sys\bin\gstregistry.exe" +"\epoc32\release\armv5\urel\gstsegment.exe"-"!:\sys\bin\gstsegment.exe" +"\epoc32\release\armv5\urel\gstsinks.exe"-"!:\sys\bin\gstsinks.exe" +"\epoc32\release\armv5\urel\gststates.exe"-"!:\sys\bin\gststates.exe" +"\epoc32\release\armv5\urel\gststructure.exe"-"!:\sys\bin\gststructure.exe" +"\epoc32\release\armv5\urel\gstsystemclock.exe"-"!:\sys\bin\gstsystemclock.exe" +"\epoc32\release\armv5\urel\gsttag.exe"-"!:\sys\bin\gsttag.exe" +"\epoc32\release\armv5\urel\gsttagsetter.exe"-"!:\sys\bin\gsttagsetter.exe" +"\epoc32\release\armv5\urel\gsttask.exe"-"!:\sys\bin\gsttask.exe" +"\epoc32\release\armv5\urel\gsttypefindhelper.exe"-"!:\sys\bin\gsttypefindhelper.exe" +"\epoc32\release\armv5\urel\gsturi.exe"-"!:\sys\bin\gsturi.exe" +"\epoc32\release\armv5\urel\gstutils.exe"-"!:\sys\bin\gstutils.exe" +"\epoc32\release\armv5\urel\gstvalue.exe"-"!:\sys\bin\gstvalue.exe" +"\epoc32\release\armv5\urel\helloworld.exe"-"!:\sys\bin\helloworld.exe" +"\epoc32\release\armv5\urel\launch.exe"-"!:\sys\bin\launch.exe" +"\epoc32\release\armv5\urel\manual_dynamic.exe"-"!:\sys\bin\manual_dynamic.exe" +"\epoc32\release\armv5\urel\manual_ghostpad.exe"-"!:\sys\bin\manual_ghostpad.exe" +"\epoc32\release\armv5\urel\manual_gstbin.exe"-"!:\sys\bin\manual_gstbin.exe" +"\epoc32\release\armv5\urel\manual_gstdecodebin.exe"-"!:\sys\bin\manual_gstdecodebin.exe" +"\epoc32\release\armv5\urel\manual_gstelementcreate.exe"-"!:\sys\bin\manual_gstelementcreate.exe" +"\epoc32\release\armv5\urel\manual_gstelementfactory.exe"-"!:\sys\bin\manual_gstelementfactory.exe" +"\epoc32\release\armv5\urel\manual_gstelementget.exe"-"!:\sys\bin\manual_gstelementget.exe" +"\epoc32\release\armv5\urel\manual_gstelementlink.exe"-"!:\sys\bin\manual_gstelementlink.exe" +"\epoc32\release\armv5\urel\manual_gstelementmake.exe"-"!:\sys\bin\manual_gstelementmake.exe" +"\epoc32\release\armv5\urel\manual_gstinit.exe"-"!:\sys\bin\manual_gstinit.exe" +"\epoc32\release\armv5\urel\manual_gstpad.exe"-"!:\sys\bin\manual_gstpad.exe" +"\epoc32\release\armv5\urel\manual_gstplaybin.exe"-"!:\sys\bin\manual_gstplaybin.exe" +"\epoc32\release\armv5\urel\manual_gstquery.exe"-"!:\sys\bin\manual_gstquery.exe" +"\epoc32\release\armv5\urel\manual_helloworld.exe"-"!:\sys\bin\manual_helloworld.exe" +"\epoc32\release\armv5\urel\manual_typefind.exe"-"!:\sys\bin\manual_typefind.exe" +"\epoc32\release\armv5\urel\metadata.exe"-"!:\sys\bin\metadata.exe" +"\epoc32\release\armv5\urel\mp3launch.exe"-"!:\sys\bin\mp3launch.exe" +"\epoc32\release\armv5\urel\parse-disabled.exe"-"!:\sys\bin\parse-disabled.exe" +"\epoc32\release\armv5\urel\parse-launch.exe"-"!:\sys\bin\parse-launch.exe" +"\epoc32\release\armv5\urel\simple-launch-lines.exe"-"!:\sys\bin\simple-launch-lines.exe" +"\epoc32\release\armv5\urel\stress.exe"-"!:\sys\bin\stress.exe" +"\epoc32\release\armv5\urel\testaudioexample.exe"-"!:\sys\bin\testaudioexample.exe" +"\epoc32\release\armv5\urel\testgstadapter.exe"-"!:\sys\bin\testgstadapter.exe" +"\epoc32\release\armv5\urel\testqueue.exe"-"!:\sys\bin\testqueue.exe" +"\epoc32\release\armv5\urel\typefind.exe"-"!:\sys\bin\typefind.exe" +"\epoc32\release\armv5\urel\gstseek.exe"-"!:\sys\bin\gstseek.exe" +"\epoc32\release\armv5\urel\wav_record.exe"-"!:\sys\bin\wav_record.exe" +"\epoc32\release\armv5\urel\amr_record.exe"-"!:\sys\bin\amr_record.exe" +"\epoc32\release\armv5\urel\aac_record.exe"-"!:\sys\bin\aac_record.exe" + +;gst_plugins_base test exe's + +"\epoc32\release\armv5\urel\gstadder.exe"-"!:\sys\bin\gstadder.exe" +"\epoc32\release\armv5\urel\gstaudioconvert.exe"-"!:\sys\bin\gstaudioconvert.exe" +"\epoc32\release\armv5\urel\gstaudiorate.exe"-"!:\sys\bin\gstaudiorate.exe" +"\epoc32\release\armv5\urel\gstaudioresample.exe"-"!:\sys\bin\gstaudioresample.exe" +"\epoc32\release\armv5\urel\gstaudiotestsrc.exe"-"!:\sys\bin\gstaudiotestsrc.exe" +"\epoc32\release\armv5\urel\createelementbase.exe"-"!:\sys\bin\createelementbase.exe" +"\epoc32\release\armv5\urel\gstdecodebin.exe"-"!:\sys\bin\gstdecodebin.exe" +"\epoc32\release\armv5\urel\gdpdepay.exe"-"!:\sys\bin\gdpdepay.exe" +"\epoc32\release\armv5\urel\multifdsink.exe"-"!:\sys\bin\multifdsink.exe" +"\epoc32\release\armv5\urel\playbin.exe"-"!:\sys\bin\playbin.exe" +"\epoc32\release\armv5\urel\gstsubparse.exe"-"!:\sys\bin\gstsubparse.exe" +"\epoc32\release\armv5\urel\volume.exe"-"!:\sys\bin\volume.exe" +"\epoc32\release\armv5\urel\clock-selection.exe"-"!:\sys\bin\clock-selection.exe" +"\epoc32\release\armv5\urel\states.exe"-"!:\sys\bin\states.exe" +"\epoc32\release\armv5\urel\fft.exe"-"!:\sys\bin\fft.exe" +;"\epoc32\release\armv5\urel\gstnetbuffer.exe"-"!:\sys\bin\gstnetbuffer.exe" +"\epoc32\release\armv5\urel\pbutils.exe"-"!:\sys\bin\pbutils.exe" +"\epoc32\release\armv5\urel\gst_plugin_rtp.exe"-"!:\sys\bin\gst_plugin_rtp.exe" +"\epoc32\release\armv5\urel\gst_plugin_tag.exe"-"!:\sys\bin\gst_plugin_tag.exe" +"\epoc32\release\armv5\urel\taudio.exe"-"!:\sys\bin\taudio.exe" +"\epoc32\release\armv5\urel\gstsimple-launch-lines.exe"-"!:\sys\bin\gstsimple-launch-lines.exe" +"\epoc32\release\armv5\urel\gststreamheader.exe"-"!:\sys\bin\gststreamheader.exe" +"\epoc32\release\armv5\urel\stress_playbin.exe"-"!:\sys\bin\stress_playbin.exe" + +;"\epoc32\release\armv5\urel\ffmpegcolorspace.exe"-"!:\sys\bin\ffmpegcolorspace.exe" +;"\epoc32\release\armv5\urel\addstream.exe"-"!:\sys\bin\addstream.exe" +;"\epoc32\release\armv5\urel\video.exe"-"!:\sys\bin\video.exe" +;"\epoc32\release\armv5\urel\typefindfunctions.exe" -"!:\sys\bin\typefindfunctions.exe" +;"\epoc32\release\armv5\urel\videorate.exe"-"!:\sys\bin\videorate.exe" + + + +;dependecy files + +;Testframework.ini and conf files + +"..\conf\gstreamertestcases_suite4.cfg"-"c:\TestFramework\gstreamertestcases_suite4.cfg" +"..\init\gstreamertestcases_suite4.ini"-"c:\TestFramework\gstreamertestcases_suite4.ini" +"..\init\TestFramework.ini"-"c:\TestFramework\TestFramework.ini" diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite4/inc/GstreamerTestCases.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/gstreamertestcases_suite4/inc/GstreamerTestCases.h Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,190 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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. +* +* Description: STIF testclass declaration +* +*/ + + +#ifndef GSTREAMERTESTCASES_H +#define GSTREAMERTESTCASES_H + +// INCLUDES +#include +#include +#include +#include + +// CONSTANTS +//const ?type ?constant_var = ?constant; + +// MACROS +//#define ?macro ?macro_def +#define TEST_CLASS_VERSION_MAJOR 0 +#define TEST_CLASS_VERSION_MINOR 0 +#define TEST_CLASS_VERSION_BUILD 0 + +// Logging path +_LIT( KGstreamerTestCasesLogPath, "\\logs\\testframework\\GstreamerTestCases\\" ); +// Log file +_LIT( KGstreamerTestCasesLogFile, "GstreamerTestCases.htm" ); +_LIT( KGstreamerTestCasesLogFileWithTitle, "GstreamerTestCases_[%S].htm" ); + +// FUNCTION PROTOTYPES +//?type ?function_name(?arg_list); + +// FORWARD DECLARATIONS +//class ?FORWARD_CLASSNAME; +class CGstreamerTestCases; + +// DATA TYPES +//enum ?declaration +//typedef ?declaration +//extern ?data_type; + +// CLASS DECLARATION + +/** +* CGstreamerTestCases test class for STIF Test Framework TestScripter. +* ?other_description_lines +* +* @lib ?library +* @since ?Series60_version +*/ +NONSHARABLE_CLASS(CGstreamerTestCases) : public CScriptBase + { + public: // Constructors and destructor + + /** + * Two-phased constructor. + */ + static CGstreamerTestCases* NewL( CTestModuleIf& aTestModuleIf ); + + /** + * Destructor. + */ + virtual ~CGstreamerTestCases(); + + public: // New functions + + /** + * ?member_description. + * @since ?Series60_version + * @param ?arg1 ?description + * @return ?description + */ + //?type ?member_function( ?type ?arg1 ); + + public: // Functions from base classes + + /** + * From CScriptBase Runs a script line. + * @since ?Series60_version + * @param aItem Script line containing method name and parameters + * @return Symbian OS error code + */ + virtual TInt RunMethodL( CStifItemParser& aItem ); + + protected: // New functions + + /** + * ?member_description. + * @since ?Series60_version + * @param ?arg1 ?description + * @return ?description + */ + //?type ?member_function( ?type ?arg1 ); + + protected: // Functions from base classes + + /** + * From ?base_class ?member_description + */ + //?type ?member_function(); + + private: + + /** + * C++ default constructor. + */ + CGstreamerTestCases( CTestModuleIf& aTestModuleIf ); + + /** + * By default Symbian 2nd phase constructor is private. + */ + void ConstructL(); + + // Prohibit copy constructor if not deriving from CBase. + // ?classname( const ?classname& ); + // Prohibit assigment operator if not deriving from CBase. + // ?classname& operator=( const ?classname& ); + + /** + * Frees all resources allocated from test methods. + * @since ?Series60_version + */ + void Delete(); + + /** + * Test methods are listed below. + */ + + /** + * Example test method. + * @since ?Series60_version + * @param aItem Script line containing parameters. + * @return Symbian OS error code. + */ + virtual TInt ExampleL( CStifItemParser& aItem ); + + /** + * Method used to log version of test class + */ + void SendTestClassVersion(); + + //ADD NEW METHOD DEC HERE + //[TestMethods] - Do not remove + + public: // Data + // ?one_line_short_description_of_data + //?data_declaration; + + protected: // Data + // ?one_line_short_description_of_data + //?data_declaration; + + private: // Data + + // ?one_line_short_description_of_data + //?data_declaration; + + // Reserved pointer for future extension + //TAny* iReserved; + + public: // Friend classes + //?friend_class_declaration; + protected: // Friend classes + //?friend_class_declaration; + private: // Friend classes + //?friend_class_declaration; + + }; + +#endif // GSTREAMERTESTCASES_H + +// End of File diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite4/init/gstreamertestcases_suite4.ini --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/gstreamertestcases_suite4/init/gstreamertestcases_suite4.ini Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,4 @@ +[general] +logFileName gstreamertestcases_suite4.log +logPath c:\logs\ +[general_end] diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite4/init/testframework.ini --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/gstreamertestcases_suite4/init/testframework.ini Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,184 @@ +# +# This is STIFTestFramework initialization file +# Comment lines start with '#'-character. +# See STIF TestFramework users guide.doc for instructions + +# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +# Set following test engine settings: +# - Set Test Reporting mode. TestReportMode's possible values are: +# + 'Summary': Summary of the tested test cases. +# + 'Environment': Hardware and software info. +# + 'TestCases': Test case report. +# + 'FullReport': Set of all above ones. +# + Example 'TestReportMode= Summary TestCases' +# +# - CreateTestReport setting controls report creation mode +# + YES, Test report will created. +# + NO, No Test report. +# +# - File path indicates the base path of the test report. +# - File name indicates the name of the test report. +# +# - File format indicates the type of the test report. +# + TXT, Test report file will be txt type, for example 'TestReport.txt'. +# + HTML, Test report will be html type, for example 'TestReport.html'. +# +# - File output indicates output source of the test report. +# + FILE, Test report logging to file. +# + RDEBUG, Test report logging to using rdebug. +# +# - File Creation Mode indicates test report overwriting if file exist. +# + OVERWRITE, Overwrites if the Test report file exist. +# + APPEND, Continue logging after the old Test report information if +# report exist. +# - Sets a device reset module's dll name(Reboot). +# + If Nokia specific reset module is not available or it is not correct one +# StifHWResetStub module may use as a template for user specific reset +# module. + +[Engine_Defaults] + +TestReportMode= FullReport # Possible values are: 'Empty', 'Summary', 'Environment', + 'TestCases' or 'FullReport' + +CreateTestReport= YES # Possible values: YES or NO + +TestReportFilePath= C:\LOGS\TestFramework\ +TestReportFileName= TestReport_gstreamertestcases_suite4 + +TestReportFormat= HTML # Possible values: TXT or HTML +TestReportOutput= FILE # Possible values: FILE or RDEBUG +TestReportFileCreationMode= OVERWRITE # Possible values: OVERWRITE or APPEND + +DeviceResetDllName= StifResetForNokia.dll # e.g. 'StifHWResetStub.dll' for user specific reseting + +[End_Defaults] +# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + + + +# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +# Module configurations start +# Modules are added between module tags +# tags. Module name is specified after ModuleName= tag, like +# ModuleName= XXXXXXXXX +# Modules might have initialisation file, specified as +# IniFile= c:\testframework\YYYYYY +# Modules might have several configuration files, like +# TestCaseFile= c:\testframework\NormalCases.txt +# TestCaseFile= c:\testframework\SmokeCases.txt +# TestCaseFile= c:\testframework\ManualCases.txt + +# (TestCaseFile is synonym for old term ConfigFile) + +# Following case specifies demo module settings. Demo module +# does not read any settings from file, so tags +# IniFile and TestCaseFile are not used. +# In the simplest case it is enough to specify only the +# name of the test module when adding new test module + +#[New_Module] +#ModuleName= demomodule +#[End_Module] + + +[New_Module] +ModuleName= TestScripter +TestCaseFile= c:\testframework\gstreamertestcases_suite4.cfg +IniFile= c:\testframework\gstreamertestcases_suite4.ini +[End_Module] + +# Load testmoduleXXX, optionally with initialization file and/or test case files +#[New_Module] +#ModuleName= testmodulexxx + +#TestModuleXXX used initialization file +#IniFile= c:\testframework\init.txt + +#TestModuleXXX used configuration file(s) +#TestCaseFile= c:\testframework\testcases1.cfg +#TestCaseFile= c:\testframework\testcases2.cfg +#TestCaseFile= c:\testframework\manualtestcases.cfg + +#[End_Module] +# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + + + +# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +# Set STIFTestFramework logging overwrite parameters for Logger. +# Hardware and emulator environment logging path and styles can +# be configured from here to overwrite the Logger's implemented values. +# +# Settings description: +# - Indicates option for creation log directory/directories. If log directory/directories +# is/are not created by user they will make by software. +# + YES, Create log directory/directories if not allready exist. +# + NO, Log directory/directories not created. Only created one is used. +# +# - Overwrite emulator path setting. +# + Example: If 'EmulatorBasePath= C:\LOGS\TestFramework\' and in code is defined +# Logger's path 'D:\\LOGS\\Module\\' with those definition the path +# will be 'C:\LOGS\TestFramework\LOGS\Module\' +# +# - Overwrite emulator's logging format. +# + TXT, Log file(s) will be txt type(s), for example 'Module.txt'. +# + HTML, Log file(s) will be html type(s), for example 'Module.html'. +# +# - Overwrited emulator logging output source. +# + FILE, Logging to file(s). +# + RDEBUG, Logging to using rdebug(s). +# +# - Overwrite hardware path setting (Same description as above in emulator path). +# - Overwrite hardware's logging format(Same description as above in emulator format). +# - Overwrite hardware's logging output source(Same description as above in emulator output). +# +# - File Creation Mode indicates file overwriting if file exist. +# + OVERWRITE, Overwrites if file(s) exist. +# + APPEND, Continue logging after the old logging information if file(s) exist. +# +# - Will thread id include to the log filename. +# + YES, Thread id to log file(s) name, Example filename 'Module_b9.txt'. +# + NO, No thread id to log file(s), Example filename 'Module.txt'. +# +# - Will time stamps include the to log file. +# + YES, Time stamp added to each line in log file(s). Time stamp is +# for example'12.Nov.2003 115958 LOGGING INFO' +# + NO, No time stamp(s). +# +# - Will line breaks include to the log file. +# + YES, Each logging event includes line break and next log event is in own line. +# + NO, No line break(s). +# +# - Will event ranking include to the log file. +# + YES, Event ranking number added to each line in log file(s). Ranking number +# depends on environment's tics, for example(includes time stamp also) +# '012 12.Nov.2003 115958 LOGGING INFO' +# + NO, No event ranking. +# + +[Logger_Defaults] + +#NOTE: If you want to set Logger using next setting(s) remove comment(s)'#' + +#CreateLogDirectories= YES # Possible values: YES or NO + +#EmulatorBasePath= C:\LOGS\TestFramework\ +#EmulatorFormat= HTML # Possible values: TXT or HTML +#EmulatorOutput= FILE # Possible values: FILE or RDEBUG + +#HardwareBasePath= D:\LOGS\TestFramework\ +#HardwareFormat= HTML # Possible values: TXT or HTML +#HardwareOutput= FILE # Possible values: FILE or RDEBUG + +#FileCreationMode= OVERWRITE # Possible values: OVERWRITE or APPEND + +#ThreadIdToLogFile= YES # Possible values: YES or NO +#WithTimeStamp= YES # Possible values: YES or NO +#WithLineBreak= YES # Possible values: YES or NO +#WithEventRanking= YES # Possible values: YES or NO + +[End_Logger_Defaults] +# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + +# End of file \ No newline at end of file diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite4/src/GstreamerTestCases.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/gstreamertestcases_suite4/src/GstreamerTestCases.cpp Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,204 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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. +* +* Description: This file contains testclass implementation. +* +*/ + +// INCLUDE FILES +#include +#include "GstreamerTestCases.h" +#include + +// EXTERNAL DATA STRUCTURES +//extern ?external_data; + +// EXTERNAL FUNCTION PROTOTYPES +//extern ?external_function( ?arg_type,?arg_type ); + +// CONSTANTS +//const ?type ?constant_var = ?constant; + +// MACROS +//#define ?macro ?macro_def + +// LOCAL CONSTANTS AND MACROS +//const ?type ?constant_var = ?constant; +//#define ?macro_name ?macro_def + +// MODULE DATA STRUCTURES +//enum ?declaration +//typedef ?declaration + +// LOCAL FUNCTION PROTOTYPES +//?type ?function_name( ?arg_type, ?arg_type ); + +// FORWARD DECLARATIONS +//class ?FORWARD_CLASSNAME; + +// ============================= LOCAL FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// ?function_name ?description. +// ?description +// Returns: ?value_1: ?description +// ?value_n: ?description_line1 +// ?description_line2 +// ----------------------------------------------------------------------------- +// +/* +?type ?function_name( + ?arg_type arg, // ?description + ?arg_type arg) // ?description + { + + ?code // ?comment + + // ?comment + ?code + } +*/ + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CGstreamerTestCases::CGstreamerTestCases +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CGstreamerTestCases::CGstreamerTestCases( + CTestModuleIf& aTestModuleIf ): + CScriptBase( aTestModuleIf ) + { + } + +// ----------------------------------------------------------------------------- +// CGstreamerTestCases::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CGstreamerTestCases::ConstructL() + { + //Read logger settings to check whether test case name is to be + //appended to log file name. + RSettingServer settingServer; + TInt ret = settingServer.Connect(); + if(ret != KErrNone) + { + User::Leave(ret); + } + // Struct to StifLogger settigs. + TLoggerSettings loggerSettings; + // Parse StifLogger defaults from STIF initialization file. + ret = settingServer.GetLoggerSettings(loggerSettings); + if(ret != KErrNone) + { + User::Leave(ret); + } + // Close Setting server session + settingServer.Close(); + + TFileName logFileName; + + if(loggerSettings.iAddTestCaseTitle) + { + TName title; + TestModuleIf().GetTestCaseTitleL(title); + logFileName.Format(KGstreamerTestCasesLogFileWithTitle, &title); + } + else + { + logFileName.Copy(KGstreamerTestCasesLogFile); + } + + iLog = CStifLogger::NewL( KGstreamerTestCasesLogPath, + logFileName, + CStifLogger::ETxt, + CStifLogger::EFile, + EFalse ); + + SendTestClassVersion(); + } + +// ----------------------------------------------------------------------------- +// CGstreamerTestCases::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CGstreamerTestCases* CGstreamerTestCases::NewL( + CTestModuleIf& aTestModuleIf ) + { + CGstreamerTestCases* self = new (ELeave) CGstreamerTestCases( aTestModuleIf ); + + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop(); + + return self; + + } + +// Destructor +CGstreamerTestCases::~CGstreamerTestCases() + { + + // Delete resources allocated from test methods + Delete(); + + // Delete logger + delete iLog; + + } + +//----------------------------------------------------------------------------- +// CGstreamerTestCases::SendTestClassVersion +// Method used to send version of test class +//----------------------------------------------------------------------------- +// +void CGstreamerTestCases::SendTestClassVersion() + { + TVersion moduleVersion; + moduleVersion.iMajor = TEST_CLASS_VERSION_MAJOR; + moduleVersion.iMinor = TEST_CLASS_VERSION_MINOR; + moduleVersion.iBuild = TEST_CLASS_VERSION_BUILD; + + TFileName moduleName; + moduleName = _L("GstreamerTestCases.dll"); + + TBool newVersionOfMethod = ETrue; + TestModuleIf().SendTestModuleVersion(moduleVersion, moduleName, newVersionOfMethod); + } + +// ========================== OTHER EXPORTED FUNCTIONS ========================= + +// ----------------------------------------------------------------------------- +// LibEntryL is a polymorphic Dll entry point. +// Returns: CScriptBase: New CScriptBase derived object +// ----------------------------------------------------------------------------- +// +EXPORT_C CScriptBase* LibEntryL( + CTestModuleIf& aTestModuleIf ) // Backpointer to STIF Test Framework + { + + return ( CScriptBase* ) CGstreamerTestCases::NewL( aTestModuleIf ); + + } + + +// End of File diff -r bc39b352897e -r 69c7080681bf gstreamer_core/tsrc/gstreamertestcases_suite4/src/GstreamerTestCasesBlocks.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gstreamer_core/tsrc/gstreamertestcases_suite4/src/GstreamerTestCasesBlocks.cpp Fri Aug 06 16:36:50 2010 -0500 @@ -0,0 +1,237 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser 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. +* +* Description: This file contains testclass implementation. +* +*/ + +// [INCLUDE FILES] - do not remove +#include +#include +#include +#include "GstreamerTestCases.h" + +// EXTERNAL DATA STRUCTURES +//extern ?external_data; + +// EXTERNAL FUNCTION PROTOTYPES +//extern ?external_function( ?arg_type,?arg_type ); + +// CONSTANTS +//const ?type ?constant_var = ?constant; + +// MACROS +//#define ?macro ?macro_def + +// LOCAL CONSTANTS AND MACROS +//const ?type ?constant_var = ?constant; +//#define ?macro_name ?macro_def + +// MODULE DATA STRUCTURES +//enum ?declaration +//typedef ?declaration + +// LOCAL FUNCTION PROTOTYPES +//?type ?function_name( ?arg_type, ?arg_type ); + +// FORWARD DECLARATIONS +//class ?FORWARD_CLASSNAME; + +// ============================= LOCAL FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// ?function_name ?description. +// ?description +// Returns: ?value_1: ?description +// ?value_n: ?description_line1 +// ?description_line2 +// ----------------------------------------------------------------------------- +// +/* +?type ?function_name( + ?arg_type arg, // ?description + ?arg_type arg) // ?description + { + + ?code // ?comment + + // ?comment + ?code + } +*/ + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CGstreamerTestCases::Delete +// Delete here all resources allocated and opened from test methods. +// Called from destructor. +// ----------------------------------------------------------------------------- +// +void CGstreamerTestCases::Delete() + { + + } + +// ----------------------------------------------------------------------------- +// CGstreamerTestCases::RunMethodL +// Run specified method. Contains also table of test mothods and their names. +// ----------------------------------------------------------------------------- +// +TInt CGstreamerTestCases::RunMethodL( + CStifItemParser& aItem ) + { + + static TStifFunctionInfo const KFunctions[] = + { + // Copy this line for every implemented function. + // First string is the function name used in TestScripter script file. + // Second is the actual implementation member function. + ENTRY( "Example", CGstreamerTestCases::ExampleL ), + //ADD NEW ENTRY HERE + // [test cases entries] - Do not remove + + }; + + const TInt count = sizeof( KFunctions ) / + sizeof( TStifFunctionInfo ); + + return RunInternalL( KFunctions, count, aItem ); + + } + +// ----------------------------------------------------------------------------- +// CGstreamerTestCases::ExampleL +// Example test method function. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +TInt CGstreamerTestCases::ExampleL( CStifItemParser& aItem ) +{ + TInt err = KErrNone; + RTimer timeoutTimer; + // Print to UI +// _LIT( KGstreamerTestCases, "GstreamerTestCases" ); +// _LIT( KExample, "Test case: " ); +// TestModuleIf().Printf( 0, KGstreamerTestCases, KExample ); + // Print to log file + + TPtrC string[2]; + TFileName arg; + //_LIT( KParam, "Param[%i]: %S" ); + + if( aItem.GetNextString ( string[0] ) != KErrNone) + { + iLog->Log( _L(">> Test cases Not Found") ); + return -1; + } + iLog->Log( _L( "Test case Name is : " ) ); + iLog->Log( string[0] ); + + while ( aItem.GetNextString ( string[1] ) == KErrNone ) + { + iLog->Log( string[1] ); + arg.Append( string[1] ); + arg.Append( TChar(' ') ); + } + + + _LIT( KArg, "Arg: " ); + iLog->Log( KArg ); + iLog->Log( arg ); + RProcess process; + err = process.Create( string[0],arg ); + + if( !err ) + { + + if( timeoutTimer.CreateLocal() != KErrNone ) + { + iLog->Log( _L(">> timeoutTimer.CreateLocal failed") ); + } + + iLog->Log( _L(">> Test cases Started") ); + TRequestStatus processStatus = KRequestPending; + TRequestStatus timerStatus = KRequestPending; + process.Logon( processStatus ); + + process.Resume(); + TTimeIntervalMicroSeconds32 timeout = 1 * 60 * 1000000; + timeoutTimer.After( timerStatus, timeout ); + + while( processStatus == KRequestPending && timerStatus == KRequestPending ) + { + User::WaitForAnyRequest(); + + } + + err = process.ExitReason(); + if( timerStatus != KRequestPending ) + { + err = KErrTimedOut; + } + + process.LogonCancel( processStatus ); + timeoutTimer.Cancel(); + /// required to complete one of the pending request.. + User::WaitForAnyRequest(); + + process.Kill( KErrNone ); + process.Close(); + timeoutTimer.Close(); + iLog->Log( _L(">> test cases completed") ); + } + else + { + iLog->Log( _L(">> test cases exe not found") ); + } + + + if( err != KErrNone ) + { + iLog->Log( CStifLogger::ERed, _L( "Test cases FAILED!" ) ); + } + else + { + iLog->Log( CStifLogger::EGreen, _L( "Test cases PASSED!" ) ); + } + + + return err; +} + +// ----------------------------------------------------------------------------- +// CGstreamerTestCases::?member_function +// ?implementation_description +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +/* +TInt CGstreamerTestCases::?member_function( + CItemParser& aItem ) + { + + ?code + + } +*/ + +// ========================== OTHER EXPORTED FUNCTIONS ========================= +// None + +// [End of File] - Do not remove diff -r bc39b352897e -r 69c7080681bf gstreamer_test_apps/gstplayer/data/GSTPlayer_reg.rss --- a/gstreamer_test_apps/gstplayer/data/GSTPlayer_reg.rss Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_test_apps/gstplayer/data/GSTPlayer_reg.rss Fri Aug 06 16:36:50 2010 -0500 @@ -32,9 +32,9 @@ * ============================================================================== */ -#include "GSTPlayer.rls" +#include "gstplayer.rls" #include -#include +#include UID2 KUidAppRegistrationResourceFile UID3 0xA000017F diff -r bc39b352897e -r 69c7080681bf gstreamer_test_apps/gstplayer/data/gstplayer.rss --- a/gstreamer_test_apps/gstplayer/data/gstplayer.rss Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_test_apps/gstplayer/data/gstplayer.rss Fri Aug 06 16:36:50 2010 -0500 @@ -38,9 +38,8 @@ // INCLUDES #include #include -#include -#include -#include +#include +#include #include #include #include @@ -49,10 +48,10 @@ #include #include -#include +#include -#include "GSTPlayer.hrh" -#include "GSTPlayer.rls" +#include "gstplayer.hrh" +#include "gstplayer.rls" #define KWidth 176 #define KHeight 100 diff -r bc39b352897e -r 69c7080681bf gstreamer_test_apps/gstplayer/group/gstplayer.mmp --- a/gstreamer_test_apps/gstplayer/group/gstplayer.mmp Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_test_apps/gstplayer/group/gstplayer.mmp Fri Aug 06 16:36:50 2010 -0500 @@ -45,17 +45,17 @@ SOURCEPATH ../src SOURCE GSTPlayer.cpp -SOURCE GSTPlayerApplication.cpp -SOURCE GSTPlayerAppView.cpp -SOURCE GSTPlayerAppUi.cpp -SOURCE GSTPlayerDocument.cpp +SOURCE GSTPlayerapplication.cpp +SOURCE GSTPlayerappview.cpp +SOURCE GSTPlayerappui.cpp +SOURCE GSTPlayerdocument.cpp SOURCE RichTextEditor.cpp SOURCE GlibEventHandler.cpp SOURCE SymGstreamer.cpp SOURCEPATH ../data -START RESOURCE GSTPlayer.rss +START RESOURCE gstplayer.rss HEADER TARGETPATH resource/apps END //RESOURCE diff -r bc39b352897e -r 69c7080681bf gstreamer_test_apps/gstplayer/inc/gstplayerdocument.h --- a/gstreamer_test_apps/gstplayer/inc/gstplayerdocument.h Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_test_apps/gstplayer/inc/gstplayerdocument.h Fri Aug 06 16:36:50 2010 -0500 @@ -35,7 +35,7 @@ #define __GSTPLAYERDOCUMENT_H__ // INCLUDES -#include +#include // FORWARD DECLARATIONS class CGSTPlayerAppUi; diff -r bc39b352897e -r 69c7080681bf gstreamer_test_apps/gstplayer/src/GSTPlayer.cpp --- a/gstreamer_test_apps/gstplayer/src/GSTPlayer.cpp Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_test_apps/gstplayer/src/GSTPlayer.cpp Fri Aug 06 16:36:50 2010 -0500 @@ -33,7 +33,7 @@ // INCLUDE FILES #include -#include "GSTPlayerApplication.h" +#include "gstplayerapplication.h" LOCAL_C CApaApplication* NewApplication() diff -r bc39b352897e -r 69c7080681bf gstreamer_test_apps/gstplayer/src/GSTPlayerapplication.cpp --- a/gstreamer_test_apps/gstplayer/src/GSTPlayerapplication.cpp Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_test_apps/gstplayer/src/GSTPlayerapplication.cpp Fri Aug 06 16:36:50 2010 -0500 @@ -32,8 +32,8 @@ */ // INCLUDE FILES -#include "GSTPlayerDocument.h" -#include "GSTPlayerApplication.h" +#include "gstplayerdocument.h" +#include "gstplayerapplication.h" // ============================ MEMBER FUNCTIONS =============================== diff -r bc39b352897e -r 69c7080681bf gstreamer_test_apps/gstplayer/src/GSTPlayerappui.cpp --- a/gstreamer_test_apps/gstplayer/src/GSTPlayerappui.cpp Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_test_apps/gstplayer/src/GSTPlayerappui.cpp Fri Aug 06 16:36:50 2010 -0500 @@ -34,18 +34,18 @@ // INCLUDE FILES #include #include -#include -#include +#include +#include #include #include #include -#include +#include #include -#include "GSTPlayer.pan" -#include "GSTPlayerAppUi.h" -#include "GSTPlayerAppView.h" -#include "GSTPlayer.hrh" +#include "gstplayer.pan" +#include "gstplayerappui.h" +#include "gstplayerappview.h" +#include "gstplayer.hrh" #include "GlibEventHandler.h" #include "gstreamer.h" diff -r bc39b352897e -r 69c7080681bf gstreamer_test_apps/gstplayer/src/GSTPlayerappview.cpp --- a/gstreamer_test_apps/gstplayer/src/GSTPlayerappview.cpp Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_test_apps/gstplayer/src/GSTPlayerappview.cpp Fri Aug 06 16:36:50 2010 -0500 @@ -35,7 +35,7 @@ #include #include #include -#include "GSTPlayerAppView.h" +#include "gstplayerappview.h" #include "GlibEventHandler.h" // ============================ MEMBER FUNCTIONS =============================== diff -r bc39b352897e -r 69c7080681bf gstreamer_test_apps/gstplayer/src/GSTPlayerdocument.cpp --- a/gstreamer_test_apps/gstplayer/src/GSTPlayerdocument.cpp Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_test_apps/gstplayer/src/GSTPlayerdocument.cpp Fri Aug 06 16:36:50 2010 -0500 @@ -32,8 +32,8 @@ */ // INCLUDE FILES -#include "GSTPlayerAppUi.h" -#include "GSTPlayerDocument.h" +#include "gstplayerappui.h" +#include "gstplayerdocument.h" // ============================ MEMBER FUNCTIONS =============================== diff -r bc39b352897e -r 69c7080681bf gstreamer_test_apps/gstplayer/src/RichTextEditor.cpp --- a/gstreamer_test_apps/gstplayer/src/RichTextEditor.cpp Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_test_apps/gstplayer/src/RichTextEditor.cpp Fri Aug 06 16:36:50 2010 -0500 @@ -24,7 +24,7 @@ * Name : RichTextEditorRTE.cpp * Part of : VoIP test application. * Description : Utility for outputting formatted text to the display. -* Version : %version: 1 % +* Version : %version: 2 % * ============================================================================ */ @@ -32,7 +32,7 @@ #include // TResourceReader #include // CEikRichTextEditor #include // CRichText -#include +#include #include "RichTextEditor.h" diff -r bc39b352897e -r 69c7080681bf gstreamer_test_apps/gstplayer/src/SymGstreamer.cpp --- a/gstreamer_test_apps/gstplayer/src/SymGstreamer.cpp Fri Jul 09 16:26:45 2010 -0500 +++ b/gstreamer_test_apps/gstplayer/src/SymGstreamer.cpp Fri Aug 06 16:36:50 2010 -0500 @@ -24,8 +24,8 @@ #include "GlibEventHandler.h" #include #include -#include -#include +#include +#include #include #include #include