summaryrefslogtreecommitdiff
path: root/docs/pwg/advanced-negotiation.xml
blob: ff57a66f88fda1736b688f8f5a801e40da977c69 (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
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
<chapter id="chapter-negotiation" xreflabel="Caps negotiation">
  <title>Caps negotiation</title>
  <para>
    Caps negotiation is the act of finding a media format (GstCaps) between
    elements that they can handle. This process in &GStreamer; can in most
    cases find an optimal solution for the complete pipeline. In this section
    we explain how this works.
  </para>

  <sect1 id="section-nego-basics">
    <title>Caps negotiation basics</title>
    <para>
      In &GStreamer;, negotiation of the media format always follows the
      following simple rules:
    </para>
    <itemizedlist>
      <listitem>
        <para>
          A downstream element suggest a format on its sinkpad and places the
          suggestion in the result of the CAPS query performed on the sinkpad.
          See also <xref linkend="section-nego-getcaps"/>.
        </para>
      </listitem>
      <listitem>
        <para>
          An upstream element decides on a format. It sends the selected media
          format downstream on its source pad with a CAPS event. Downstream
          elements reconfigure themselves to handle the media type in the CAPS
          event on the sinkpad.
        </para>
      </listitem>
      <listitem>
        <para>
          A downstream element can inform upstream that it would like to
          suggest a new format by sending a RECONFIGURE event upstream. The
          RECONFIGURE event simply instructs an upstream element to restart
          the negotiation phase. Because the element that sent out the
          RECONFIGURE event is now suggesting another format, the format
          in the pipeline might change.
        </para>
      </listitem>
    </itemizedlist>
    <para>
      In addition to the CAPS and RECONFIGURE event and the CAPS query, there
      is an ACCEPT_CAPS query to quickly check if a certain caps can
      be accepted by an element.
    </para>
    <para>
      All negotiation follows these simple rules. Let's take a look at some
      typical uses cases and how negotiation happens.
    </para>
  </sect1>

  <sect1 id="section-nego-usecases">
    <title>Caps negotiation use cases</title>
    <para>
      In what follows we will look at some use cases for push-mode scheduling.
      The pull-mode scheduling negotiation phase is discussed in
      <xref linkend="section-nego-pullmode"/> and is actually similar as we
      will see. 
    </para>
    <para>
      Since the sink pads only suggest formats and the source pads need to
      decide, the most complicated work is done in the source pads.
      We can identify 3 caps negotiation use cases for the source pads:
    </para>
    <itemizedlist>
      <listitem>
        <para>
          Fixed negotiation. An element can output one format only.
          See <xref linkend="section-nego-fixed"/>.
        </para>
      </listitem>
      <listitem>
        <para>
          Transform negotiation. There is a (fixed) transform between the
          input and output format of the element, usually based on some
          element property. The caps that the element will produce depend
          on the upstream caps and the caps that the element can accept
          depend on the downstream caps.
          See <xref linkend="section-nego-transform"/>.
        </para>
      </listitem>
      <listitem>
        <para>
          Dynamic negotiation. An element can output many formats.
          See <xref linkend="section-nego-dynamic"/>.
        </para>
      </listitem>
    </itemizedlist>

    <sect2 id="section-nego-fixed">
      <title>Fixed negotiation</title>
      <para>
        In this case, the source pad can only produce a fixed format. Usually
        this format is encoded inside the media. No downstream element can
        ask for a different format, the only way that the source pad will
        renegotiate is when the element decides to change the caps itself.
      </para>
      <para>
        Elements that could implement fixed caps (on their source pads) are,
        in general, all elements that are not renegotiable. Examples include:
      </para>
      <itemizedlist>
        <listitem>
          <para>
            A typefinder, since the type found is part of the actual data stream
            and can thus not be re-negotiated. The typefinder will look at the
            stream of bytes, figure out the type, send a CAPS event with the
            caps and then push buffers of the type.
          </para>
        </listitem>
        <listitem>
          <para>
            Pretty much all demuxers, since the contained elementary data
            streams are defined in the file headers, and thus not
            renegotiable.
          </para>
        </listitem>
        <listitem>
          <para>
            Some decoders, where the format is embedded in the data stream
            and not part of the peercaps <emphasis>and</emphasis> where the
            decoder itself is not reconfigurable, too.
          </para>
        </listitem>
        <listitem>
          <para>
            Some sources that produce a fixed format.
          </para>
        </listitem>
      </itemizedlist>
      <para>
        <function>gst_pad_use_fixed_caps()</function> is used on the source
        pad with fixed caps. As long as the pad is not negotiated, the default
        CAPS query will return the caps presented in the padtemplate. As soon
        as the pad is negotiated, the CAPS query will return the negotiated
        caps (and nothing else). These are the relevant code snippets for fixed
        caps source pads.
      </para>
      <programlisting>
<![CDATA[
[..]
  pad = gst_pad_new_from_static_template (..);
  gst_pad_use_fixed_caps (pad);
[..]
]]>
      </programlisting>
      <para>
        The fixed caps can then be set on the pad by calling
        <function>gst_pad_set_caps ()</function>.
      </para>
      <programlisting>
<![CDATA[
[..]
    caps = gst_caps_new_simple ("audio/x-raw",
        "format", G_TYPE_STRING, GST_AUDIO_NE(F32),
        "rate", G_TYPE_INT, <samplerate>,
        "channels", G_TYPE_INT, <num-channels>, NULL);
    if (!gst_pad_set_caps (pad, caps)) {
      GST_ELEMENT_ERROR (element, CORE, NEGOTIATION, (NULL),
          ("Some debug information here"));
      return GST_FLOW_ERROR;
    }
[..]
]]>
      </programlisting>
      <para>
        These types of elements also don't have a relation between the input
        format and the output format, the input caps simply don't contain the
        information needed to produce the output caps.
      </para>
      <para>
        All other elements that need to be configured for the format should
        implement full caps negotiation, which will be explained in the next
        few sections.
      </para>
    </sect2>

    <sect2 id="section-nego-transform">
      <title>Transform negotiation</title>
      <para>
        In this negotiation technique, there is a fixed transform between
        the element input caps and the output caps. This transformation
        could be parameterized by element properties but not by the
        content of the stream (see <xref linkend="section-nego-fixed"/>
        for that use-case).
      </para>
      <para>
        The caps that the element can accept depend on the (fixed
        transformation) downstream caps. The caps that the element can
        produce depend on the (fixed transformation of) the upstream
        caps.
      </para>
      <para>
        This type of element can usually set caps on its source pad from
        the <function>_event()</function> function on the sink pad when
        it received the CAPS event. This means that the caps transform
        function transforms a fixed caps into another fixed caps.
        Examples of elements include:
      </para>
      <itemizedlist>
        <listitem>
          <para>
            Videobox. It adds configurable border around a video frame
            depending on object properties.
          </para>
        </listitem>
        <listitem>
          <para>
            Identity elements. All elements that don't change the format
            of the data, only the content. Video and audio effects are an
            example. Other examples include elements that inspect the
            stream.
          </para>
        </listitem>
        <listitem>
          <para>
            Some decoders and encoders, where the output format is defined
            by input format, like mulawdec and mulawenc. These decoders
            usually have no headers that define the content of the stream.
            They are usually more like conversion elements.
          </para>
        </listitem>
      </itemizedlist>
      <para>
        Below is an example of a negotiation steps of a typical transform 
        element. In the sink pad CAPS event handler, we compute the caps
        for the source pad and set those.
      </para>
      <programlisting>
<![CDATA[
  [...]

static gboolean
gst_my_filter_setcaps (GstMyFilter *filter,
		       GstCaps *caps)
{
  GstStructure *structure;
  int rate, channels;
  gboolean ret;
  GstCaps *outcaps;

  structure = gst_caps_get_structure (caps, 0);
  ret = gst_structure_get_int (structure, "rate", &rate);
  ret = ret && gst_structure_get_int (structure, "channels", &channels);
  if (!ret)
    return FALSE;

  outcaps = gst_caps_new_simple ("audio/x-raw",
      "format", G_TYPE_STRING, GST_AUDIO_NE(S16),
      "rate", G_TYPE_INT, rate,
      "channels", G_TYPE_INT, channels, NULL);
  ret = gst_pad_set_caps (filter->srcpad, outcaps);
  gst_caps_unref (outcaps);

  return ret;
}

static gboolean
gst_my_filter_sink_event (GstPad    *pad,
		          GstObject *parent,
		          GstEvent  *event)
{
  gboolean ret;
  GstMyFilter *filter = GST_MY_FILTER (parent);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_CAPS:
    {
      GstCaps *caps;

      gst_event_parse_caps (event, &caps);
      ret = gst_my_filter_setcaps (filter, caps);
      break;
    }
    default:
      ret = gst_pad_event_default (pad, parent, event);
      break;
  }
  return ret;
}

  [...]
]]>
      </programlisting>
    </sect2>

    <sect2 id="section-nego-dynamic">
      <title>Dynamic negotiation</title>
      <para>
        A last negotiation method is the most complex and powerful dynamic
        negotiation.
      </para>
      <para>
        Like with the transform negotiation in 
        <xref linkend="section-nego-transform"/>, dynamic negotiation will
        perform a transformation on the downstream/upstream caps. Unlike the
        transform negotiation, this transform will convert fixed caps to
        unfixed caps. This means that the sink pad input caps can be converted
        into unfixed (multiple) formats. The source pad will have to choose a
        format from all the possibilities. It would usually like to choose a
        format that requires the least amount of effort to produce but it does
        not have to be. The selection of the format should also depend on the
        caps that can be accepted downstream (see a QUERY_CAPS function in
        <xref linkend="section-nego-getcaps"/>).
      </para>
      <para>
        A typical flow goes like this:
      </para>
      <itemizedlist>
        <listitem>
          <para>
            Caps are received on the sink pad of the element.
          </para>
        </listitem>
        <listitem>
          <para>
            If the element prefers to operate in passthrough mode, check
            if downstream accepts the caps with the ACCEPT_CAPS query. If it
            does, we can complete negotiation and we can operate in
            passthrough mode.
          </para>
        </listitem>
        <listitem>
          <para>
            Calculate the possible caps for the source pad.
          </para>
        </listitem>
        <listitem>
          <para>
            Query the downstream peer pad for the list of possible
            caps.
          </para>
        </listitem>
        <listitem>
          <para>
            Select from the downstream list the first caps that you can
            transform to and set this as the output caps. You might have to
            fixate the caps to some reasonable defaults to construct
            fixed caps.
          </para>
        </listitem>
      </itemizedlist>
      <para>
        Examples of this type of elements include:
      </para>
      <itemizedlist>
        <listitem>
          <para>
            Converter elements such as videoconvert, audioconvert, audioresample,
            videoscale, ...
          </para>
        </listitem>
        <listitem>
          <para>
            Source elements such as audiotestsrc, videotestsrc, v4l2src,
            pulsesrc, ...
          </para>
        </listitem>
      </itemizedlist>
      <para>
        Let's look at the example of an element that can convert between
        samplerates, so where input and output samplerate don't have to be
        the same:
      </para>
      <programlisting>
<![CDATA[
static gboolean
gst_my_filter_setcaps (GstMyFilter *filter,
		       GstCaps *caps)
{
  if (gst_pad_set_caps (filter->sinkpad, caps)) {
    filter->passthrough = TRUE;
  } else {
    GstCaps *othercaps, *newcaps;
    GstStructure *s = gst_caps_get_structure (caps, 0), *others;

    /* no passthrough, setup internal conversion */
    gst_structure_get_int (s, "channels", &filter->channels);
    othercaps = gst_pad_get_allowed_caps (filter->srcpad);
    others = gst_caps_get_structure (othercaps, 0);
    gst_structure_set (others,
      "channels", G_TYPE_INT, filter->channels, NULL);

    /* now, the samplerate value can optionally have multiple values, so
     * we "fixate" it, which means that one fixed value is chosen */
    newcaps = gst_caps_copy_nth (othercaps, 0);
    gst_caps_unref (othercaps);
    gst_pad_fixate_caps (filter->srcpad, newcaps);
    if (!gst_pad_set_caps (filter->srcpad, newcaps))
      return FALSE;

    /* we are now set up, configure internally */
    filter->passthrough = FALSE;
    gst_structure_get_int (s, "rate", &filter->from_samplerate);
    others = gst_caps_get_structure (newcaps, 0);
    gst_structure_get_int (others, "rate", &filter->to_samplerate);
  }

  return TRUE;
}

static gboolean
gst_my_filter_sink_event (GstPad    *pad,
		          GstObject *parent,
		          GstEvent  *event)
{
  gboolean ret;
  GstMyFilter *filter = GST_MY_FILTER (parent);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_CAPS:
    {
      GstCaps *caps;

      gst_event_parse_caps (event, &caps);
      ret = gst_my_filter_setcaps (filter, caps);
      break;
    }
    default:
      ret = gst_pad_event_default (pad, parent, event);
      break;
  }
  return ret;
}

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

  /* push on if in passthrough mode */
  if (filter->passthrough)
    return gst_pad_push (filter->srcpad, buf);

  /* convert, push */
  out = gst_my_filter_convert (filter, buf);
  gst_buffer_unref (buf);

  return gst_pad_push (filter->srcpad, out);
}
]]>
      </programlisting>
    </sect2>
  </sect1>

  <sect1 id="section-nego-upstream" xreflabel="Upstream caps (re)negotiation">
    <title>Upstream caps (re)negotiation</title>
    <para>
      Upstream negotiation's primary use is to renegotiate (part of) an
      already-negotiated pipeline to a new format. Some practical examples
      include to select a different video size because the size of the video
      window changed, and the video output itself is not capable of rescaling,
      or because the audio channel configuration changed.
    </para>
    <para>
      Upstream caps renegotiation is requested by sending a GST_EVENT_RECONFIGURE
      event upstream. The idea is that it will instruct the upstream element
      to reconfigure its caps by doing a new query for the allowed caps and then
      choosing a new caps. The element that sends out the RECONFIGURE event
      would influence the selection of the new caps by returning the new
      prefered caps from its GST_QUERY_CAPS query function. The RECONFIGURE
      event will set the GST_PAD_FLAG_NEED_RECONFIGURE on all pads that it
      travels over.
    </para>
    <para>
      It is important to note here that different elements actually have
      different responsibilities here:
    </para>
    <itemizedlist>
      <listitem>
        <para>
          Elements that want to propose a new format upstream need to first
          check if the new caps are acceptable upstream with an ACCEPT_CAPS
          query. Then they would send a RECONFIGURE event and be prepared to
          answer the CAPS query with the new prefered format. It should be
          noted that when there is no upstream element that can (or wants)
          to renegotiate, the element needs to deal with the currently
          configured format.
        </para>
      </listitem>
      <listitem>
        <para>
          Elements that operate in transform negotiation according to
          <xref linkend="section-nego-transform"/> pass the RECONFIGURE
          event upstream. Because these elements simply do a fixed transform
          based on the upstream caps, they need to send the event upstream
          so that it can select a new format.
        </para>
      </listitem>
      <listitem>
        <para>
          Elements that operate in fixed negotiation 
          (<xref linkend="section-nego-fixed"/>) drop the RECONFIGURE event.
          These elements can't reconfigure and their output caps don't depend
          on the upstream caps so the event can be dropped.
        </para>
      </listitem>
      <listitem>
        <para>
          Elements that can be reconfigured on the source pad (source pads
          implementing dynamic negotiation in
          <xref linkend="section-nego-dynamic"/>) should check its
          NEED_RECONFIGURE flag with
          <function>gst_pad_check_reconfigure ()</function> and it should
          start renegotiation when the function returns TRUE.
        </para>
      </listitem>
    </itemizedlist>
  </sect1>

  <sect1 id="section-nego-getcaps" xreflabel="Implementing a CAPS query function">
    <title>Implementing a CAPS query function</title>
    <para>
      A <function>_query ()</function>-function with the GST_QUERY_CAPS query
      type is called when a peer element would like to know which formats
      this pad supports, and in what order of preference. The return value
      should be all formats that this elements supports, taking into account
      limitations of peer elements further downstream or upstream, sorted by
      order of preference, highest preference first.
    </para>
    <para>
    </para>
    <programlisting>
<![CDATA[
static gboolean
gst_my_filter_query (GstPad *pad, GstObject * parent, GstQuery * query)
{
  gboolean ret;
  GstMyFilter *filter = GST_MY_FILTER (parent);

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_CAPS
    {
      GstPad *otherpad;
      GstCaps *temp, *caps, *filt, *tcaps;
      gint i;

      otherpad = (pad == filter->srcpad) ? filter->sinkpad :
                                           filter->srcpad;
      caps = gst_pad_get_allowed_caps (otherpad);

      gst_query_parse_caps (query, &filt);

      /* We support *any* samplerate, indifferent from the samplerate
       * supported by the linked elements on both sides. */
      for (i = 0; i < gst_caps_get_size (caps); i++) {
        GstStructure *structure = gst_caps_get_structure (caps, i);

        gst_structure_remove_field (structure, "rate");
      }

      /* make sure we only return results that intersect our
       * padtemplate */
      tcaps = gst_pad_get_pad_template_caps (pad);
      if (tcaps) {
        temp = gst_caps_intersect (caps, tcaps);
        gst_caps_unref (caps);
        gst_caps_unref (tcaps);
        caps = temp;
      }
      /* filter against the query filter when needed */
      if (filt) {
        temp = gst_caps_intersect (caps, filt);
        gst_caps_unref (caps);
        caps = temp;
      }
      gst_query_set_caps_result (query, caps);
      gst_caps_unref (caps);
      ret = TRUE;
      break;
    }
    default:
      ret = gst_pad_query_default (pad, parent, query);
      break;
  }
  return ret;
}
]]>
    </programlisting>
  </sect1>

  <sect1 id="section-nego-pullmode">
    <title>Pull-mode Caps negotiation</title>
    <para>
      WRITEME, the mechanism of pull-mode negotiation is not yet fully
      understood.
    </para>

    <para>
      Using all the knowledge you've acquired by reading this chapter, you
      should be able to write an element that does correct caps negotiation.
      If in doubt, look at other elements of the same type in our git
      repository to get an idea of how they do what you want to do.
    </para>
  </sect1>
</chapter>