docs/libs/tmpl/gstcolorbalance.sgml: Updated.
authorJulien Moutte <julien@moutte.net>
Sun, 5 Feb 2006 16:03:48 +0000 (16:03 +0000)
committerJulien Moutte <julien@moutte.net>
Sun, 5 Feb 2006 16:03:48 +0000 (16:03 +0000)
Original commit message from CVS:
2006-02-05  Julien MOUTTE  <julien@moutte.net>

* docs/libs/tmpl/gstcolorbalance.sgml: Updated.
* ext/pango/gsttextoverlay.c: (gst_text_overlay_init),
(gst_text_overlay_src_event), (gst_text_overlay_collected):
* gst/subparse/gstsubparse.c: (gst_sub_parse_dispose),
(gst_sub_parse_class_init), (gst_sub_parse_init),
(gst_sub_parse_src_event), (parse_mdvdsub), (parse_subrip),
(parse_mpsub), (parser_state_init), (handle_buffer),
(gst_sub_parse_chain), (gst_sub_parse_sink_event),
(plugin_init):
* gst/subparse/gstsubparse.h: Introduce seeking code.

ChangeLog
docs/libs/tmpl/gstcolorbalance.sgml
ext/pango/gsttextoverlay.c
gst/subparse/gstsubparse.c
gst/subparse/gstsubparse.h

index 0d97681..9044201 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2006-02-05  Julien MOUTTE  <julien@moutte.net>
+
+       * docs/libs/tmpl/gstcolorbalance.sgml: Updated.
+       * ext/pango/gsttextoverlay.c: (gst_text_overlay_init),
+       (gst_text_overlay_src_event), (gst_text_overlay_collected):
+       * gst/subparse/gstsubparse.c: (gst_sub_parse_dispose),
+       (gst_sub_parse_class_init), (gst_sub_parse_init),
+       (gst_sub_parse_src_event), (parse_mdvdsub), (parse_subrip),
+       (parse_mpsub), (parser_state_init), (handle_buffer),
+       (gst_sub_parse_chain), (gst_sub_parse_sink_event), (plugin_init):
+       * gst/subparse/gstsubparse.h: Introduce seeking code.
+
 2006-02-05  Tim-Philipp Müller  <tim at centricular dot net>
 
        * gst-libs/gst/tag/gstvorbistag.c: (gst_vorbis_tag_add):
index 7ac9f04..ccb0ae2 100644 (file)
@@ -23,6 +23,15 @@ interface for adjusting color balance settings
 </para>
 
 
+<!-- ##### SIGNAL GstColorBalance::value-changed ##### -->
+<para>
+
+</para>
+
+@gstcolorbalance: the object which received the signal.
+@arg1: 
+@arg2: 
+
 <!-- ##### STRUCT GstColorBalanceClass ##### -->
 <para>
 
index 150c128..c8ea906 100644 (file)
@@ -152,9 +152,7 @@ static GstStateChangeReturn gst_text_overlay_change_state (GstElement * element,
     GstStateChange transition);
 static GstCaps *gst_text_overlay_getcaps (GstPad * pad);
 static gboolean gst_text_overlay_setcaps (GstPad * pad, GstCaps * caps);
-static GstPadLinkReturn gst_text_overlay_text_pad_linked (GstPad * pad,
-    GstPad * peer);
-static void gst_text_overlay_text_pad_unlinked (GstPad * pad);
+static gboolean gst_text_overlay_src_event (GstPad * pad, GstEvent * event);
 static GstFlowReturn gst_text_overlay_collected (GstCollectPads * pads,
     gpointer data);
 static void gst_text_overlay_finalize (GObject * object);
@@ -295,10 +293,6 @@ gst_text_overlay_init (GstTextOverlay * overlay, GstTextOverlayClass * klass)
     overlay->text_sinkpad =
         gst_pad_new_from_template (gst_static_pad_template_get
         (&text_sink_template_factory), "text_sink");
-    gst_pad_set_link_function (overlay->text_sinkpad,
-        GST_DEBUG_FUNCPTR (gst_text_overlay_text_pad_linked));
-    gst_pad_set_unlink_function (overlay->text_sinkpad,
-        GST_DEBUG_FUNCPTR (gst_text_overlay_text_pad_unlinked));
     gst_element_add_pad (GST_ELEMENT (overlay), overlay->text_sinkpad);
   }
 
@@ -308,6 +302,8 @@ gst_text_overlay_init (GstTextOverlay * overlay, GstTextOverlayClass * klass)
       (&src_template_factory), "src");
   gst_pad_set_getcaps_function (overlay->srcpad,
       GST_DEBUG_FUNCPTR (gst_text_overlay_getcaps));
+  gst_pad_set_event_function (overlay->srcpad,
+      GST_DEBUG_FUNCPTR (gst_text_overlay_src_event));
   gst_element_add_pad (GST_ELEMENT (overlay), overlay->srcpad);
 
   overlay->layout =
@@ -339,9 +335,8 @@ gst_text_overlay_init (GstTextOverlay * overlay, GstTextOverlayClass * klass)
 
   overlay->video_collect_data = gst_collect_pads_add_pad (overlay->collect,
       overlay->video_sinkpad, sizeof (GstCollectData));
-
-  /* text pad will be added when it is linked */
-  overlay->text_collect_data = NULL;
+  overlay->text_collect_data = gst_collect_pads_add_pad (overlay->collect,
+      overlay->text_sinkpad, sizeof (GstCollectData));
 }
 
 static void
@@ -399,43 +394,6 @@ gst_text_overlay_setcaps (GstPad * pad, GstCaps * caps)
   return ret;
 }
 
-static GstPadLinkReturn
-gst_text_overlay_text_pad_linked (GstPad * pad, GstPad * peer)
-{
-  GstTextOverlay *overlay;
-
-  overlay = GST_TEXT_OVERLAY (GST_PAD_PARENT (pad));
-
-  GST_DEBUG_OBJECT (overlay, "Text pad linked");
-
-  if (overlay->text_collect_data == NULL) {
-    overlay->text_collect_data = gst_collect_pads_add_pad (overlay->collect,
-        overlay->text_sinkpad, sizeof (GstCollectData));
-  }
-
-  overlay->need_render = TRUE;
-
-  return GST_PAD_LINK_OK;
-}
-
-static void
-gst_text_overlay_text_pad_unlinked (GstPad * pad)
-{
-  GstTextOverlay *overlay;
-
-  /* don't use gst_pad_get_parent() here, will deadlock */
-  overlay = GST_TEXT_OVERLAY (GST_PAD_PARENT (pad));
-
-  GST_DEBUG_OBJECT (overlay, "Text pad unlinked");
-
-  if (overlay->text_collect_data) {
-    gst_collect_pads_remove_pad (overlay->collect, overlay->text_sinkpad);
-    overlay->text_collect_data = NULL;
-  }
-
-  overlay->need_render = TRUE;
-}
-
 static void
 gst_text_overlay_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
@@ -545,6 +503,64 @@ gst_text_overlay_set_property (GObject * object, guint prop_id,
   GST_OBJECT_UNLOCK (overlay);
 }
 
+static gboolean
+gst_text_overlay_src_event (GstPad * pad, GstEvent * event)
+{
+  gboolean ret = FALSE;
+  GstTextOverlay *overlay = NULL;
+
+  overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEEK:
+
+      GST_DEBUG_OBJECT (overlay, "seek received, driving from here");
+
+      /* Flush downstream */
+      gst_pad_push_event (overlay->srcpad, gst_event_new_flush_start ());
+
+      /* Stopping collect pads */
+      gst_collect_pads_stop (overlay->collect);
+
+      /* Flush upstream, this is required so that we can take the stream lock
+         safely */
+      gst_pad_push_event (overlay->video_sinkpad, gst_event_new_flush_start ());
+      gst_pad_push_event (overlay->text_sinkpad, gst_event_new_flush_start ());
+
+      /* Acquire stream lock */
+      GST_PAD_STREAM_LOCK (overlay->video_sinkpad);
+      GST_PAD_STREAM_LOCK (overlay->text_sinkpad);
+
+      /* Seek on each sink pad */
+      gst_event_ref (event);
+      ret = gst_pad_push_event (overlay->video_sinkpad, event);
+      if (ret) {
+        ret = gst_pad_push_event (overlay->text_sinkpad, event);
+      } else {
+        gst_event_unref (event);
+      }
+
+      /* Stop flushing upstream */
+      gst_pad_push_event (overlay->video_sinkpad, gst_event_new_flush_stop ());
+      gst_pad_push_event (overlay->text_sinkpad, gst_event_new_flush_stop ());
+
+      /* Start collect pads again */
+      gst_collect_pads_start (overlay->collect);
+
+      /* Release stream lock */
+      GST_PAD_STREAM_UNLOCK (overlay->video_sinkpad);
+      GST_PAD_STREAM_UNLOCK (overlay->text_sinkpad);
+      break;
+    default:
+      gst_event_ref (event);
+      ret = gst_pad_push_event (overlay->video_sinkpad, event);
+      ret = gst_pad_push_event (overlay->text_sinkpad, event);
+  }
+
+  gst_object_unref (overlay);
+
+  return ret;
+}
 
 static GstCaps *
 gst_text_overlay_getcaps (GstPad * pad)
@@ -876,6 +892,22 @@ gst_text_overlay_collected (GstCollectPads * pads, gpointer data)
 
   GST_DEBUG ("Collecting");
 
+  if (overlay->video_collect_data->abidata.ABI.new_segment) {
+
+    GST_DEBUG ("generating newsegment, start %" GST_TIME_FORMAT
+        ", stop %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (overlay->video_collect_data->segment.start),
+        GST_TIME_ARGS (overlay->video_collect_data->segment.stop));
+
+    gst_pad_push_event (overlay->srcpad, gst_event_new_new_segment (FALSE,
+            overlay->video_collect_data->segment.rate, GST_FORMAT_TIME,
+            overlay->video_collect_data->segment.start,
+            overlay->video_collect_data->segment.stop,
+            overlay->video_collect_data->segment.last_stop));
+
+    overlay->video_collect_data->abidata.ABI.new_segment = FALSE;
+  }
+
   video_frame = gst_collect_pads_peek (overlay->collect,
       overlay->video_collect_data);
 
index 1e554ba..cbfc10a 100644 (file)
@@ -56,10 +56,6 @@ static GstStateChangeReturn gst_sub_parse_change_state (GstElement * element,
 
 static GstFlowReturn gst_sub_parse_chain (GstPad * sinkpad, GstBuffer * buf);
 
-#if 0
-static GstCaps *gst_sub_parse_type_find (GstBuffer * buf, gpointer private);
-#endif
-
 static GstElementClass *parent_class = NULL;
 
 GType
@@ -107,12 +103,30 @@ gst_sub_parse_base_init (GstSubParseClass * klass)
 }
 
 static void
+gst_sub_parse_dispose (GObject * object)
+{
+  GstSubParse *subparse = GST_SUBPARSE (object);
+
+  GST_DEBUG_OBJECT (subparse, "cleaning up subtitle parser");
+
+  if (subparse->segment) {
+    gst_segment_free (subparse->segment);
+    subparse->segment = NULL;
+  }
+
+  GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+}
+
+static void
 gst_sub_parse_class_init (GstSubParseClass * klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
 
   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
 
+  object_class->dispose = gst_sub_parse_dispose;
+
   element_class->change_state = gst_sub_parse_change_state;
 }
 
@@ -133,6 +147,15 @@ gst_sub_parse_init (GstSubParse * subparse)
 
   subparse->textbuf = g_string_new (NULL);
   subparse->parser_type = GST_SUB_PARSE_FORMAT_UNKNOWN;
+  subparse->flushing = FALSE;
+  subparse->segment = gst_segment_new ();
+  if (subparse->segment) {
+    gst_segment_init (subparse->segment, GST_FORMAT_TIME);
+    subparse->need_segment = TRUE;
+  } else {
+    GST_WARNING_OBJECT (subparse, "segment creation failed");
+    g_assert_not_reached ();
+  }
 }
 
 /*
@@ -140,40 +163,6 @@ gst_sub_parse_init (GstSubParse * subparse)
  */
 
 static gboolean
-gst_sub_parse_do_seek (GstSubParse * self, GstEvent * event)
-{
-  GstSeekType type;
-  GstFormat format;
-
-  gst_event_parse_seek (event, NULL, &format, NULL, &type, NULL, NULL, NULL);
-
-  if (format != GST_FORMAT_TIME) {
-    GST_DEBUG ("Cannot handle seek in non-TIME formats");
-    return FALSE;
-  }
-
-  /* TODO: use GstSegment? */
-  if (type != GST_SEEK_TYPE_SET) {
-    GST_DEBUG ("Only support GST_SEEK_TYPE_SET");
-    return FALSE;
-  }
-
-  GST_PAD_STREAM_LOCK (self->sinkpad);
-
-  /* just seek to 0, rely on the overlayer to throw away buffers until the right
-     time -- and his mother cried... */
-  self->next_offset = 0;
-
-  /* FIXME: shouldn't we be sending at least a newsegment event? */
-
-  /* FIXME: ... and send a seek event upstream? */
-
-  GST_PAD_STREAM_UNLOCK (self->sinkpad);
-
-  return TRUE;
-}
-
-static gboolean
 gst_sub_parse_src_event (GstPad * pad, GstEvent * event)
 {
   GstSubParse *self = GST_SUBPARSE (gst_pad_get_parent (pad));
@@ -183,14 +172,55 @@ gst_sub_parse_src_event (GstPad * pad, GstEvent * event)
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_SEEK:
-      ret = gst_sub_parse_do_seek (self, event);
+    {
+      GstFormat format;
+      GstSeekType start_type, stop_type;
+      gint64 start, stop;
+      gdouble rate;
+      gboolean update;
+
+      gst_event_parse_seek (event, &rate, &format, &self->segment_flags,
+          &start_type, &start, &stop_type, &stop);
+
+      if (format != GST_FORMAT_TIME) {
+        GST_WARNING_OBJECT (self, "we only support seeking in TIME format");
+        gst_event_unref (event);
+        goto beach;
+      }
+
+      /* Convert that seek to a seeking in bytes at position 0,
+         FIXME: could use an index */
+      ret = gst_pad_push_event (self->sinkpad,
+          gst_event_new_seek (rate, GST_FORMAT_BYTES, self->segment_flags,
+              GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, 0));
+
+      if (ret) {
+        /* Apply the seek to our segment */
+        gst_segment_set_seek (self->segment, rate, format, self->segment_flags,
+            start_type, start, stop_type, stop, &update);
+
+        GST_DEBUG_OBJECT (self, "segment configured from %" GST_TIME_FORMAT
+            " to %" GST_TIME_FORMAT ", position %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (self->segment->start),
+            GST_TIME_ARGS (self->segment->stop),
+            GST_TIME_ARGS (self->segment->last_stop));
+
+        self->next_offset = 0;
+
+        self->need_segment = TRUE;
+      } else {
+        GST_WARNING_OBJECT (self, "seek to 0 bytes failed");
+      }
+
       gst_event_unref (event);
       break;
+    }
     default:
       ret = gst_pad_event_default (pad, event);
       break;
   }
 
+beach:
   gst_object_unref (self);
 
   return ret;
@@ -267,6 +297,8 @@ parse_mdvdsub (ParserState * state, const gchar * line)
   const gchar *line_split;
   gchar *line_chunk;
   guint start_frame, end_frame;
+  gint64 clip_start = 0, clip_stop = 0;
+  gboolean in_seg = FALSE;
 
   /* FIXME: hardcoded for now, but detecting the correct value is
    * not going to be easy, I suspect... */
@@ -288,6 +320,19 @@ parse_mdvdsub (ParserState * state, const gchar * line)
   state->start_time = (start_frame - 1000) / frames_per_sec * GST_SECOND;
   state->duration = (end_frame - start_frame) / frames_per_sec * GST_SECOND;
 
+  /* Check our segment start/stop */
+  in_seg = gst_segment_clip (state->segment, GST_FORMAT_TIME,
+      state->start_time, state->start_time + state->duration, &clip_start,
+      &clip_stop);
+
+  /* No need to parse that text if it's out of segment */
+  if (in_seg) {
+    state->start_time = clip_start;
+    state->duration = clip_stop - clip_start;
+  } else {
+    return NULL;
+  }
+
   /* skip the {%u}{%u} part */
   line = strchr (line, '}') + 1;
   line = strchr (line, '}') + 1;
@@ -368,6 +413,23 @@ parse_subrip (ParserState * state, const gchar * line)
       }
       return NULL;
     case 2:
+    {                           /* No need to parse that text if it's out of segment */
+      gint64 clip_start = 0, clip_stop = 0;
+      gboolean in_seg = FALSE;
+
+      /* Check our segment start/stop */
+      in_seg = gst_segment_clip (state->segment, GST_FORMAT_TIME,
+          state->start_time, state->start_time + state->duration,
+          &clip_start, &clip_stop);
+
+      if (in_seg) {
+        state->start_time = clip_start;
+        state->duration = clip_stop - clip_start;
+      } else {
+        state->state = 0;
+        return NULL;
+      }
+    }
       /* looking for subtitle text; empty line ends this
        * subtitle entry */
       if (state->buf->len)
@@ -401,6 +463,23 @@ parse_mpsub (ParserState * state, const gchar * line)
       }
       return NULL;
     case 1:
+    {                           /* No need to parse that text if it's out of segment */
+      gint64 clip_start = 0, clip_stop = 0;
+      gboolean in_seg = FALSE;
+
+      /* Check our segment start/stop */
+      in_seg = gst_segment_clip (state->segment, GST_FORMAT_TIME,
+          state->start_time, state->start_time + state->duration,
+          &clip_start, &clip_stop);
+
+      if (in_seg) {
+        state->start_time = clip_start;
+        state->duration = clip_stop - clip_start;
+      } else {
+        state->state = 0;
+        return NULL;
+      }
+    }
       /* looking for subtitle text; empty line ends this
        * subtitle entry */
       if (state->buf->len)
@@ -433,6 +512,7 @@ parser_state_init (ParserState * state)
   state->start_time = 0;
   state->duration = 0;
   state->state = 0;
+  state->segment = NULL;
 }
 
 static void
@@ -566,7 +646,10 @@ handle_buffer (GstSubParse * self, GstBuffer * buf)
     gst_caps_unref (caps);
   }
 
-  while ((line = get_next_line (self))) {
+  while ((line = get_next_line (self)) && !self->flushing) {
+    /* Set segment on our parser state machine */
+    self->state.segment = self->segment;
+    /* Now parse the line, out of segment lines will just return NULL */
     GST_DEBUG ("Parsing line '%s'", line);
     subtitle = self->parse_line (&self->state, line);
     g_free (line);
@@ -583,6 +666,9 @@ handle_buffer (GstSubParse * self, GstBuffer * buf)
         GST_BUFFER_TIMESTAMP (buf) = self->state.start_time;
         GST_BUFFER_DURATION (buf) = self->state.duration;
 
+        gst_segment_set_last_stop (self->segment, GST_FORMAT_TIME,
+            self->state.start_time);
+
         GST_DEBUG ("Sending text '%s', %" GST_TIME_FORMAT " + %"
             GST_TIME_FORMAT, subtitle, GST_TIME_ARGS (self->state.start_time),
             GST_TIME_ARGS (self->state.duration));
@@ -608,10 +694,21 @@ gst_sub_parse_chain (GstPad * sinkpad, GstBuffer * buf)
   GstSubParse *self;
 
   GST_DEBUG ("gst_sub_parse_chain");
-  self = GST_SUBPARSE (GST_OBJECT_PARENT (sinkpad));
+  self = GST_SUBPARSE (gst_pad_get_parent (sinkpad));
+
+  /* Push newsegment if needed */
+  if (self->need_segment) {
+    gst_pad_push_event (self->srcpad, gst_event_new_new_segment (FALSE,
+            self->segment->rate, self->segment->format,
+            self->segment->last_stop, self->segment->stop,
+            self->segment->time));
+    self->need_segment = FALSE;
+  }
 
   ret = handle_buffer (self, buf);
 
+  gst_object_unref (self);
+
   return ret;
 }
 
@@ -640,10 +737,40 @@ gst_sub_parse_sink_event (GstPad * pad, GstEvent * event)
       ret = gst_pad_event_default (pad, event);
       break;
     }
-    case GST_EVENT_NEWSEGMENT:{
+    case GST_EVENT_NEWSEGMENT:
+    {
+      GstFormat format;
+      gdouble rate;
+      gint64 start, stop, time;
+      gboolean update;
+
+      GST_DEBUG_OBJECT (self, "received new segment");
+
+      gst_event_parse_new_segment (event, &update, &rate, &format, &start,
+          &stop, &time);
+
+      /* now copy over the values */
+      gst_segment_set_newsegment (self->segment, update, rate, format,
+          start, stop, time);
+
+      ret = TRUE;
       gst_event_unref (event);
       break;
     }
+    case GST_EVENT_FLUSH_START:
+    {
+      self->flushing = TRUE;
+
+      ret = gst_pad_event_default (pad, event);
+      break;
+    }
+    case GST_EVENT_FLUSH_STOP:
+    {
+      self->flushing = FALSE;
+
+      ret = gst_pad_event_default (pad, event);
+      break;
+    }
     default:
       ret = gst_pad_event_default (pad, event);
       break;
index f10fe30..94b0f3a 100644 (file)
@@ -53,6 +53,7 @@ typedef struct {
   GString *buf;
   guint64  start_time;
   guint64  duration;
+  GstSegment *segment;
 } ParserState;
 
 typedef gchar* (*Parser) (ParserState *state, const gchar *line);
@@ -73,6 +74,13 @@ struct _GstSubParse {
   /* seek */
   guint64 offset;
   guint64 next_offset;
+  
+  /* Segment */
+  GstSegment *segment;
+  GstSeekFlags  segment_flags;
+  gboolean need_segment;
+  
+  gboolean flushing;
 };
 
 struct _GstSubParseClass {