aboutsummaryrefslogtreecommitdiff
path: root/docs/pwg/advanced-events.xml
blob: b755452a668a4a5adec7842f419191d13ae043fa (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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
<chapter id="chapter-advanced-events">
  <title>Events: Seeking, Navigation and More</title>
  <para>
    There are many different event types but only two ways they can travel in
    the pipeline: downstream or upstream. It is very important to understand
    how both of these methods work because if one element in the pipeline is not
    handling them correctly the whole event system of the pipeline is broken.
    We will try to explain here how these methods work and how elements are 
    supposed to implement them.
  </para>
  <sect1 id="section-events-downstream" xreflabel="Downstream events">
    <title>Downstream events</title>
    <para>
      Downstream events are received through the sink pad's event handler,
      as set using <function>gst_pad_set_event_function ()</function> when
      the pad was created.
    </para>
    <para>
      Downstream events can travel in two ways: they can be in-band (serialised
      with the buffer flow) or out-of-band (travelling through the pipeline
      instantly, possibly not in the same thread as the streaming thread that
      is processing the buffers, skipping ahead of buffers being processed
      or queued in the pipeline). The most common downstream events
      (NEWSEGMENT, EOS, TAG) are all serialised with the buffer flow.
    </para>
    <para>
      Here is a typical event function:
    </para>
    <programlisting>
static gboolean
gst_my_filter_sink_event (GstPad  *pad, GstEvent * event)
{
  GstMyFilter *filter;
  gboolean ret;

  filter = GST_MY_FILTER (gst_pad_get_parent (pad));
  ...

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_NEWSEGMENT:
      /* maybe save and/or update the current segment (e.g. for output
       * clipping) or convert the event into one in a different format
       * (e.g. BYTES to TIME) or drop it and set a flag to send a newsegment
       * event in a different format later */
      ret = gst_pad_push_event (filter-&gt;src_pad, event);
      break;
    case GST_EVENT_EOS:
      /* end-of-stream, we should close down all stream leftovers here */
      gst_my_filter_stop_processing (filter);
      ret = gst_pad_push_event (filter-&gt;src_pad, event);
      break;
    case GST_EVENT_FLUSH_STOP:
      gst_my_filter_clear_temporary_buffers (filter);
      ret = gst_pad_push_event (filter-&gt;src_pad, event);
      break;      
    default:
      ret = gst_pad_event_default (pad, event);
      break;
  }

  ...
  gst_object_unref (filter);
  return ret;
}
    </programlisting>
  <para>
    If your element is chain-based, you will almost always have to implement
    a sink event function, since that is how you are notified about
    new segments and the end of the stream.
  </para>
  <para>
    If your element is exclusively loop-based, you may or may not want a
    sink event function (since the element is driving the pipeline it will
    know the length of the stream in advance or be notified by the flow
    return value of <function>gst_pad_pull_range()</function>. In some cases
    even loop-based element may receive events from upstream though (for
    example audio decoders with an id3demux or apedemux element in front of
    them, or demuxers that are being fed input from sources that send
    additional information about the stream in custom events, as DVD sources
    do).
  </para>
  </sect1>
  <sect1 id="section-events-upstream" xreflabel="Upstream events">
    <title>Upstream events</title>
    <para>
      Upstream events are generated by an element somewhere downstream in
      the pipeline (example: a video sink may generate navigation
      events that informs upstream elements about the current position of
      the mouse pointer). This may also happen indirectly on request of the
      application, for example when the application executes a seek on a
      pipeline this seek request will be passed on to a sink element which
      will then in turn generate an upstream seek event.
    </para>
    <para>
      The most common upstream events are seek events and Quality-of-Service
      (QoS) events.
    </para>
    <para>
      An upstream event can be sent using the
      <function>gst_pad_send_event</function> function. This
      function simply call the default event handler of that pad. The default
      event handler of pads is <function>gst_pad_event_default</function>, and
      it basically sends the event to the peer pad. So upstream events always
      arrive on the src pad of your element and are handled by the default event
      handler except if you override that handler to handle it yourself. There
      are some specific cases where you have to do that :
    </para>
    <itemizedlist mark="opencircle">
      <listitem>
        <para>
          If you have multiple sink pads in your element. In that case you will
          have to decide which one of the sink pads you will send the event to
          (if not all of them).
        </para>
      </listitem>
      <listitem>
        <para>
          If you need to handle that event locally. For example a navigation 
          event that you will want to convert before sending it upstream, or
          a QoS event that you want to handle.
        </para>
      </listitem>
    </itemizedlist>
    <para>
      The processing you will do in that event handler does not really matter
      but there are important rules you have to absolutely respect because
      one broken element event handler is breaking the whole pipeline event 
      handling. Here they are :
    </para>
    <itemizedlist mark="opencircle">
      <listitem>
        <para>
          Always forward events you won't handle upstream using the default 
          <function>gst_pad_event_default</function> method.
        </para>
      </listitem>
      <listitem>
        <para>
          If you are generating some new event based on the one you received
          don't forget to gst_event_unref the event you received.
        </para>
      </listitem>
      <listitem>
        <para>
          Event handler function are supposed to return TRUE or FALSE indicating
          if the event has been handled or not. Never simply return TRUE/FALSE
          in that handler except if you really know that you have handled that 
          event.
        </para>
      </listitem>
      <listitem>
        <para>
          Remember that the event handler might be called from a different
          thread than the streaming thread, so make sure you use
          appropriate locking everywhere and at the beginning of the function
          obtain a reference to your element via the
          <function>gst_pad_get_parent()</function> (and release it again at
          the end of the function with <function>gst_object_unref ()</function>.
        </para>
      </listitem>
    </itemizedlist>
  </sect1>

  <sect1 id="section-events-definitions" xreflabel="All Events Together">
    <title>All Events Together</title>
    <para>
      In this chapter follows a list of all defined events that are currently
      being used, plus how they should be used/interpreted. You can check the
      what type a certain event is using the GST_EVENT_TYPE macro (or if you
      need a string for debugging purposes you can use GST_EVENT_TYPE_NAME).
    </para>
    <para>
      In this chapter, we will discuss the following events:
    </para>
    <itemizedlist>
      <listitem><para><xref linkend="section-events-eos"/></para></listitem>
      <listitem><para><xref linkend="section-events-flush-start"/></para></listitem>
      <listitem><para><xref linkend="section-events-flush-stop"/></para></listitem>
      <listitem><para><xref linkend="section-events-newsegment"/></para></listitem>
      <listitem><para><xref linkend="section-events-seek"/></para></listitem>
      <listitem><para><xref linkend="section-events-nav"/></para></listitem>
      <listitem><para><xref linkend="section-events-tag"/></para></listitem>
    </itemizedlist>
    <para>
      For more comprehensive information about events and how they should be
      used correctly in various circumstances please consult the GStreamer
      design documentation. This section only gives a general overview.      
    </para>

    <sect2 id="section-events-eos" xreflabel="End of Stream (EOS)">
      <title>End of Stream (EOS)</title>
      <para>
        End-of-stream events are sent if the stream that an element sends out
        is finished. An element receiving this event (from upstream, so it
        receives it on its sinkpad) will generally just process any buffered
        data (if there is any) and then forward the event further downstream.
        The <function>gst_pad_event_default ()</function> takes care of all
        this, so most elements do not need to support this event. Exceptions are
        elements that explicitly need to close a resource down on EOS, and
        N-to-1 elements. Note that the stream itself is <emphasis>not</emphasis>
        a resource that should be closed down on EOS! Applications might seek
        back to a point before EOS and continue playing again.
      </para>
      <para>
        The EOS event has no properties, which makes it one of the simplest
        events in &GStreamer;. It is created using the 
        <function>gst_event_new_eos()</function> function.
      </para>
      <para>
        It is important to note that <emphasis>only elements driving the
        pipeline should ever send an EOS event</emphasis>. If your element
        is chain-based, it is not driving the pipeline. Chain-based elements
        should just return GST_FLOW_EOS from their chain function at
        the end of the stream (or the configured segment), the upstream
        element that is driving the pipeline will then take care of
        sending the EOS event (or alternatively post a SEGMENT_DONE message
        on the bus depending on the mode of operation). If you are implementing
        your own source element, you also do not need to ever manually send
        an EOS event, you should also just return GST_FLOW_EOS in
        your create function (assuming your element derives from GstBaseSrc
        or GstPushSrc).
      </para>
    </sect2>

    <sect2 id="section-events-flush-start" xreflabel="Flush Start">
      <title>Flush Start</title>
      <para>
        The flush start event is sent downstream if all buffers and caches
        in the pipeline should be emptied. <quote>Queue</quote> elements will
        empty their internal list of buffers when they receive this event, for
        example. File sink elements (e.g. <quote>filesink</quote>) will flush
        the kernel-to-disk cache (<function>fdatasync ()</function> or
        <function>fflush ()</function>) when they receive this event. Normally,
        elements receiving this event will simply just forward it, since most
        filter or filter-like elements don't have an internal cache of data.
        <function>gst_pad_event_default ()</function> does just that, so for
        most elements, it is enough to forward the event using the default
        event handler.
      </para>
      <para>
        As a side-effect of flushing all data from the pipeline, this event
        unblocks the streaming thread by making all pads reject data until
        they receive a <xref linkend="section-events-flush-stop"/> signal
        (elements trying to push data will get a FLUSHING flow return
         and stop processing data).
      </para>
      <para>
        The flush-start event is created with the
        <function>gst_event_new_flush_start ()</function>.
        Like the EOS event, it has no properties. This event is usually
        only created by elements driving the pipeline, like source elements
        operating in push-mode or pull-range based demuxers/decoders.
      </para>
    </sect2>

    <sect2 id="section-events-flush-stop" xreflabel="Flush Stop">
      <title>Flush Stop</title>
      <para>
        The flush-stop event is sent by an element driving the pipeline
        after a flush-start and tells pads and elements downstream that
        they should accept events and buffers again (there will be at
        least a NEWSEGMENT event before any buffers first though).
      </para>
      <para>
        If your element keeps temporary caches of stream data, it should
        clear them when it receives a FLUSH-STOP event (and also whenever
        its chain function receives a buffer with the DISCONT flag set).
      </para>
      <para>
        The flush-stop event is created with
        <function>gst_event_new_flush_stop ()</function>. Like the EOS event,
        it has no properties.
      </para>
    </sect2>

    <sect2 id="section-events-newsegment" xreflabel="New Segment">
      <title>New Segment</title>
      <para>
        A new segment event is sent downstream to either announce a new
        segment of data in the data stream or to update the current segment
        with new values. A new segment event must always be sent before the
        first buffer of data and after a flush (see above).
      </para>
      <para>
        The first new segment event is created by the element driving the 
        pipeline, like a source operating in push-mode or a demuxer/decoder
        operating pull-based. This new segment event then travels down the
        pipeline and may be transformed on the way (a decoder, for example,
        might receive a new-segment event in BYTES format and might transform
        this into a new-segment event in TIMES format based on the average
        bitrate).
      </para>
      <para>
        New segment events may also be used to indicate 'gaps' in the stream,
        like in a subtitle stream for example where there may not be any
        data at all for a considerable amount of (stream) time. This is done
        by updating the segment start of the current segment (see the design
        documentation for more details).
      </para>
      <para>
        Depending on the element type, the event can simply be forwarded using
        <function>gst_pad_event_default ()</function>, or it should be parsed
        and a modified event should be sent on. The last is true for demuxers,
        which generally have a byte-to-time conversion concept. Their input
        is usually byte-based, so the incoming event will have an offset in
        byte units (<symbol>GST_FORMAT_BYTES</symbol>), too. Elements
        downstream, however, expect new segment events in time units, so that
        it can be used to update the pipeline clock. Therefore, demuxers and
        similar elements should not forward the event, but parse it, free it
        and send a new newsegment event (in time units,
        <symbol>GST_FORMAT_TIME</symbol>) further downstream.
      </para>
      <para>
        The newsegment event is created using the function
        <function>gst_event_new_new_segment ()</function>. See the API
        reference and design document for details about its parameters. 
      </para>
      <para>
        Elements parsing this event can use gst_event_parse_new_segment_full()
        to extract the event details. Elements may find the GstSegment
        API useful to keep track of the current segment (if they want to use
        it for output clipping, for example).
      </para>
    </sect2>

    <sect2 id="section-events-seek" xreflabel="Seek Request">
      <title>Seek Request</title>
      <para>
        Seek events are meant to request a new stream position to elements.
        This new position can be set in several formats (time, bytes or
        <quote>default units</quote> [a term indicating frames for video,
        channel-independent samples for audio, etc.]). Seeking can be done with
        respect to the end-of-file, start-of-file or current position, and
        usually happens in upstream direction (downstream seeking is done by
        sending a NEWSEGMENT event with the appropriate offsets for elements
        that support that, like filesink).
      </para>
      <para>
        Elements receiving seek events should, depending on the element type,
        either just forward it upstream (filters, decoders), change the
        format in which the event is given and then forward it (demuxers),
        or handle the event by changing the file pointer in their internal
        stream resource (file sources, demuxers/decoders driving the pipeline
        in pull-mode) or something else.
      </para>
      <para>
        Seek events are built up using positions in specified formats (time,
        bytes, units). They are created using the function
        <function>gst_event_new_seek ()</function>. Note that many plugins do
        not support seeking from the end of the stream or from the current
        position. An element not driving the pipeline and forwarding a seek
        request should not assume that the seek succeeded or actually happened,
        it should operate based on the NEWSEGMENT events it receives.
      </para>
      <para>
        Elements parsing this event can do this using
        <function>gst_event_parse_seek()</function>.
      </para>
    </sect2>

    <sect2 id="section-events-nav" xreflabel="Navigation">
      <title>Navigation</title>
      <para>
        Navigation events are sent upstream by video sinks to inform upstream
        elements of where the mouse pointer is, if and where mouse pointer
        clicks have happened, or if keys have been pressed or released.
      </para>
      <para>
        All this information is contained in the event structure which can
        be obtained with <function>gst_event_get_structure ()</function>.
      </para>
      <para>
        Check out the navigationtest element in gst-plugins-good for an idea
        how to extract navigation information from this event.
      </para>
    </sect2>

    <sect2 id="section-events-tag" xreflabel="Tag (metadata)">
      <title>Tag (metadata)</title>
      <para>
        Tagging events are being sent downstream to indicate the tags as parsed
        from the stream data. This is currently used to preserve tags during
        stream transcoding from one format to the other. Tags are discussed
        extensively in <xref linkend="chapter-advanced-tagging"/>. Most
        elements will simply forward the event by calling
        <function>gst_pad_event_default ()</function>.
      </para>
      <para>
        The tag event is created using the function
        <function>gst_event_new_tag ()</function>, but more often elements will
        use either the <function>gst_element_found_tags ()</function> function
        or the <function>gst_element_found_tags_for_pad ()</function>, which
        will do both: post a tag message on the bus and send a tag event
        downstream. All of these functions require a filled-in taglist as
        argument, which they will take ownership of.
      </para>
      <para>
        Elements parsing this event can use the function
        <function>gst_event_parse_tag ()</function> to acquire the
        taglist that the event contains.
      </para>
    </sect2>
  </sect1>
</chapter>