From 80d666f353825391b06d28166abe7616fc42dff0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Jan 2007 12:30:46 +0000 Subject: [PATCH] Added docs. Original commit message from CVS: * docs/plugins/Makefile.am: * docs/plugins/gst-plugins-base-plugins-docs.sgml: * docs/plugins/gst-plugins-base-plugins-sections.txt: * ext/ogg/gstoggdemux.c: (gst_ogg_page_copy), (gst_ogg_page_free), (gst_ogg_pad_query_types), (gst_ogg_pad_submit_page), (gst_ogg_chain_reset), (gst_ogg_chain_new_stream), (gst_ogg_demux_perform_seek): * ext/ogg/gstoggdemux.h: Added docs. Add some more comments. Small cleanups. --- ChangeLog | 14 ++ docs/plugins/Makefile.am | 1 + docs/plugins/gst-plugins-base-plugins-docs.sgml | 1 + docs/plugins/gst-plugins-base-plugins-sections.txt | 10 + ext/ogg/gstoggdemux.c | 233 ++++++--------------- ext/ogg/gstoggdemux.h | 180 ++++++++++++++++ 6 files changed, 270 insertions(+), 169 deletions(-) create mode 100644 ext/ogg/gstoggdemux.h diff --git a/ChangeLog b/ChangeLog index 3d17bb6..d45acc1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ 2007-01-09 Wim Taymans + * docs/plugins/Makefile.am: + * docs/plugins/gst-plugins-base-plugins-docs.sgml: + * docs/plugins/gst-plugins-base-plugins-sections.txt: + * ext/ogg/gstoggdemux.c: (gst_ogg_page_copy), (gst_ogg_page_free), + (gst_ogg_pad_query_types), (gst_ogg_pad_submit_page), + (gst_ogg_chain_reset), (gst_ogg_chain_new_stream), + (gst_ogg_demux_perform_seek): + * ext/ogg/gstoggdemux.h: + Added docs. + Add some more comments. + Small cleanups. + +2007-01-09 Wim Taymans + * ext/theora/theoradec.c: * ext/vorbis/vorbisdec.c: * gst-libs/gst/audio/gstringbuffer.c: diff --git a/docs/plugins/Makefile.am b/docs/plugins/Makefile.am index 318d042..73cf7d6 100644 --- a/docs/plugins/Makefile.am +++ b/docs/plugins/Makefile.am @@ -80,6 +80,7 @@ EXTRA_HFILES = \ $(top_srcdir)/ext/cdparanoia/gstcdparanoiasrc.h \ $(top_srcdir)/ext/gnomevfs/gstgnomevfssink.h \ $(top_srcdir)/ext/gnomevfs/gstgnomevfssrc.h \ + $(top_srcdir)/ext/ogg/gstoggdemux.h \ $(top_srcdir)/ext/pango/gstclockoverlay.h \ $(top_srcdir)/ext/pango/gsttextoverlay.h \ $(top_srcdir)/ext/pango/gsttextrender.h \ diff --git a/docs/plugins/gst-plugins-base-plugins-docs.sgml b/docs/plugins/gst-plugins-base-plugins-docs.sgml index 3fd42be..db405c1 100644 --- a/docs/plugins/gst-plugins-base-plugins-docs.sgml +++ b/docs/plugins/gst-plugins-base-plugins-docs.sgml @@ -27,6 +27,7 @@ + diff --git a/docs/plugins/gst-plugins-base-plugins-sections.txt b/docs/plugins/gst-plugins-base-plugins-sections.txt index 8b38ca6..9b2925a 100644 --- a/docs/plugins/gst-plugins-base-plugins-sections.txt +++ b/docs/plugins/gst-plugins-base-plugins-sections.txt @@ -217,6 +217,16 @@ gst_gnome_vfs_src_get_type
+element-oggdemux +oggdemux +GstOggDemux + +GST_OGG_DEMUX +GST_OGG_DEMUX_CLASS +GstOggDemuxClass +
+ +
element-playbin playbin GstPlayBin diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index 7870efd..3c31a77 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -19,16 +19,36 @@ * Boston, MA 02111-1307, USA. */ +/** + * SECTION:element-oggdemux + * @short_description: a demuxer for ogg files + * + * + * + * This element demuxes ogg files into their encoded audio and video components. + * + * Example pipelines + * + * + * gst-launch -v filesrc location=test.ogg ! oggdemux ! vorbisdec ! audioconvert ! alsasink + * + * Decodes the vorbis audio stored inside an ogg container. + * + * + * + * Last reviewed on 2006-12-30 (0.10.5) + */ + + #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include -#include #include #include - #include +#include "gstoggdemux.h" + static const GstElementDetails gst_ogg_demux_details = GST_ELEMENT_DETAILS ("Ogg demuxer", "Codec/Demuxer", @@ -73,155 +93,6 @@ gst_ogg_page_free (ogg_page * page) g_free (page); } -#define GST_TYPE_OGG_PAD (gst_ogg_pad_get_type()) -#define GST_OGG_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_PAD, GstOggPad)) -#define GST_OGG_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_PAD, GstOggPad)) -#define GST_IS_OGG_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_PAD)) -#define GST_IS_OGG_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_PAD)) - -typedef struct _GstOggPad GstOggPad; -typedef struct _GstOggPadClass GstOggPadClass; - -#define GST_TYPE_OGG_DEMUX (gst_ogg_demux_get_type()) -#define GST_OGG_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_DEMUX, GstOggDemux)) -#define GST_OGG_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_DEMUX, GstOggDemux)) -#define GST_IS_OGG_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_DEMUX)) -#define GST_IS_OGG_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_DEMUX)) - -static GType gst_ogg_demux_get_type (void); - -typedef struct _GstOggDemux GstOggDemux; -typedef struct _GstOggDemuxClass GstOggDemuxClass; - -/* all information needed for one ogg chain (relevant for chained bitstreams) */ -typedef struct _GstOggChain -{ - GstOggDemux *ogg; - - gint64 offset; /* starting offset of chain */ - gint64 end_offset; /* end offset of chain */ - gint64 bytes; /* number of bytes */ - - gboolean have_bos; - - GArray *streams; - - GstClockTime total_time; /* the total time of this chain, this is the MAX of - the totals of all streams */ - GstClockTime begin_time; /* when this chain starts in the stream */ - - GstClockTime segment_start; /* the timestamp of the first sample, this is the MIN of - the start times of all streams. */ - GstClockTime segment_stop; /* the timestamp of the last page, this is the MAX of the - streams. */ -} GstOggChain; - -/* different modes for the pad */ -typedef enum -{ - GST_OGG_PAD_MODE_INIT, /* we are feeding our internal decoder to get info */ - GST_OGG_PAD_MODE_STREAMING, /* we are streaming buffers to the outside */ -} GstOggPadMode; - -#define PARENT GstPad -#define PARENTCLASS GstPadClass - -/* all information needed for one ogg stream */ -struct _GstOggPad -{ - PARENT pad; /* subclass GstPad */ - - gboolean have_type; - GstOggPadMode mode; - - GstPad *elem_pad; /* sinkpad of internal element */ - GstElement *element; /* internal element */ - GstPad *elem_out; /* our sinkpad to receive buffers form the internal element */ - - GstOggChain *chain; /* the chain we are part of */ - GstOggDemux *ogg; /* the ogg demuxer we are part of */ - - GList *headers; - - gboolean is_skeleton; - gboolean have_fisbone; - gint64 granulerate_n; - gint64 granulerate_d; - guint32 preroll; - guint granuleshift; - - gint serialno; - gint64 packetno; - gint64 current_granule; - - GstClockTime start_time; /* the timestamp of the first sample */ - - gint64 first_granule; /* the granulepos of first page == first sample in next page */ - GstClockTime first_time; /* the timestamp of the second page or granuletime of first page */ - - ogg_stream_state stream; - GList *continued; - - gboolean discont; - GstFlowReturn last_ret; /* last return of _pad_push() */ - - gboolean dynamic; /* True if the internal element had dynamic pads */ - guint padaddedid; /* The signal id for element::pad-added */ -}; - -struct _GstOggPadClass -{ - PARENTCLASS parent_class; -}; - -#define GST_CHAIN_LOCK(ogg) g_mutex_lock((ogg)->chain_lock) -#define GST_CHAIN_UNLOCK(ogg) g_mutex_unlock((ogg)->chain_lock) - -struct _GstOggDemux -{ - GstElement element; - - GstPad *sinkpad; - - gint64 length; - gint64 offset; - - gboolean seekable; - gboolean running; - - gboolean need_chains; - - /* state */ - GMutex *chain_lock; /* we need the lock to protect the chains */ - GArray *chains; /* list of chains we know */ - GstClockTime total_time; - GstFlowReturn chain_error; /* error we received while finding chains */ - - GstOggChain *current_chain; - GstOggChain *building_chain; - - /* playback start/stop positions */ - GstSegment segment; - gboolean segment_running; - - GstEvent *event; - GstEvent *newsegment; /* pending newsegment to be sent from _loop */ - - gint64 current_granule; - - /* annodex stuff */ - gboolean have_fishead; - gint64 basetime; - - /* ogg stuff */ - ogg_sync_state sync; -}; - -struct _GstOggDemuxClass -{ - GstElementClass parent_class; -}; - static GstStaticPadTemplate internaltemplate = GST_STATIC_PAD_TEMPLATE ("internal", GST_PAD_SINK, @@ -410,6 +281,7 @@ gst_ogg_pad_query_types (GstPad * pad) { static const GstQueryType query_types[] = { GST_QUERY_DURATION, + GST_QUERY_SEEKING, 0 }; @@ -972,7 +844,9 @@ decoder_error: } } -/* queue data */ +/* queue data, basically takes the packet, puts it in a buffer and store the + * buffer in the headers list. + */ static GstFlowReturn gst_ogg_demux_queue_data (GstOggPad * pad, ogg_packet * packet) { @@ -1280,6 +1154,8 @@ gst_ogg_pad_submit_page (GstOggPad * pad, ogg_page * page) ogg = pad->ogg; + /* for negative rates we read pages backwards and must therefore be carefull + * with continued pages */ if (ogg->segment.rate < 0.0) { gint npackets; @@ -1288,7 +1164,11 @@ gst_ogg_pad_submit_page (GstOggPad * pad, ogg_page * page) /* number of completed packets in the page */ npackets = ogg_page_packets (page); if (!continued) { - /* page is not continued so it contains at least one packet start */ + /* page is not continued so it contains at least one packet start. It's + * possible that no packet ends on this page (npackets == 0). In that + * case, the next (continued) page(s) we kept contain the remainder of the + * packets. We mark npackets=1 to make us start decoding the pages in the + * remainder of the algorithm. */ if (npackets == 0) npackets = 1; } @@ -1303,7 +1183,8 @@ gst_ogg_pad_submit_page (GstOggPad * pad, ogg_page * page) if (ogg_stream_pagein (&pad->stream, page) != 0) goto choked; - /* flush all packets in the stream layer */ + /* flush all packets in the stream layer, this might not give a packet if + * the page had no packets finishing on the page (npackets == 0). */ result = gst_ogg_pad_stream_out (pad, 0); if (pad->continued) { @@ -1426,29 +1307,26 @@ gst_ogg_chain_new_stream (GstOggChain * chain, glong serialno) ret = g_object_new (GST_TYPE_OGG_PAD, NULL); /* we own this one */ gst_object_ref (ret); - gst_object_sink (GST_OBJECT (ret)); - - list = gst_tag_list_new (); - name = g_strdup_printf ("serial_%08lx", serialno); + gst_object_sink (ret); GST_PAD_DIRECTION (ret) = GST_PAD_SRC; + ret->discont = TRUE; + ret->chain = chain; ret->ogg = chain->ogg; - ret->discont = TRUE; + + ret->serialno = serialno; + if (ogg_stream_init (&ret->stream, serialno) != 0) + goto init_failed; + + name = g_strdup_printf ("serial_%08lx", serialno); gst_object_set_name (GST_OBJECT (ret), name); g_free (name); - ret->serialno = serialno; - if (ogg_stream_init (&ret->stream, serialno) != 0) { - GST_ERROR ("Could not initialize ogg_stream struct for serial %08lx.", - serialno); - gst_object_unref (ret); - return NULL; - } + /* FIXME: either do something with it or remove it */ + list = gst_tag_list_new (); gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_SERIAL, serialno, NULL); - /* FIXME: either have it or remove it */ - //gst_element_found_tags (GST_ELEMENT (ogg), list); gst_tag_list_free (list); GST_DEBUG_OBJECT (chain->ogg, @@ -1457,6 +1335,15 @@ gst_ogg_chain_new_stream (GstOggChain * chain, glong serialno) g_array_append_val (chain->streams, ret); return ret; + + /* ERRORS */ +init_failed: + { + GST_ERROR ("Could not initialize ogg_stream struct for serial %08lx.", + serialno); + gst_object_unref (ret); + return NULL; + } } static GstOggPad * @@ -2960,6 +2847,14 @@ done: return ret; } +/* reverse mode. + * + * We read the pages backwards and send the packets forwards. The first packet + * in the page will be pushed with the DISCONT flag set. + * + * Special care has to be taken for continued pages, which we can only decode + * when we have the previous page(s). + */ static GstFlowReturn gst_ogg_demux_loop_reverse (GstOggDemux * ogg) { diff --git a/ext/ogg/gstoggdemux.h b/ext/ogg/gstoggdemux.h new file mode 100644 index 0000000..e7203e0 --- /dev/null +++ b/ext/ogg/gstoggdemux.h @@ -0,0 +1,180 @@ +/* GStreamer + * Copyright (C) 2004 Wim Taymans + * + * gstoggdemux.c: ogg stream demuxer + * + * 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_OGG_DEMUX_H__ +#define __GST_OGG_DEMUX_H__ + +#include + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_OGG_PAD (gst_ogg_pad_get_type()) +#define GST_OGG_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_PAD, GstOggPad)) +#define GST_OGG_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_PAD, GstOggPad)) +#define GST_IS_OGG_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_PAD)) +#define GST_IS_OGG_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_PAD)) + +typedef struct _GstOggPad GstOggPad; +typedef struct _GstOggPadClass GstOggPadClass; + +#define GST_TYPE_OGG_DEMUX (gst_ogg_demux_get_type()) +#define GST_OGG_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_DEMUX, GstOggDemux)) +#define GST_OGG_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_DEMUX, GstOggDemux)) +#define GST_IS_OGG_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_DEMUX)) +#define GST_IS_OGG_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_DEMUX)) + +static GType gst_ogg_demux_get_type (void); + +typedef struct _GstOggDemux GstOggDemux; +typedef struct _GstOggDemuxClass GstOggDemuxClass; +typedef struct _GstOggChain GstOggChain; + +/* all information needed for one ogg chain (relevant for chained bitstreams) */ +struct _GstOggChain +{ + GstOggDemux *ogg; + + gint64 offset; /* starting offset of chain */ + gint64 end_offset; /* end offset of chain */ + gint64 bytes; /* number of bytes */ + + gboolean have_bos; + + GArray *streams; + + GstClockTime total_time; /* the total time of this chain, this is the MAX of + the totals of all streams */ + GstClockTime begin_time; /* when this chain starts in the stream */ + + GstClockTime segment_start; /* the timestamp of the first sample, this is the MIN of + the start times of all streams. */ + GstClockTime segment_stop; /* the timestamp of the last page, this is the MAX of the + streams. */ +}; + +/* different modes for the pad */ +typedef enum +{ + GST_OGG_PAD_MODE_INIT, /* we are feeding our internal decoder to get info */ + GST_OGG_PAD_MODE_STREAMING, /* we are streaming buffers to the outside */ +} GstOggPadMode; + +/* all information needed for one ogg stream */ +struct _GstOggPad +{ + GstPad pad; /* subclass GstPad */ + + gboolean have_type; + GstOggPadMode mode; + + GstPad *elem_pad; /* sinkpad of internal element */ + GstElement *element; /* internal element */ + GstPad *elem_out; /* our sinkpad to receive buffers form the internal element */ + + GstOggChain *chain; /* the chain we are part of */ + GstOggDemux *ogg; /* the ogg demuxer we are part of */ + + GList *headers; + + gboolean is_skeleton; + gboolean have_fisbone; + gint64 granulerate_n; + gint64 granulerate_d; + guint32 preroll; + guint granuleshift; + + gint serialno; + gint64 packetno; + gint64 current_granule; + + GstClockTime start_time; /* the timestamp of the first sample */ + + gint64 first_granule; /* the granulepos of first page == first sample in next page */ + GstClockTime first_time; /* the timestamp of the second page or granuletime of first page */ + + ogg_stream_state stream; + GList *continued; + + gboolean discont; + GstFlowReturn last_ret; /* last return of _pad_push() */ + + gboolean dynamic; /* True if the internal element had dynamic pads */ + guint padaddedid; /* The signal id for element::pad-added */ +}; + +struct _GstOggPadClass +{ + GstPadClass parent_class; +}; + +#define GST_CHAIN_LOCK(ogg) g_mutex_lock((ogg)->chain_lock) +#define GST_CHAIN_UNLOCK(ogg) g_mutex_unlock((ogg)->chain_lock) + +struct _GstOggDemux +{ + GstElement element; + + GstPad *sinkpad; + + gint64 length; + gint64 offset; + + gboolean seekable; + gboolean running; + + gboolean need_chains; + + /* state */ + GMutex *chain_lock; /* we need the lock to protect the chains */ + GArray *chains; /* list of chains we know */ + GstClockTime total_time; + GstFlowReturn chain_error; /* error we received while finding chains */ + + GstOggChain *current_chain; + GstOggChain *building_chain; + + /* playback start/stop positions */ + GstSegment segment; + gboolean segment_running; + + GstEvent *event; + GstEvent *newsegment; /* pending newsegment to be sent from _loop */ + + gint64 current_granule; + + /* annodex stuff */ + gboolean have_fishead; + gint64 basetime; + + /* ogg stuff */ + ogg_sync_state sync; +}; + +struct _GstOggDemuxClass +{ + GstElementClass parent_class; +}; + +G_END_DECLS + +#endif /* __GST_OGG_DEMUX_H__ */ -- 2.7.4