ext/ogg/: Mark delta units in the muxer.
authorWim Taymans <wim.taymans@gmail.com>
Tue, 17 Aug 2004 10:40:50 +0000 (10:40 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Tue, 17 Aug 2004 10:40:50 +0000 (10:40 +0000)
Original commit message from CVS:
* ext/ogg/gstoggdemux.c: (gst_ogg_demux_iterate),
(gst_ogg_pad_push):
* ext/ogg/gstoggmux.c: (gst_ogg_mux_init),
(gst_ogg_mux_request_new_pad), (gst_ogg_mux_next_buffer),
(gst_ogg_mux_buffer_from_page), (gst_ogg_mux_push_page),
(gst_ogg_mux_send_headers), (gst_ogg_mux_loop):
Mark delta units in the muxer.
Try to decode the packet after an out-of-sync error from
libogg.

ChangeLog
ext/ogg/Makefile.am
ext/ogg/gstoggdemux.c
ext/ogg/gstoggmux.c

index ca0e788..9260c40 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 2004-08-17  Wim Taymans  <wim@fluendo.com>
 
+       * ext/ogg/gstoggdemux.c: (gst_ogg_demux_iterate),
+       (gst_ogg_pad_push):
+       * ext/ogg/gstoggmux.c: (gst_ogg_mux_init),
+       (gst_ogg_mux_request_new_pad), (gst_ogg_mux_next_buffer),
+       (gst_ogg_mux_buffer_from_page), (gst_ogg_mux_push_page),
+       (gst_ogg_mux_send_headers), (gst_ogg_mux_loop):
+       Mark delta units in the muxer.
+       Try to decode the packet after an out-of-sync error from
+       libogg.
+
+2004-08-17  Wim Taymans  <wim@fluendo.com>
+
        * gst/tcp/gstmultifdsink.c: (gst_multifdsink_class_init),
        (gst_multifdsink_init), (gst_multifdsink_add),
        (gst_multifdsink_client_queue_buffer),
index 42cfb61..5b0bacd 100644 (file)
@@ -2,7 +2,7 @@ plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
 
 plugin_LTLIBRARIES = libgstogg.la
 
-libgstogg_la_SOURCES = gstoggdemux.c gstoggmux.c gstogg.c
+libgstogg_la_SOURCES = gstogg.c gstoggdemux.c gstoggmux.c
 libgstogg_la_CFLAGS = $(GST_CFLAGS) $(OGG_CFLAGS)
 libgstogg_la_LIBADD = $(OGG_LIBS)
 libgstogg_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
index 48a6234..c1fc8f1 100644 (file)
@@ -533,7 +533,8 @@ gst_ogg_demux_src_event (GstPad * pad, GstEvent * event)
 
       GST_OGG_SET_STATE (ogg, GST_OGG_STATE_SEEK);
       FOR_PAD_IN_CURRENT_CHAIN (ogg, pad,
-          pad->flags |= GST_OGG_PAD_NEEDS_DISCONT;);
+          pad->flags |= GST_OGG_PAD_NEEDS_DISCONT;
+          );
       GST_DEBUG_OBJECT (ogg,
           "initiating seeking to format %d, offset %" G_GUINT64_FORMAT, format,
           offset);
@@ -606,7 +607,8 @@ gst_ogg_demux_handle_event (GstPad * pad, GstEvent * event)
       gst_event_unref (event);
       GST_FLAG_UNSET (ogg, GST_OGG_FLAG_WAIT_FOR_DISCONT);
       FOR_PAD_IN_CURRENT_CHAIN (ogg, pad,
-          pad->flags |= GST_OGG_PAD_NEEDS_DISCONT;);
+          pad->flags |= GST_OGG_PAD_NEEDS_DISCONT;
+          );
       break;
     default:
       gst_pad_event_default (pad, event);
@@ -876,7 +878,8 @@ _find_chain_get_unknown_part (GstOggDemux * ogg, gint64 * start, gint64 * end)
   *end = G_MAXINT64;
 
   g_assert (ogg->current_chain >= 0);
-  FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, *start = MAX (*start, pad->end_offset););
+  FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, *start = MAX (*start, pad->end_offset);
+      );
 
   if (ogg->setup_state == SETUP_FIND_LAST_CHAIN) {
     *end = gst_file_pad_get_length (ogg->sinkpad);
@@ -1005,7 +1008,8 @@ _find_streams_check (GstOggDemux * ogg)
   } else {
     endpos = G_MAXINT64;
     FOR_PAD_IN_CHAIN (ogg, pad, ogg->chains->len - 1,
-        endpos = MIN (endpos, pad->start_offset););
+        endpos = MIN (endpos, pad->start_offset);
+        );
   }
   if (!ogg->seek_skipped || gst_ogg_demux_position (ogg) >= endpos) {
     /* have we found the endposition for all streams yet? */
@@ -1130,9 +1134,9 @@ gst_ogg_demux_iterate (GstFilePad * pad)
         break;
       case 1:
         GST_LOG_OBJECT (ogg,
-            "processing ogg page (serial %d, packet %ld, granule pos %llu",
+            "processing ogg page (serial %d, packet %ld, granule pos %llu, state: %d",
             ogg_page_serialno (&page), ogg_page_pageno (&page),
-            ogg_page_granulepos (&page));
+            ogg_page_granulepos (&page), ogg->state);
         switch (ogg->state) {
           case GST_OGG_STATE_SETUP:
             if (!setup_funcs[ogg->setup_state].process (ogg, &page)) {
@@ -1323,11 +1327,13 @@ gst_ogg_pad_push (GstOggDemux * ogg, GstOggPad * pad)
 
   while (TRUE) {
     ret = ogg_stream_packetout (&pad->stream, &packet);
+    GST_LOG_OBJECT (ogg, "packetout gave %d", ret);
     switch (ret) {
       case 0:
         return;
       case -1:
-        gst_ogg_pad_reset (ogg, pad);
+        /* out of sync, could call gst_ogg_pad_reset() here but ogg can decode
+         * the packet just fine. We should probably send a DISCONT though. */
         break;
       case 1:{
         /* only push data when playing, not during seek or similar */
index bb641ab..b635060 100644 (file)
@@ -58,6 +58,10 @@ typedef struct
   guint state;                  /* state of the pad */
 
   GList *headers;
+
+  gboolean new_page;            /* starting a new page */
+  gboolean first_delta;         /* was the first packet in the page a delta */
+  gboolean prev_delta;          /* was the previous buffer a delta frame */
 }
 GstOggPad;
 
@@ -93,7 +97,7 @@ struct _GstOggMux
   guint64 max_delay;
   guint64 max_page_delay;
 
-  gboolean keyframe_mode;       /* when a delta frame is detected on a stream, we mark
+  GstOggPad *delta_pad;         /* when a delta frame is detected on a stream, we mark
                                    pages as delta frames up to the page that has the
                                    keyframe */
 };
@@ -263,6 +267,8 @@ gst_ogg_mux_init (GstOggMux * ogg_mux)
   ogg_mux->max_delay = DEFAULT_MAX_DELAY;
   ogg_mux->max_page_delay = DEFAULT_MAX_PAGE_DELAY;
 
+  ogg_mux->delta_pad = NULL;
+
   gst_element_set_loop_function (GST_ELEMENT (ogg_mux), gst_ogg_mux_loop);
 }
 
@@ -348,6 +354,9 @@ gst_ogg_mux_request_new_pad (GstElement * element,
       oggpad->eos = FALSE;
       /* we assume there will be some control data first for this pad */
       oggpad->state = GST_OGG_PAD_STATE_CONTROL;
+      oggpad->new_page = TRUE;
+      oggpad->first_delta = FALSE;
+      oggpad->prev_delta = FALSE;
 
       /* save a pointer to our data in the pad */
       gst_pad_set_element_private (newpad, oggpad);
@@ -446,6 +455,7 @@ gst_ogg_mux_next_buffer (GstOggPad * pad)
           GST_DEBUG ("muxer: got incaps buffer in control state, ignoring");
           /* just ignore */
           gst_buffer_unref (buf);
+          /* pull next one in next iteration */
           data = NULL;
         } else {
           GST_DEBUG
@@ -460,7 +470,7 @@ gst_ogg_mux_next_buffer (GstOggPad * pad)
 }
 
 static GstBuffer *
-gst_ogg_mux_buffer_from_page (GstOggMux * mux, ogg_page * page)
+gst_ogg_mux_buffer_from_page (GstOggMux * mux, ogg_page * page, gboolean delta)
 {
   GstBuffer *buffer;
 
@@ -476,15 +486,17 @@ gst_ogg_mux_buffer_from_page (GstOggMux * mux, ogg_page * page)
   GST_BUFFER_OFFSET (buffer) = mux->offset;
   mux->offset += GST_BUFFER_SIZE (buffer);
   GST_BUFFER_OFFSET_END (buffer) = mux->offset;
+  if (delta)
+    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_DELTA_UNIT);
 
   return buffer;
 }
 
 static void
-gst_ogg_mux_push_page (GstOggMux * mux, ogg_page * page)
+gst_ogg_mux_push_page (GstOggMux * mux, ogg_page * page, gboolean delta)
 {
   if (GST_PAD_IS_USABLE (mux->srcpad)) {
-    GstBuffer *buffer = gst_ogg_mux_buffer_from_page (mux, page);
+    GstBuffer *buffer = gst_ogg_mux_buffer_from_page (mux, page, delta);
 
     gst_pad_push (mux->srcpad, GST_DATA (buffer));
   }
@@ -714,7 +726,7 @@ gst_ogg_mux_send_headers (GstOggMux * mux)
 
     GST_LOG ("flushing page with first packet");
     while (ogg_stream_flush (&pad->stream, &page)) {
-      GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page);
+      GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
 
       GST_LOG ("swapped out page");
       hbufs = g_list_append (hbufs, hbuf);
@@ -758,7 +770,7 @@ gst_ogg_mux_send_headers (GstOggMux * mux)
         GST_LOG ("flushing page as packet %d is first or last packet",
             pad->packetno);
         while (ogg_stream_flush (&pad->stream, &page)) {
-          GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page);
+          GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
 
           GST_LOG ("swapped out page");
           hbufs = g_list_append (hbufs, hbuf);
@@ -767,7 +779,7 @@ gst_ogg_mux_send_headers (GstOggMux * mux)
         GST_LOG ("try to swap out page");
         /* just try to swap out a page then */
         while (ogg_stream_pageout (&pad->stream, &page) > 0) {
-          GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page);
+          GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
 
           GST_LOG ("swapped out page");
           hbufs = g_list_append (hbufs, hbuf);
@@ -820,6 +832,7 @@ gst_ogg_mux_loop (GstElement * element)
 {
   GstOggMux *ogg_mux;
   GstOggPad *best;
+  gboolean delta_unit;
 
   ogg_mux = GST_OGG_MUX (element);
 
@@ -838,11 +851,13 @@ gst_ogg_mux_loop (GstElement * element)
       ogg_page page;
 
       while (ogg_stream_flush (&ogg_mux->pulling->stream, &page)) {
-        gst_ogg_mux_push_page (ogg_mux, &page);
+        gst_ogg_mux_push_page (ogg_mux, &page, ogg_mux->pulling->first_delta);
         /* increment the page number counter */
         ogg_mux->pulling->pageno++;
+        ogg_mux->pulling->first_delta = TRUE;
       }
       ogg_mux->pulling = NULL;
+      ogg_mux->pulling->new_page = TRUE;
     }
   }
 
@@ -874,6 +889,7 @@ gst_ogg_mux_loop (GstElement * element)
     GstBuffer *buf, *tmpbuf;
     GstOggPad *pad = ogg_mux->pulling;
     gint64 duration;
+    gboolean force_flush;
 
     /* now see if we have a buffer */
     buf = pad->buffer;
@@ -888,6 +904,7 @@ gst_ogg_mux_loop (GstElement * element)
       }
     }
 
+    delta_unit = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_DELTA_UNIT);
     duration = GST_BUFFER_DURATION (buf);
 
     /* create a packet from the buffer */
@@ -908,40 +925,74 @@ gst_ogg_mux_loop (GstElement * element)
     /* mark EOS */
     packet.e_o_s = (tmpbuf == NULL ? 1 : 0);
 
-    /* swap the packet in */
-    ogg_stream_packetin (&pad->stream, &packet);
-
-    /* don't need the old buffer anymore */
-    gst_buffer_unref (pad->buffer);
-    /* store new readahead buffer */
-    pad->buffer = tmpbuf;
-
+    /* we flush when we see a new keyframe */
+    force_flush = (pad->prev_delta && !delta_unit);
     if (duration != -1) {
       pad->duration += duration;
       /* if page duration exceeds max, flush page */
       if (pad->duration > ogg_mux->max_page_delay) {
-        while (ogg_stream_flush (&pad->stream, &page)) {
-          gst_ogg_mux_push_page (ogg_mux, &page);
-          /* increment the page number counter */
-          pad->pageno++;
-        }
+        force_flush = TRUE;
         pad->duration = 0;
-        return;
       }
     }
 
-    /* flush out the pages now. The packet we got could end up in
-     * more than one page so we need to flush them all */
+    /* force flush */
+    if (force_flush) {
+      while (ogg_stream_flush (&pad->stream, &page)) {
+        gst_ogg_mux_push_page (ogg_mux, &page, pad->first_delta);
+        /* increment the page number counter */
+        pad->pageno++;
+        pad->first_delta = TRUE;
+      }
+      pad->new_page = TRUE;
+    }
+
+    /* if this is the first packet of a new page figure out the delta flag */
+    if (pad->new_page) {
+      if (delta_unit) {
+        /* This page is a delta frame */
+        if (ogg_mux->delta_pad == NULL) {
+          /* we got a delta unit on this pad */
+          ogg_mux->delta_pad = pad;
+        }
+        /* mark the page as delta */
+        pad->first_delta = TRUE;
+      } else {
+        /* got a keyframe */
+        if (ogg_mux->delta_pad == pad) {
+          /* if we get it on the pad with deltaunits,
+           * we mark the page as non delta */
+          pad->first_delta = FALSE;
+        }
+      }
+      pad->new_page = FALSE;
+    }
+
+    /* save key unit to track delta->key unit transitions */
+    pad->prev_delta = delta_unit;
+
+    /* swap the packet in */
+    ogg_stream_packetin (&pad->stream, &packet);
+
+    /* don't need the old buffer anymore */
+    gst_buffer_unref (pad->buffer);
+    /* store new readahead buffer */
+    pad->buffer = tmpbuf;
+
+    /* let ogg write out the pages now. The packet we got could end 
+     * up in more than one page so we need to write them all */
     while (ogg_stream_pageout (&pad->stream, &page) > 0) {
       /* we have a complete page now, we can push the page 
        * and make sure to pull on a new pad the next time around */
-      gst_ogg_mux_push_page (ogg_mux, &page);
+      gst_ogg_mux_push_page (ogg_mux, &page, pad->first_delta);
       /* increment the page number counter */
       pad->pageno++;
       /* we're done pulling on this pad, make sure to choose a new 
        * pad for pulling in the next iteration */
       ogg_mux->pulling = NULL;
+      pad->first_delta = TRUE;
       pad->duration = 0;
+      pad->new_page = TRUE;
     }
   }
 }