Index: gstdvddemux.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-ugly/gst/mpegstream/gstdvddemux.c,v
retrieving revision 1.39
diff -u -p -r1.39 gstdvddemux.c
--- gstdvddemux.c	9 Oct 2006 12:09:14 -0000	1.39
+++ gstdvddemux.c	2 Nov 2006 11:27:04 -0000
@@ -139,8 +139,6 @@ static void gst_dvd_demux_base_init (gpo
 static void gst_dvd_demux_init (GstDVDDemux * dvd_demux,
     GstDVDDemuxClass * klass);
 
-static GstFlowReturn gst_dvd_demux_send_buffer (GstMPEGParse * mpeg_parse,
-    GstBuffer * buffer, GstClockTime time);
 static gboolean gst_dvd_demux_process_event (GstMPEGParse * mpeg_parse,
     GstEvent * event);
 
@@ -167,6 +165,9 @@ static GstFlowReturn gst_dvd_demux_send_
     GstMPEGStream * outstream,
     GstBuffer * buffer, GstClockTime timestamp, guint offset, guint size);
 
+static GstFlowReturn gst_dvd_demux_combine_flows (GstMPEGDemux * mpegdemux,
+    GstMPEGStream * stream, GstFlowReturn flow);
+
 static void gst_dvd_demux_set_cur_audio
     (GstDVDDemux * dvd_demux, gint stream_nr);
 static void gst_dvd_demux_set_cur_subpicture
@@ -192,7 +193,7 @@ gst_dvd_demux_base_init (gpointer klass)
   GstMPEGDemuxClass *demux_class = GST_MPEG_DEMUX_CLASS (klass);
   GstDVDDemuxClass *dvd_demux_class = GST_DVD_DEMUX_CLASS (klass);
 
-  mpeg_parse_class->send_buffer = gst_dvd_demux_send_buffer;
+  mpeg_parse_class->send_buffer = NULL;
   mpeg_parse_class->process_event = gst_dvd_demux_process_event;
 
   /* sink pad */
@@ -245,6 +246,7 @@ gst_dvd_demux_class_init (GstDVDDemuxCla
   mpeg_demux_class->get_audio_stream = gst_dvd_demux_get_audio_stream;
   mpeg_demux_class->get_video_stream = gst_dvd_demux_get_video_stream;
   mpeg_demux_class->send_subbuffer = gst_dvd_demux_send_subbuffer;
+  mpeg_demux_class->combine_flows = gst_dvd_demux_combine_flows;
   mpeg_demux_class->process_private = gst_dvd_demux_process_private;
   mpeg_demux_class->synchronise_pads = gst_dvd_demux_synchronise_pads;
   mpeg_demux_class->sync_stream_to_time = gst_dvd_demux_sync_stream_to_time;
@@ -288,15 +290,6 @@ gst_dvd_demux_init (GstDVDDemux * dvd_de
   dvd_demux->langcodes = NULL;
 }
 
-
-static GstFlowReturn
-gst_dvd_demux_send_buffer (GstMPEGParse * mpeg_parse, GstBuffer * buffer,
-    GstClockTime time)
-{
-  gst_buffer_unref (buffer);
-  return GST_FLOW_OK;
-}
-
 static gboolean
 gst_dvd_demux_process_event (GstMPEGParse * mpeg_parse, GstEvent * event)
 {
@@ -918,6 +911,58 @@ gst_dvd_demux_process_private (GstMPEGDe
   return ret;
 }
 
+/* random magic value */
+#define MIN_BUFS_FOR_NO_MORE_PADS 100
+
+static GstFlowReturn
+gst_dvd_demux_combine_flows (GstMPEGDemux * mpegdemux, GstMPEGStream * stream,
+    GstFlowReturn flow)
+{
+  GstDVDDemux * demux = (GstDVDDemux *) mpegdemux;
+  gint i;
+
+  /* store the value */
+  stream->last_flow = flow;
+
+  /* if it's success we can return the value right away */
+  if (GST_FLOW_IS_SUCCESS (flow))
+    goto done;
+
+  /* any other error that is not-linked can be returned right
+   * away */
+  if (flow != GST_FLOW_NOT_LINKED) {
+    GST_DEBUG_OBJECT (demux, "flow %s on pad %" GST_PTR_FORMAT,
+        gst_flow_get_name (flow), stream->pad);
+    goto done;
+  }
+
+  /* let parent class check for anything non-not-linked for its streams */
+  flow = GST_MPEG_DEMUX_CLASS (parent_class)->combine_flows (mpegdemux, stream, flow);
+  if (flow != GST_FLOW_NOT_LINKED)
+    goto done;
+
+  /* only return NOT_LINKED if all other pads returned NOT_LINKED */
+  for (i = 0; i < GST_DVD_DEMUX_NUM_SUBPICTURE_STREAMS ; i++) {
+    if (demux->subpicture_stream[i] != NULL) {
+      flow = demux->subpicture_stream[i]->last_flow;
+      /* some other return value (must be SUCCESS but we can return
+       * other values as well) */
+      if (flow != GST_FLOW_NOT_LINKED)
+        goto done;
+      if (demux->subpicture_stream[i]->buffers_sent < MIN_BUFS_FOR_NO_MORE_PADS) {
+        flow = GST_FLOW_OK;
+        goto done;
+      }
+    }
+  }
+  /* if we get here, all other pads were unlinked and we return
+   * NOT_LINKED then */
+  GST_DEBUG_OBJECT (demux, "all pads combined have not-linked flow");
+
+done:
+  return flow;
+}
+
 static GstFlowReturn
 gst_dvd_demux_send_subbuffer (GstMPEGDemux * mpeg_demux,
     GstMPEGStream * outstream, GstBuffer * buffer,
@@ -987,10 +1032,22 @@ gst_dvd_demux_send_subbuffer (GstMPEGDem
     gst_buffer_set_caps (outbuf, outstream->caps);
 
     ret = gst_pad_push (outpad, outbuf);
+
+    /* this was one of the current_foo pads, which is shadowing one of the
+     * foo_%02d pads, so since we keep track of the last flow value in the
+     * stream structure we need to combine the OK/NOT_LINKED flows here
+     * (because both pads share the same stream structure) */
+    if ((ret == GST_FLOW_NOT_LINKED && outstream->last_flow == GST_FLOW_OK) ||
+        (ret == GST_FLOW_OK && outstream->last_flow == GST_FLOW_NOT_LINKED)) {
+      outstream->last_flow = GST_FLOW_OK;
+      ret = GST_FLOW_OK;
+    }
   }
 
   gst_buffer_unref (buffer);
 
+  ret = DEMUX_CLASS (dvd_demux)->combine_flows (mpeg_demux, outstream, ret);
+
   return ret;
 }
 
Index: gstmpegdemux.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-ugly/gst/mpegstream/gstmpegdemux.c,v
retrieving revision 1.92
diff -u -p -r1.92 gstmpegdemux.c
--- gstmpegdemux.c	9 Oct 2006 12:09:14 -0000	1.92
+++ gstmpegdemux.c	2 Nov 2006 11:27:05 -0000
@@ -92,9 +92,6 @@ GST_BOILERPLATE_FULL (GstMPEGDemux, gst_
 
 static void gst_mpeg_demux_class_init (GstMPEGDemuxClass * klass);
 
-static GstFlowReturn gst_mpeg_demux_send_buffer (GstMPEGParse * mpeg_parse,
-    GstBuffer * buffer, GstClockTime time);
-
 static GstPad *gst_mpeg_demux_new_output_pad (GstMPEGDemux * mpeg_demux,
     const gchar * name, GstPadTemplate * temp);
 static void gst_mpeg_demux_init_stream (GstMPEGDemux * mpeg_demux,
@@ -120,6 +117,8 @@ static GstFlowReturn gst_mpeg_demux_pars
 static GstFlowReturn gst_mpeg_demux_send_subbuffer (GstMPEGDemux * mpeg_demux,
     GstMPEGStream * outstream, GstBuffer * buffer,
     GstClockTime timestamp, guint offset, guint size);
+static GstFlowReturn gst_mpeg_demux_combine_flows (GstMPEGDemux * mpeg_demux,
+    GstMPEGStream * stream, GstFlowReturn flow);
 static GstFlowReturn gst_mpeg_demux_process_private (GstMPEGDemux * mpeg_demux,
     GstBuffer * buffer,
     guint stream_nr, GstClockTime timestamp, guint headerlen, guint datalen);
@@ -190,7 +189,7 @@ gst_mpeg_demux_class_init (GstMPEGDemuxC
   mpeg_parse_class->parse_syshead = gst_mpeg_demux_parse_syshead;
   mpeg_parse_class->parse_packet = gst_mpeg_demux_parse_packet;
   mpeg_parse_class->parse_pes = gst_mpeg_demux_parse_pes;
-  mpeg_parse_class->send_buffer = gst_mpeg_demux_send_buffer;
+  mpeg_parse_class->send_buffer = NULL;
 
   klass->new_output_pad = gst_mpeg_demux_new_output_pad;
   klass->init_stream = gst_mpeg_demux_init_stream;
@@ -198,6 +197,7 @@ gst_mpeg_demux_class_init (GstMPEGDemuxC
   klass->get_audio_stream = gst_mpeg_demux_get_audio_stream;
   klass->get_private_stream = gst_mpeg_demux_get_private_stream;
   klass->send_subbuffer = gst_mpeg_demux_send_subbuffer;
+  klass->combine_flows = gst_mpeg_demux_combine_flows;
   klass->process_private = gst_mpeg_demux_process_private;
   klass->synchronise_pads = gst_mpeg_demux_synchronise_pads;
   klass->sync_stream_to_time = gst_mpeg_demux_sync_stream_to_time;
@@ -229,14 +229,6 @@ gst_mpeg_demux_init (GstMPEGDemux * mpeg
   mpeg_demux->last_pts = -1;
 }
 
-static GstFlowReturn
-gst_mpeg_demux_send_buffer (GstMPEGParse * mpeg_parse, GstBuffer * buffer,
-    GstClockTime time)
-{
-  gst_buffer_unref (buffer);
-  return GST_FLOW_OK;
-}
-
 static gint
 _demux_get_writer_id (GstIndex * index, GstPad * pad)
 {
@@ -291,6 +283,9 @@ gst_mpeg_demux_init_stream (GstMPEGDemux
 
   str->cur_ts = 0;
   str->scr_offs = 0;
+
+  str->last_flow = GST_FLOW_OK;
+  str->buffers_sent = 0;
 }
 
 static GstMPEGStream *
@@ -712,12 +707,12 @@ done:
   if (id == 0xBD) {
     /* Private stream 1. */
     GST_DEBUG_OBJECT (mpeg_demux, "we have a private 1 packet");
-    CLASS (mpeg_demux)->process_private (mpeg_demux, buffer, 0, timestamp,
+    ret = CLASS (mpeg_demux)->process_private (mpeg_demux, buffer, 0, timestamp,
         headerlen, datalen);
   } else if (id == 0xBF) {
     /* Private stream 2. */
     GST_DEBUG_OBJECT (mpeg_demux, "we have a private 2 packet");
-    CLASS (mpeg_demux)->process_private (mpeg_demux, buffer, 1, timestamp,
+    ret = CLASS (mpeg_demux)->process_private (mpeg_demux, buffer, 1, timestamp,
         headerlen, datalen);
   } else if (id >= 0xC0 && id <= 0xDF) {
     /* Audio. */
@@ -855,13 +850,13 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *
   if (id == 0xBD) {
     /* Private stream 1. */
     GST_DEBUG_OBJECT (mpeg_demux, "we have a private 1 packet");
-    CLASS (mpeg_demux)->process_private (mpeg_demux, buffer, 0, timestamp,
-        headerlen, datalen);
+    ret = CLASS (mpeg_demux)->process_private (mpeg_demux, buffer, 0,
+        timestamp, headerlen, datalen);
   } else if (id == 0xBF) {
     /* Private stream 2. */
     GST_DEBUG_OBJECT (mpeg_demux, "we have a private 2 packet");
-    CLASS (mpeg_demux)->process_private (mpeg_demux, buffer, 1, timestamp,
-        headerlen, datalen);
+    ret = CLASS (mpeg_demux)->process_private (mpeg_demux, buffer, 1,
+        timestamp, headerlen, datalen);
   } else if (id >= 0xC0 && id <= 0xDF) {
     /* Audio. */
     GST_DEBUG_OBJECT (mpeg_demux, "we have an audio packet");
@@ -886,6 +881,78 @@ gst_mpeg_demux_parse_pes (GstMPEGParse *
   return ret;
 }
 
+/* random magic value */
+#define MIN_BUFS_FOR_NO_MORE_PADS 100
+
+static GstFlowReturn
+gst_mpeg_demux_combine_flows (GstMPEGDemux * demux, GstMPEGStream * stream,
+    GstFlowReturn flow)
+{
+  gint i;
+
+  /* store the value */
+  stream->last_flow = flow;
+
+  /* if it's success we can return the value right away */
+  if (GST_FLOW_IS_SUCCESS (flow))
+    goto done;
+
+  /* any other error that is not-linked can be returned right
+   * away */
+  if (flow != GST_FLOW_NOT_LINKED) {
+    GST_DEBUG_OBJECT (demux, "flow %s on pad %" GST_PTR_FORMAT,
+        gst_flow_get_name (flow), stream->pad);
+    goto done;
+  }
+
+  /* only return NOT_LINKED if all other pads returned NOT_LINKED */
+  for (i = 0; i < GST_MPEG_DEMUX_NUM_VIDEO_STREAMS; i++) {
+    if (demux->video_stream[i] != NULL) {
+      flow = demux->video_stream[i]->last_flow;
+      /* some other return value (must be SUCCESS but we can return
+       * other values as well) */
+      if (flow != GST_FLOW_NOT_LINKED)
+        goto done;
+      if (demux->video_stream[i]->buffers_sent < MIN_BUFS_FOR_NO_MORE_PADS) {
+        flow = GST_FLOW_OK;
+        goto done;
+      }
+    }
+  }
+  for (i = 0; i < GST_MPEG_DEMUX_NUM_AUDIO_STREAMS; i++) {
+    if (demux->audio_stream[i] != NULL) {
+      flow = demux->audio_stream[i]->last_flow;
+      /* some other return value (must be SUCCESS but we can return
+       * other values as well) */
+      if (flow != GST_FLOW_NOT_LINKED)
+        goto done;
+      if (demux->audio_stream[i]->buffers_sent < MIN_BUFS_FOR_NO_MORE_PADS) {
+        flow = GST_FLOW_OK;
+        goto done;
+      }
+    }
+  }
+  for (i = 0; i < GST_MPEG_DEMUX_NUM_PRIVATE_STREAMS; i++) {
+    if (demux->private_stream[i] != NULL) {
+      flow = demux->private_stream[i]->last_flow;
+      /* some other return value (must be SUCCESS but we can return
+       * other values as well) */
+      if (flow != GST_FLOW_NOT_LINKED)
+        goto done;
+      if (demux->private_stream[i]->buffers_sent < MIN_BUFS_FOR_NO_MORE_PADS) {
+        flow = GST_FLOW_OK;
+        goto done;
+      }
+    }
+  }
+  /* if we get here, all other pads were unlinked and we return
+   * NOT_LINKED then */
+  GST_DEBUG_OBJECT (demux, "all pads combined have not-linked flow");
+
+done:
+  return flow;
+}
+
 static GstFlowReturn
 gst_mpeg_demux_send_subbuffer (GstMPEGDemux * mpeg_demux,
     GstMPEGStream * outstream, GstBuffer * buffer,
@@ -927,6 +994,8 @@ gst_mpeg_demux_send_subbuffer (GstMPEGDe
   GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
   GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buffer) + offset;
   ret = gst_pad_push (outstream->pad, outbuf);
+  GST_LOG ("flow on %s: %s", GST_PAD_NAME (outstream->pad), gst_flow_get_name (ret));
+  ++outstream->buffers_sent;
 
   if (GST_CLOCK_TIME_IS_VALID (mpeg_demux->max_gap) &&
       GST_CLOCK_TIME_IS_VALID (mpeg_parse->current_ts) &&
@@ -936,6 +1005,8 @@ gst_mpeg_demux_send_subbuffer (GstMPEGDe
         mpeg_parse->current_ts - mpeg_demux->max_gap_tolerance);
   }
 
+  ret = CLASS (mpeg_demux)->combine_flows (mpeg_demux, outstream, ret);
+
   return ret;
 }
 
Index: gstmpegdemux.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-ugly/gst/mpegstream/gstmpegdemux.h,v
retrieving revision 1.25
diff -u -p -r1.25 gstmpegdemux.h
--- gstmpegdemux.h	1 Jun 2006 21:11:41 -0000	1.25
+++ gstmpegdemux.h	2 Nov 2006 11:27:05 -0000
@@ -88,14 +88,16 @@ typedef struct _GstMPEGDemuxClass GstMPE
 
 /* Information associated to a single MPEG stream. */
 struct _GstMPEGStream {
-  gint          type;
-  gint          number;
-  GstPad        *pad;
-  GstCaps	*caps;
-  gint          index_id;
-  gint          size_bound;
-  GstClockTime  cur_ts;
-  GstClockTimeDiff scr_offs;
+  gint              type;
+  gint              number;
+  GstPad           *pad;
+  GstCaps          *caps;
+  gint              index_id;
+  gint              size_bound;
+  GstClockTime      cur_ts;
+  GstClockTimeDiff  scr_offs;
+  GstFlowReturn     last_flow;
+  guint             buffers_sent;
 };
 
 /* Extended structure to hold additional information for video
@@ -183,6 +185,10 @@ struct _GstMPEGDemuxClass {
                                           guint size);
 
 
+  GstFlowReturn (*combine_flows)        (GstMPEGDemux  *mpeg_demux,
+                                         GstMPEGStream *stream,
+                                         GstFlowReturn  flow);
+
   GstFlowReturn (*process_private)      (GstMPEGDemux *mpeg_demux,
                                          GstBuffer *buffer,
                                          guint stream_nr,
Index: gstmpegparse.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-ugly/gst/mpegstream/gstmpegparse.c,v
retrieving revision 1.96
diff -u -p -r1.96 gstmpegparse.c
--- gstmpegparse.c	16 Oct 2006 18:07:23 -0000	1.96
+++ gstmpegparse.c	2 Nov 2006 11:27:06 -0000
@@ -407,6 +407,9 @@ gst_mpeg_parse_process_event (GstMPEGPar
       gst_mpeg_packetize_flush_cache (mpeg_parse->packetize);
       break;
     }
+    case GST_EVENT_EOS:
+      GST_DEBUG_OBJECT (mpeg_parse, "EOS");
+      /* fall through to default handler */
     default:
       if (CLASS (mpeg_parse)->send_event) {
         ret = CLASS (mpeg_parse)->send_event (mpeg_parse, event);
@@ -684,8 +687,8 @@ gst_mpeg_parse_event (GstPad * pad, GstE
 static GstFlowReturn
 gst_mpeg_parse_chain (GstPad * pad, GstBuffer * buffer)
 {
-  GstMPEGParse *mpeg_parse = GST_MPEG_PARSE (gst_pad_get_parent (pad));
-  GstFlowReturn result = GST_FLOW_ERROR;
+  GstMPEGParse *mpeg_parse = GST_MPEG_PARSE (GST_PAD_PARENT (pad));
+  GstFlowReturn result;
   guint id;
   gboolean mpeg2;
   GstClockTime time;
@@ -704,10 +707,10 @@ gst_mpeg_parse_chain (GstPad * pad, GstB
     if (result == GST_FLOW_RESEND) {
       /* there was not enough data in packetizer cache */
       result = GST_FLOW_OK;
-      goto done;
+      break;
     }
     if (result != GST_FLOW_OK)
-      goto done;
+      break;
 
     id = GST_MPEG_PACKETIZE_ID (mpeg_parse->packetize);
     mpeg2 = GST_MPEG_PACKETIZE_IS_MPEG2 (mpeg_parse->packetize);
@@ -749,7 +752,7 @@ gst_mpeg_parse_chain (GstPad * pad, GstB
       GST_DEBUG_OBJECT (mpeg_parse, "waiting for SCR");
       gst_buffer_unref (buffer);
       result = GST_FLOW_OK;
-      goto done;
+      break;
     }
 
     /* Update the byte count. */
@@ -768,7 +771,7 @@ gst_mpeg_parse_chain (GstPad * pad, GstB
         GST_ELEMENT_ERROR (mpeg_parse, CORE, NEGOTIATION, (NULL), (NULL));
         gst_buffer_unref (buffer);
         result = GST_FLOW_ERROR;
-        goto done;
+        break;
       }
     }
 
@@ -819,13 +822,11 @@ gst_mpeg_parse_chain (GstPad * pad, GstB
           ", total since SCR: %" G_GINT64_FORMAT ", br: %" G_GINT64_FORMAT
           ", next SCR: %" G_GINT64_FORMAT, size, bss, br, mpeg_parse->next_scr);
     }
-  } while (!GST_FLOW_IS_FATAL (result));
-
-done:
-  gst_object_unref (mpeg_parse);
+  } while (GST_FLOW_IS_SUCCESS (result));
 
-  if (result == GST_FLOW_NOT_LINKED)
-    result = GST_FLOW_OK;
+  if (result != GST_FLOW_OK) {
+    GST_DEBUG_OBJECT (mpeg_parse, "flow: %s", gst_flow_get_name (result));
+  }
 
   return result;
 }
