Sophie

Sophie

distrib > Mandriva > 10.0-com > i586 > by-pkgid > f0a9f2b9c81d34eadc43f527947c0b70 > files > 210

libgstreamer0.7-devel-0.7.4-2mdk.i586.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML
><HEAD
><TITLE
>How a loopfunc works</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
REL="HOME"
TITLE="GStreamer Plugin Writer's Guide"
HREF="index.html"><LINK
REL="UP"
TITLE="Advanced Filter Concepts"
HREF="part-advanced.html"><LINK
REL="PREVIOUS"
TITLE="The Optimal Scheduler"
HREF="section-sched-opt.html"><LINK
REL="NEXT"
TITLE="The Bytestream Object"
HREF="section-loopfn-bytestream.html"></HEAD
><BODY
CLASS="chapter"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
><SPAN
CLASS="application"
>GStreamer</SPAN
> Plugin Writer's Guide</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="section-sched-opt.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="section-loopfn-bytestream.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="chapter"
><H1
><A
NAME="chapter-loopbased-loopfn"
></A
>Chapter 12. How a loopfunc works</H1
><P
>&#13;    A <CODE
CLASS="function"
>_loop ()</CODE
> function is a function that is called by
    the scheduler, but without providing data to the element. Instead, the
    element will become responsible for acquiring its own data, and it will
    still be responsible of sending data over to its source pads. This method
    noticeably complicates scheduling; you should only write loop-based
    elements when you need to. Normally, chain-based elements are preferred.
    Examples of elements that <SPAN
CLASS="emphasis"
><I
CLASS="emphasis"
>have</I
></SPAN
> to be loop-based are
    elements with multiple sink pads. Since the scheduler will push data into
    the pads as it comes (and this might not be synchronous), you will easily
    get ascynronous data on both pads, which means that the data that arrives
    on the first pad has a different display timestamp then the data arriving
    on the second pad at the same time. To get over these issues, you should
    write such elements in a loop-based form. Other elements that are
    <SPAN
CLASS="emphasis"
><I
CLASS="emphasis"
>easier</I
></SPAN
> to write in a loop-based form than in a
    chain-based form are demuxers and parsers. It is not required to write such
    elements in a loop-based form, though.
  </P
><P
>&#13;    Below is an example of the easiest loop-function that one can write:
  </P
><PRE
CLASS="programlisting"
>&#13;static void	gst_my_filter_loopfunc	(GstElement *element);

static void
gst_my_filter_init (GstMyFilter *filter)
{
[..]
  gst_element_set_loopfunc (GST_ELEMENT (filter), gst_my_filter_loopfunc);
[..]
}

static void
gst_my_filter_loopfunc (GstElement *element)
{
  GstMyFilter *filter = GST_MY_FILTER (element);
  GstData *data;

  /* acquire data */
  data = gst_pad_pull (filter-&#62;sinkpad);

  /* send data */
  gst_pad_push (filter-&#62;srcpad, data);
}
  </PRE
><P
>&#13;    Obviously, this specific example has no single advantage over a chain-based
    element, so you should never write such elements. However, it's a good
    introduction to the concept.
  </P
><DIV
CLASS="sect1"
><H1
CLASS="sect1"
><A
NAME="section-loopfn-multiinput"
>12.1. Multi-Input Elements</A
></H1
><P
>&#13;      Elements with multiple sink pads need to take manual control over their
      input to assure that the input is synchronized. The following example
      code could (should) be used in an aggregator, i.e. an element that takes
      input from multiple streams and sends it out intermangled. Not really
      useful in practice, but a good example, again.
    </P
><PRE
CLASS="programlisting"
>&#13;

typedef struct _GstMyFilterInputContext {
  gboolean   eos;
  GstBuffer *lastbuf;
} GstMyFilterInputContext;

[..]

static void
gst_my_filter_init (GstMyFilter *filter)
{
  GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter);
  GstMyFilterInputContext *context;

  filter-&#62;sinkpad1 = gst_pad_new_from_template (
	gst_element_class_get_pad_template (klass, "sink"), "sink_1");
  context = g_new0 (GstMyFilterInputContext, 1);
  gst_pad_set_private_data (filter-&#62;sinkpad1, context);
[..]
  filter-&#62;sinkpad2 = gst_pad_new_from_template (
	gst_element_class_get_pad_template (klass, "sink"), "sink_2");
  context = g_new0 (GstMyFilterInputContext, 1);
  gst_pad_set_private_data (filter-&#62;sinkpad2, context);
[..]
  gst_element_set_loopfunc (GST_ELEMENT (filter),
			    gst_my_filter_loopfunc);
}

[..]

static void
gst_my_filter_loopfunc (GstElement *element)
{
  GstMyFilter *filter = GST_MY_FILTER (element);
  GList *padlist;
  GstMyFilterInputContext *first_context = NULL;

  /* Go over each sink pad, update the cache if needed, handle EOS
   * or non-responding streams and see which data we should handle
   * next. */
  for (padlist = gst_element_get_padlist (element);
       padlist != NULL; padlist = g_list_next (padlist)) {
    GstPad *pad = GST_PAD (padlist-&#62;data);
    GstMyFilterInputContext *context = gst_pad_get_private_data (pad);

    if (GST_PAD_IS_SRC (pad))
      continue;

    while (GST_PAD_IS_USABLE (pad) &#38;&#38;
           !context-&#62;eos &#38;&#38; !context-&#62;lastbuf) {
      GstData *data = gst_pad_pull (pad);

      if (GST_IS_EVENT (data)) {
        /* We handle events immediately */
        GstEvent *event = GST_EVENT (data);

        switch (GST_EVENT_TYPE (event)) {
          case GST_EVENT_EOS:
            context-&#62;eos = TRUE;
            gst_event_unref (event);
            break;
          case GST_EVENT_DISCONTINUOUS:
            g_warning ("HELP! How do I handle this?");
            /* fall-through */
          default:
            gst_pad_event_default (pad, event);
            break;
        }
      } else {
        /* We store the buffer to handle synchronization below */
        context-&#62;lastbuf = GST_BUFFER (data);
      }
    }

    /* synchronize streams by always using the earliest buffer */
    if (context-&#62;lastbuf) {
      if (!first_context) {
        first_context = context;
      } else {
        if (GST_BUFFER_TIMESTAMP (context-&#62;lastbuf) &#60;
		GST_BUFFER_TIMESTAMP (first_context-&#62;lastbuf))
          first_context = context;
      }
    }
  }

  /* If we handle no data at all, we're at the end-of-stream, so
   * we should signal EOS. */
  if (!first_context) {
    gst_pad_push (filter-&#62;srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
    gst_element_set_eos (element);
    return;
  }

  /* So we do have data! Let's forward that to our source pad. */
  gst_pad_push (filter-&#62;srcpad, GST_DATA (first_context-&#62;lastbuf));
  first_context-&#62;lastbuf = NULL;
}

    </PRE
><P
>&#13;      Note that a loop-function is allowed to return. Better yet, a loop
      function <SPAN
CLASS="emphasis"
><I
CLASS="emphasis"
>has to</I
></SPAN
> return so the scheduler can
      let other elements run (this is particularly true for the optimal
      scheduler). Whenever the scheduler feels right, it will call the
      loop-function of the element again.
    </P
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="section-sched-opt.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="section-loopfn-bytestream.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>The Optimal Scheduler</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="part-advanced.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>The Bytestream Object</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>