summaryrefslogtreecommitdiff
path: root/pwg-building-chainfn.md
blob: 9252aa53ab416ecf693606698e38c2c95c182f24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
---
title: The chain function
...

# The chain function

The chain function is the function in which all data processing takes
place. In the case of a simple filter, `_chain ()` functions are mostly
linear functions - so for each incoming buffer, one buffer will go out,
too. Below is a very simple implementation of a chain function:

``` c

static GstFlowReturn gst_my_filter_chain (GstPad    *pad,
                                          GstObject *parent,
                                          GstBuffer *buf);

[..]

static void
gst_my_filter_init (GstMyFilter * filter)
{
[..]
  /* configure chain function on the pad before adding
   * the pad to the element */
  gst_pad_set_chain_function (filter->sinkpad,
      gst_my_filter_chain);
[..]
}

static GstFlowReturn
gst_my_filter_chain (GstPad    *pad,
                     GstObject *parent,
             GstBuffer *buf)
{
  GstMyFilter *filter = GST_MY_FILTER (parent);

  if (!filter->silent)
    g_print ("Have data of size %" G_GSIZE_FORMAT" bytes!\n",
        gst_buffer_get_size (buf));

  return gst_pad_push (filter->srcpad, buf);
}
```

Obviously, the above doesn't do much useful. Instead of printing that
the data is in, you would normally process the data there. Remember,
however, that buffers are not always writeable.

In more advanced elements (the ones that do event processing), you may
want to additionally specify an event handling function, which will be
called when stream-events are sent (such as caps, end-of-stream,
newsegment, tags, etc.).

    static void
    gst_my_filter_init (GstMyFilter * filter)
    {
    [..]
      gst_pad_set_event_function (filter->sinkpad,
          gst_my_filter_sink_event);
    [..]
    }
    
    
    
    static gboolean
    gst_my_filter_sink_event (GstPad    *pad,
                      GstObject *parent,
                      GstEvent  *event)
    {
      GstMyFilter *filter = GST_MY_FILTER (parent);
    
      switch (GST_EVENT_TYPE (event)) {
        case GST_EVENT_CAPS:
          /* we should handle the format here */
          break;
        case GST_EVENT_EOS:
          /* end-of-stream, we should close down all stream leftovers here */
          gst_my_filter_stop_processing (filter);
          break;
        default:
          break;
      }
    
      return gst_pad_event_default (pad, parent, event);
    }
    
    static GstFlowReturn
    gst_my_filter_chain (GstPad    *pad,
                 GstObject *parent,
                 GstBuffer *buf)
    {
      GstMyFilter *filter = GST_MY_FILTER (parent);
      GstBuffer *outbuf;
    
      outbuf = gst_my_filter_process_data (filter, buf);
      gst_buffer_unref (buf);
      if (!outbuf) {
        /* something went wrong - signal an error */
        GST_ELEMENT_ERROR (GST_ELEMENT (filter), STREAM, FAILED, (NULL), (NULL));
        return GST_FLOW_ERROR;
      }
    
      return gst_pad_push (filter->srcpad, outbuf);
    }

In some cases, it might be useful for an element to have control over
the input data rate, too. In that case, you probably want to write a
so-called *loop-based* element. Source elements (with only source pads)
can also be *get-based* elements. These concepts will be explained in
the advanced section of this guide, and in the section that specifically
discusses source pads.