From b8583561dac5a07699ffd7e8a19dcb67599570b6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 24 Nov 2006 15:40:58 +0000 Subject: [PATCH] ext/ogg/gstoggdemux.c: Some cleanups. Original commit message from CVS: * ext/ogg/gstoggdemux.c: (gst_ogg_page_copy), (gst_ogg_page_free), (gst_ogg_pad_init), (gst_ogg_pad_dispose), (gst_ogg_pad_reset), (gst_ogg_pad_stream_out), (gst_ogg_pad_submit_page), (gst_ogg_chain_reset), (gst_ogg_demux_perform_seek): Some cleanups. Handle continued pages in reverse mode. --- ChangeLog | 9 +++ ext/ogg/gstoggdemux.c | 176 +++++++++++++++++++++++++++++++++++------- 2 files changed, 157 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index db0af7c30a..b871fa64ca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2006-11-24 Wim Taymans + + * ext/ogg/gstoggdemux.c: (gst_ogg_page_copy), (gst_ogg_page_free), + (gst_ogg_pad_init), (gst_ogg_pad_dispose), (gst_ogg_pad_reset), + (gst_ogg_pad_stream_out), (gst_ogg_pad_submit_page), + (gst_ogg_chain_reset), (gst_ogg_demux_perform_seek): + Some cleanups. + Handle continued pages in reverse mode. + 2006-11-24 Wim Taymans * ext/vorbis/vorbisdec.c: (vorbis_dec_push_forward), diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index c13c0b7177..83f15cc4c8 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -51,6 +51,28 @@ GST_DEBUG_CATEGORY_STATIC (gst_ogg_demux_debug); GST_DEBUG_CATEGORY_STATIC (gst_ogg_demux_setup_debug); #define GST_CAT_DEFAULT gst_ogg_demux_debug +static ogg_page * +gst_ogg_page_copy (ogg_page * page) +{ + ogg_page *p = g_new0 (ogg_page, 1); + + /* make a copy of the page */ + p->header = g_memdup (page->header, page->header_len); + p->header_len = page->header_len; + p->body = g_memdup (page->body, page->body_len); + p->body_len = page->body_len; + + return p; +} + +static void +gst_ogg_page_free (ogg_page * page) +{ + g_free (page->header); + g_free (page->body); + 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)) @@ -138,6 +160,7 @@ struct _GstOggPad 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() */ @@ -301,6 +324,7 @@ gst_ogg_pad_init (GstOggPad * pad) pad->first_time = GST_CLOCK_TIME_NONE; pad->have_type = FALSE; + pad->continued = NULL; pad->headers = NULL; } @@ -329,6 +353,11 @@ gst_ogg_pad_dispose (GObject * object) g_list_free (pad->headers); pad->headers = NULL; + /* clear continued pages */ + g_list_foreach (pad->continued, (GFunc) gst_ogg_page_free, NULL); + g_list_free (pad->continued); + pad->continued = NULL; + ogg_stream_reset (&pad->stream); G_OBJECT_CLASS (ogg_pad_parent_class)->dispose (object); @@ -535,7 +564,13 @@ static void gst_ogg_pad_reset (GstOggPad * pad) { ogg_stream_reset (&pad->stream); - /* FIXME: need a discont here */ + + /* clear continued pages */ + g_list_foreach (pad->continued, (GFunc) gst_ogg_page_free, NULL); + g_list_free (pad->continued); + pad->continued = NULL; + + pad->last_ret = GST_FLOW_OK; } /* the filter function for selecting the elements we can use in @@ -1176,27 +1211,22 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet) return ret; } -/* submit a page to an oggpad, this function will then submit all - * the packets in the page. +/* flush at most @npackets from the stream layer. All packets if + * @npackets is 0; */ static GstFlowReturn -gst_ogg_pad_submit_page (GstOggPad * pad, ogg_page * page) +gst_ogg_pad_stream_out (GstOggPad * pad, gint npackets) { - ogg_packet packet; - int ret; - gboolean done = FALSE; GstFlowReturn result = GST_FLOW_OK; + gboolean done = FALSE; GstOggDemux *ogg; - ogg = GST_OGG_DEMUX (GST_PAD_PARENT (pad)); - - if (ogg_stream_pagein (&pad->stream, page) != 0) - goto choked; - - if (ogg_page_continued (page)) - GST_LOG_OBJECT (ogg, "have continued page"); + ogg = pad->ogg; while (!done) { + int ret; + ogg_packet packet; + ret = ogg_stream_packetout (&pad->stream, &packet); switch (ret) { case 0: @@ -1220,9 +1250,100 @@ gst_ogg_pad_submit_page (GstOggPad * pad, ogg_page * page) gst_ogg_pad_reset (pad); break; } + if (npackets > 0) { + npackets--; + done = (npackets == 0); + } } return result; + /* ERRORS */ +could_not_submit: + { + GST_WARNING_OBJECT (ogg, + "could not submit packet for stream %08x, error: %d", pad->serialno, + result); + gst_ogg_pad_reset (pad); + return result; + } +} + +/* submit a page to an oggpad, this function will then submit all + * the packets in the page. + */ +static GstFlowReturn +gst_ogg_pad_submit_page (GstOggPad * pad, ogg_page * page) +{ + GstFlowReturn result = GST_FLOW_OK; + GstOggDemux *ogg; + gboolean continued = FALSE; + + ogg = pad->ogg; + + if (ogg->segment.rate < 0.0) { + gint npackets; + + continued = ogg_page_continued (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 */ + if (npackets == 0) + npackets = 1; + } + GST_LOG_OBJECT (ogg, "continued: %d, %d packets", continued, npackets); + + if (npackets == 0) { + GST_LOG_OBJECT (ogg, "no decodable packets, we need a previous page"); + goto done; + } + } + + if (ogg_stream_pagein (&pad->stream, page) != 0) + goto choked; + + /* flush all packets in the stream layer */ + result = gst_ogg_pad_stream_out (pad, 0); + + if (pad->continued) { + ogg_packet packet; + + /* now send the continued pages to the stream layer */ + while (pad->continued) { + ogg_page *p = (ogg_page *) pad->continued->data; + + GST_LOG_OBJECT (ogg, "submitting continued page %p", p); + if (ogg_stream_pagein (&pad->stream, p) != 0) + goto choked; + + pad->continued = g_list_delete_link (pad->continued, pad->continued); + + /* free the page */ + gst_ogg_page_free (p); + } + + GST_LOG_OBJECT (ogg, "flushing last continued packet"); + /* flush 1 continued packet in the stream layer */ + result = gst_ogg_pad_stream_out (pad, 1); + + /* flush all remaining packets, we pushed them in the previous round. + * We don't use _reset() because we still want to get the discont when + * we submit a next page. */ + while (ogg_stream_packetout (&pad->stream, &packet) != 0); + } + +done: + /* keep continued pages (only in reverse mode) */ + if (continued) { + ogg_page *p = gst_ogg_page_copy (page); + + GST_LOG_OBJECT (ogg, "keeping continued page %p", p); + pad->continued = g_list_prepend (pad->continued, p); + } + + return result; + choked: { GST_WARNING_OBJECT (ogg, @@ -1232,14 +1353,6 @@ choked: /* we continue to recover */ return GST_FLOW_OK; } -could_not_submit: - { - GST_WARNING_OBJECT (ogg, - "could not submit packet for stream %08x, error: %d", pad->serialno, - result); - gst_ogg_pad_reset (pad); - return result; - } } @@ -1288,6 +1401,18 @@ gst_ogg_chain_mark_discont (GstOggChain * chain) } } +static void +gst_ogg_chain_reset (GstOggChain * chain) +{ + gint i; + + for (i = 0; i < chain->streams->len; i++) { + GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); + + gst_ogg_pad_reset (pad); + } +} + static GstOggPad * gst_ogg_chain_new_stream (GstOggChain * chain, glong serialno) { @@ -2072,13 +2197,8 @@ gst_ogg_demux_perform_seek (GstOggDemux * ogg, GstEvent * event) * make sure the streaming thread is not messing with the stream */ for (i = 0; i < ogg->chains->len; i++) { GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i); - gint j; - for (j = 0; j < chain->streams->len; j++) { - GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, j); - - ogg_stream_reset (&pad->stream); - } + gst_ogg_chain_reset (chain); } }