avidemux: fix memory leak
[platform/upstream/gst-plugins-good.git] / gst / avi / gstavidemux.c
index 0dc2517..3fd44c2 100644 (file)
@@ -37,8 +37,6 @@
  * compressed audio or video data, this will only work if you have the
  * right decoder elements/plugins installed.
  * </refsect2>
- *
- * Last reviewed on 2006-12-29 (0.10.6)
  */
 
 #ifdef HAVE_CONFIG_H
@@ -137,7 +135,7 @@ gst_avi_demux_class_init (GstAviDemuxClass * klass)
   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
   GObjectClass *gobject_class = (GObjectClass *) klass;
   GstPadTemplate *videosrctempl, *audiosrctempl, *subsrctempl, *subpicsrctempl;
-  GstCaps *audcaps, *vidcaps, *subcaps, *subpiccaps;;
+  GstCaps *audcaps, *vidcaps, *subcaps, *subpiccaps;
 
   GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux",
       0, "Demuxer for AVI streams");
@@ -181,6 +179,11 @@ gst_avi_demux_class_init (GstAviDemuxClass * klass)
       "Erik Walthinsen <omega@cse.ogi.edu>, "
       "Wim Taymans <wim.taymans@chello.be>, "
       "Thijs Vermeir <thijsvermeir@gmail.com>");
+
+  gst_caps_unref(audcaps);
+  gst_caps_unref(vidcaps);
+  gst_caps_unref(subcaps);
+  gst_caps_unref(subpiccaps);
 }
 
 static void
@@ -198,6 +201,7 @@ gst_avi_demux_init (GstAviDemux * avi)
   gst_element_add_pad (GST_ELEMENT_CAST (avi), avi->sinkpad);
 
   avi->adapter = gst_adapter_new ();
+  avi->flowcombiner = gst_flow_combiner_new ();
 
   gst_avi_demux_reset (avi);
 
@@ -212,6 +216,7 @@ gst_avi_demux_finalize (GObject * object)
   GST_DEBUG ("AVI: finalize");
 
   g_object_unref (avi->adapter);
+  gst_flow_combiner_free (avi->flowcombiner);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -234,6 +239,7 @@ gst_avi_demux_reset_stream (GstAviDemux * avi, GstAviStream * stream)
     if (stream->exposed) {
       gst_pad_set_active (stream->pad, FALSE);
       gst_element_remove_pad (GST_ELEMENT_CAST (avi), stream->pad);
+      gst_flow_combiner_remove_pad (avi->flowcombiner, stream->pad);
     } else
       gst_object_unref (stream->pad);
   }
@@ -466,7 +472,7 @@ gst_avi_demux_handle_src_query (GstPad * pad, GstObject * parent,
         if (stream->is_vbr) {
           /* VBR */
           pos = avi_stream_convert_frames_to_time_unchecked (stream,
-              stream->current_total);
+              stream->current_entry);
           GST_DEBUG_OBJECT (avi, "VBR convert frame %u, time %"
               GST_TIME_FORMAT, stream->current_entry, GST_TIME_ARGS (pos));
         } else if (stream->strf.auds->av_bps != 0) {
@@ -481,18 +487,11 @@ gst_avi_demux_handle_src_query (GstPad * pad, GstObject * parent,
           guint64 xlen = avi->avih->us_frame *
               avi->avih->tot_frames * GST_USECOND;
 
-          if (stream->is_vbr) {
-            pos = gst_util_uint64_scale (xlen, stream->current_entry,
-                stream->idx_n);
-            GST_DEBUG_OBJECT (avi, "VBR perc convert frame %u, time %"
-                GST_TIME_FORMAT, stream->current_entry, GST_TIME_ARGS (pos));
-          } else {
-            pos = gst_util_uint64_scale (xlen, stream->current_total,
-                stream->total_bytes);
-            GST_DEBUG_OBJECT (avi,
-                "CBR perc convert bytes %u, time %" GST_TIME_FORMAT,
-                stream->current_total, GST_TIME_ARGS (pos));
-          }
+          pos = gst_util_uint64_scale (xlen, stream->current_total,
+              stream->total_bytes);
+          GST_DEBUG_OBJECT (avi,
+              "CBR perc convert bytes %u, time %" GST_TIME_FORMAT,
+              stream->current_total, GST_TIME_ARGS (pos));
         } else {
           /* we don't know */
           res = FALSE;
@@ -672,7 +671,7 @@ gst_avi_demux_seek_streams (GstAviDemux * avi, guint64 offset, gboolean before)
 }
 #endif
 
-static guint
+static gint
 gst_avi_demux_index_entry_offset_search (GstAviIndexEntry * entry,
     guint64 * offset)
 {
@@ -900,7 +899,6 @@ gst_avi_demux_handle_sink_event (GstPad * pad, GstObject * parent,
       gst_adapter_clear (avi->adapter);
       avi->have_eos = FALSE;
       for (i = 0; i < avi->num_streams; i++) {
-        avi->stream[i].last_flow = GST_FLOW_OK;
         avi->stream[i].discont = TRUE;
       }
       /* fall through to default case so that the event gets passed downstream */
@@ -1072,8 +1070,7 @@ gst_avi_demux_parse_file_header (GstElement * element, GstBuffer * buf)
 not_avi:
   {
     GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
-        ("File is not an AVI file: %" GST_FOURCC_FORMAT,
-            GST_FOURCC_ARGS (doctype)));
+        ("File is not an AVI file: 0x%" G_GINT32_MODIFIER "x", doctype));
     return FALSE;
   }
 }
@@ -1888,6 +1885,7 @@ gst_avi_demux_expose_streams (GstAviDemux * avi, gboolean force)
     if (force || stream->idx_n != 0) {
       GST_LOG_OBJECT (avi, "Adding pad %s", GST_PAD_NAME (stream->pad));
       gst_element_add_pad ((GstElement *) avi, stream->pad);
+      gst_flow_combiner_add_pad (avi->flowcombiner, stream->pad);
 
 #if 0
       if (avi->element_index)
@@ -2023,6 +2021,7 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
   gst_riff_vprp *vprp = NULL;
   GstEvent *event;
   gchar *stream_id;
+  GstMapInfo map;
 
   element = GST_ELEMENT_CAST (avi);
 
@@ -2216,22 +2215,17 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
         break;
       case GST_RIFF_TAG_strn:
         g_free (stream->name);
-        if (sub != NULL) {
-          GstMapInfo map;
 
-          gst_buffer_map (sub, &map, GST_MAP_READ);
-          stream->name = g_strndup ((gchar *) map.data, map.size);
-          gst_buffer_unmap (sub, &map);
-          gst_buffer_unref (sub);
-          sub = NULL;
+        gst_buffer_map (sub, &map, GST_MAP_READ);
+        stream->name = g_strndup ((gchar *) map.data, map.size);
+        gst_buffer_unmap (sub, &map);
+        gst_buffer_unref (sub);
+        sub = NULL;
 
-          if (avi->globaltags == NULL)
-            avi->globaltags = gst_tag_list_new_empty ();
-          gst_tag_list_add (avi->globaltags, GST_TAG_MERGE_REPLACE,
-              GST_TAG_TITLE, stream->name, NULL);
-        } else {
-          stream->name = g_strdup ("");
-        }
+        if (avi->globaltags == NULL)
+          avi->globaltags = gst_tag_list_new_empty ();
+        gst_tag_list_add (avi->globaltags, GST_TAG_MERGE_REPLACE,
+            GST_TAG_TITLE, stream->name, NULL);
         GST_DEBUG_OBJECT (avi, "stream name: %s", stream->name);
         break;
       case GST_RIFF_IDIT:
@@ -2410,7 +2404,6 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
   stream->current_entry = -1;
   stream->current_total = 0;
 
-  stream->last_flow = GST_FLOW_OK;
   stream->discont = TRUE;
 
   stream->total_bytes = 0;
@@ -3021,7 +3014,7 @@ static GstFlowReturn
 gst_avi_demux_peek_tag (GstAviDemux * avi, guint64 offset, guint32 * tag,
     guint * size)
 {
-  GstFlowReturn res = GST_FLOW_OK;
+  GstFlowReturn res;
   GstBuffer *buf = NULL;
   GstMapInfo map;
 
@@ -3477,6 +3470,7 @@ gst_avi_demux_stream_header_push (GstAviDemux * avi)
                     if (avi->globaltags) {
                       gst_tag_list_insert (avi->globaltags, tags,
                           GST_TAG_MERGE_REPLACE);
+                      gst_tag_list_unref (tags);
                     } else {
                       avi->globaltags = tags;
                     }
@@ -4063,6 +4057,7 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi)
               if (avi->globaltags) {
                 gst_tag_list_insert (avi->globaltags, tags,
                     GST_TAG_MERGE_REPLACE);
+                gst_tag_list_unref (tags);
               } else {
                 avi->globaltags = tags;
               }
@@ -4079,6 +4074,7 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi)
               if (avi->globaltags) {
                 gst_tag_list_insert (avi->globaltags, tags,
                     GST_TAG_MERGE_REPLACE);
+                gst_tag_list_unref (tags);
               } else {
                 avi->globaltags = tags;
               }
@@ -4192,6 +4188,7 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi)
               if (avi->globaltags) {
                 gst_tag_list_insert (avi->globaltags, tags,
                     GST_TAG_MERGE_REPLACE);
+                gst_tag_list_unref (tags);
               } else {
                 avi->globaltags = tags;
               }
@@ -4226,6 +4223,7 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi)
               if (avi->globaltags) {
                 gst_tag_list_insert (avi->globaltags, tags,
                     GST_TAG_MERGE_REPLACE);
+                gst_tag_list_unref (tags);
               } else {
                 avi->globaltags = tags;
               }
@@ -4367,9 +4365,11 @@ no_index:
   }
 pull_range_failed:
   {
+    if (res == GST_FLOW_FLUSHING)
+      return res;
     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
         ("pull_range flow reading header: %s", gst_flow_get_name (res)));
-    return GST_FLOW_ERROR;
+    return res;
   }
 }
 
@@ -4644,9 +4644,10 @@ gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad, GstEvent * event)
   /* reset the last flow and mark discont, seek is always DISCONT */
   for (i = 0; i < avi->num_streams; i++) {
     GST_DEBUG_OBJECT (avi, "marking DISCONT");
-    avi->stream[i].last_flow = GST_FLOW_OK;
     avi->stream[i].discont = TRUE;
   }
+  /* likewise for the whole new segment */
+  gst_flow_combiner_reset (avi->flowcombiner);
   GST_PAD_STREAM_UNLOCK (avi->sinkpad);
 
   return TRUE;
@@ -5009,37 +5010,11 @@ static GstFlowReturn
 gst_avi_demux_combine_flows (GstAviDemux * avi, GstAviStream * stream,
     GstFlowReturn ret)
 {
-  guint i;
-  gboolean unexpected = FALSE, not_linked = TRUE;
-
-  /* store the value */
-  stream->last_flow = ret;
+  GST_LOG_OBJECT (avi, "Stream %s:%s flow return: %s",
+      GST_DEBUG_PAD_NAME (stream->pad), gst_flow_get_name (ret));
+  ret = gst_flow_combiner_update_pad_flow (avi->flowcombiner, stream->pad, ret);
+  GST_LOG_OBJECT (avi, "combined to return %s", gst_flow_get_name (ret));
 
-  /* any other error that is not-linked or eos can be returned right away */
-  if (G_LIKELY (ret != GST_FLOW_EOS && 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++) {
-    GstAviStream *ostream = &avi->stream[i];
-
-    ret = ostream->last_flow;
-    /* no unexpected or unlinked, return */
-    if (G_LIKELY (ret != GST_FLOW_EOS && 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_EOS);
-    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_EOS;
-done:
-  GST_LOG_OBJECT (avi, "combined %s to return %s",
-      gst_flow_get_name (stream->last_flow), gst_flow_get_name (ret));
   return ret;
 }
 
@@ -5098,7 +5073,6 @@ gst_avi_demux_advance (GstAviDemux * avi, GstAviStream * stream,
           &stream->current_timestamp, &stream->current_ts_end,
           &stream->current_offset, &stream->current_offset_end);
       /* and MARK discont for this stream */
-      stream->last_flow = GST_FLOW_OK;
       stream->discont = TRUE;
       GST_DEBUG_OBJECT (avi, "Moved from %u to %u, ts %" GST_TIME_FORMAT
           ", ts_end %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
@@ -5140,7 +5114,7 @@ gst_avi_demux_find_next (GstAviDemux * avi, gfloat rate)
     stream = &avi->stream[i];
 
     /* ignore streams that finished */
-    if (stream->last_flow == GST_FLOW_EOS)
+    if (stream->pad && GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS)
       continue;
 
     position = stream->current_timestamp;
@@ -5794,8 +5768,10 @@ gst_avi_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
       GST_OBJECT_UNLOCK (avi);
 
       /* calculate and perform seek */
-      if (!avi_demux_handle_seek_push (avi, avi->sinkpad, event))
+      if (!avi_demux_handle_seek_push (avi, avi->sinkpad, event)) {
+        gst_event_unref (event);
         goto seek_failed;
+      }
 
       gst_event_unref (event);
       avi->state = GST_AVI_DEMUX_MOVI;