summaryrefslogtreecommitdiff
path: root/configuring-pipelines.rst
blob: 440be2aa040b0565efc9aa21b9b091cda6257d00 (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
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
.. SPDX-License-Identifier: CC-BY-SA-4.0

Configuring Pipelines
=====================

Allowing fine-grained control of formats comes at the cost of increasing
complexity for applications. Where an application used to only have to set the
format on a video device, it must now set formats on all pads in the pipeline,
and ensure that the result forms a coherent configuration.

As previously stated, the examples in this section will be based on the NXP
i.MX8MP ISP device:

.. graphviz:: imx8mp-isp.dot
   :caption: Media graph of the NXP i.MX8MP with default configuration


Anatomy of a Pipeline
---------------------

.. _media-ctl: https://git.linuxtv.org/v4l-utils.git/tree/utils/media-ctl
.. _v4l2-ctl: https://git.linuxtv.org/v4l-utils.git/tree/utils/v4l2-ctl

The `media-ctl`_ utility can be used to display the formats on all pads in a
graph. Let's start by disecting the output of ``media-ctl -d /dev/media0 -p``:

.. code-block:: none
   :linenos:
   :lineno-start: 1

   $ media-ctl -d /dev/media0 -p
   Media controller API version 6.0.0

   Media device information
   ------------------------
   driver          rkisp1
   model           rkisp1
   serial          
   bus info        platform:rkisp1
   hw revision     0xe
   driver version  6.0.0

media-ctl first provides summary information, to quickly identify the hardware
device corresponding to the media controller device (``/dev/media0`` here):

- the driver name
- the device model name
- the device serial number (when available)
- which bus the device sits on
- the device hardware revision (in a device-specific format)
- the driver version (identical to the kernel version)

The ISP integrated in the NXP i.MX8MP is also found in Rockchip SoCs. They are
both handled by the ``rkisp1`` kernel driver, as shown by the driver and device
model names.

media-ctl then prints detailed information for all entities in the graph.
Entities are sorted by their numerical ID, which doesn't necessarily follow any
logical order. To improve readability, the entities below have been reordered
in source to sink order, as shown by the line numbers. This corresponds to the
top to bottom order in the graphical representation of the media graph.

.. code-block:: none
   :linenos:
   :lineno-start: 73

   - entity 34: imx290 2-001a (1 pad, 1 link)
                type V4L2 subdev subtype Sensor flags 0
                device node name /dev/v4l-subdev3
           pad0: Source
                   [fmt:SRGGB10_1X10/1920x1080 field:none
                    crop.bounds:(0,0)/1945x1097
                    crop:(12,8)/1920x1080]
                   -> "csis-32e40000.csi":0 []

All entities have a numerical ID and a name. The first entity in pipeline order
has ID ``34`` and is named ``imx290 2-001a``. Names are chosen by drivers but
should follow a set of naming rules. For devices controlled through an I2C bus,
as is the case here, the entity name is made of the device model (``imx290``)
and bus information (``2-001a``) separated by a space. The I2C bus information
is itself made of the bus number and the device address (in hexadecimal),
separated by a dash.

This particular entity has a total of 1 pad and 1 link (line 73). It is a V4L2
subdevice whose subtype is a camera sensor (line 74). The subdevice is exposed
to userspace through the ``/dev/v4l-subdev3`` device node (line 75).

For each pad of the entity media-ctl then displays the pad index and type, the
available links, as well as pad information specific to the entity type.  Pad
indices start at 0. The IMX290 camera sensor entity has a single pad, thus at
index 0 and named ``pad0``, whose type is a source pad (line 76).

Links are displayed on lines starting with a ``->`` (for outbound links, on
source pads) or ``<-`` (for inbound links, on sink pads) sign, followed by the
link target (``"csis-32e40000.csi":0``) and link flags (``[]``). The link
target is a pad of another entity, expressed as the target entity name
surrounded by double quotes, followed by a colon and the target pad index. The
supported link flags (with their numerical values) are:

ENABLED (0x1)
   The link is enabled. In the absence of this flag, the link is disabled.

IMMUTABLE (0x2)
   The link is immutable, its ``ENABLED`` flag cannot be modified. Immutable
   links in practice always have the ``ENABLED`` flag set.

As the list of link flags is empty, this specific link is thus disabled, but
can be enabled as it isn't immutable. The graphical representation displays
this link as a dotted line.

We will ignore for now the pad information specific to the entity type
displayed on lines 77 to 79, this will be explained further down.

The next entity, in graph order, is the MIPI CSI-2 receiver that the camera
sensor is attached to:

.. code-block:: none
   :linenos:
   :lineno-start: 64

   - entity 29: csis-32e40000.csi (2 pads, 2 links)
                type V4L2 subdev subtype Unknown flags 0
                device node name /dev/v4l-subdev2
           pad0: Sink
                   [fmt:UYVY8_1X16/640x480 field:none colorspace:smpte170m xfer:709 ycbcr:601 quantization:lim-range]
                   <- "imx290 2-001a":0 []
           pad1: Source
                   [fmt:UYVY8_1X16/640x480 field:none colorspace:smpte170m xfer:709 ycbcr:601 quantization:lim-range]
                   -> "rkisp1_isp":0 [ENABLED]

The CSI-2 receiver is an IP core internal to the SoC, modelled in the kernel as
a platform device. Entity names from platform devices are more free-formed. In
this case, the driver follows the usual recommendation, which uses the platform
device model name (``csis``) and the platform device name (``32e40000.csi``),
separated by a dash. On machines using Device Tree to describe the system (as
is the case on ARM and ARM64 machines), the platform device name is typically
make of the device's bus address (``32e40000``) and device node name (``csi``).

This entity has two pads, a sink pad and a source pad, with one link each. The
sink pad, ``pad0`` (line 67), is the target of the link originating from the
camera sensor, and is thus without surprise displayed as connected to the
source pad of the camera sensor (line 69). The link flags being a property of
the link, not the pad, they match the link flags displayed in the camera sensor
entity.

The source pad, ``pad1`` (line 70), is connected to pad 0 of the ``rkisp1_isp``
entity (line 72). This link is enabled but not immutable, thus displayed as a
thin plain line in the graphical representation.

The next entity represents the core of the ISP itself:

.. code-block:: none
   :linenos:
   :lineno-start: 14

   - entity 1: rkisp1_isp (4 pads, 4 links)
               type V4L2 subdev subtype Unknown flags 0
               device node name /dev/v4l-subdev0
           pad0: Sink
                   [fmt:SRGGB10_1X10/800x600 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range
                    crop.bounds:(0,0)/800x600
                    crop:(0,0)/800x600]
                   <- "csis-32e40000.csi":1 [ENABLED]
           pad1: Sink
                   [fmt:unknown/0x0 field:none]
                   <- "rkisp1_params":0 [ENABLED,IMMUTABLE]
           pad2: Source
                   [fmt:YUYV8_2X8/800x600 field:none colorspace:srgb xfer:srgb ycbcr:601 quantization:lim-range
                    crop.bounds:(0,0)/800x600
                    crop:(0,0)/800x600]
                   -> "rkisp1_resizer_mainpath":0 [ENABLED]
           pad3: Source
                   [fmt:unknown/0x0 field:none]
                   -> "rkisp1_stats":0 [ENABLED,IMMUTABLE]

Its name doesn't follow the previously described recommendation for entities
corresponding to platform devices, which shows that applications can't rely on
a particular format for entity names in general. This may be considered as a
kernel bug, but is unlikely to be changed as entity name changes may break
existing applications.

This entity is also a V4L2 subdevice, with four pads, two sink pads (``pad0``
and ``pad1`` on lines 17 and 22 respectively) and two source pads (``pad2`` and
``pad3`` on lines 25 and 30). Pads 1 and 3 are connected to entities
representing the video device nodes through which ISP parameters are supplied
and ISP statistics are captured. We will ignore them in this example as they
are not strictly required to operate the device. It is however worth noting
that the corresponding links are enabled and immutable, and thus displayed in
the graphical representation as thich plain lines.

Pad 2 is a source pad that connects the ISP core to the resizer, which is the
next entity in the pipeline.

.. code-block:: none
   :linenos:
   :lineno-start: 34

   - entity 6: rkisp1_resizer_mainpath (2 pads, 2 links)
               type V4L2 subdev subtype Unknown flags 0
               device node name /dev/v4l-subdev1
           pad0: Sink
                   [fmt:YUYV8_2X8/800x600 field:none colorspace:srgb xfer:srgb ycbcr:601 quantization:lim-range
                    crop.bounds:(0,0)/800x600
                    crop:(0,0)/800x600]
                   <- "rkisp1_isp":2 [ENABLED]
           pad1: Source
                   [fmt:YUYV8_2X8/800x600 field:none colorspace:srgb xfer:srgb ycbcr:601 quantization:lim-range]
                   -> "rkisp1_mainpath":0 [ENABLED,IMMUTABLE]

The resizer is also a V4L2 subdevice, and has nothing noteworthy at this point
compared to the entities previously described. Its source pad (line 42) is
connected to the last entity in the pipeline:

.. code-block:: none
   :linenos:
   :lineno-start: 46

   - entity 9: rkisp1_mainpath (1 pad, 1 link)
               type Node subtype V4L flags 0
               device node name /dev/video0
           pad0: Sink
                   <- "rkisp1_resizer_mainpath":1 [ENABLED,IMMUTABLE]

The ``rkisp1_mainpath`` entity, unlike all previous entities, is not a V4L2
subdevice but a V4L2 video node (line 47). Its device node name is
``/dev/video0`` (line 48), corresponding to the output of the pipeline. This is
the device node from which frames originating from the sensor, processed by the
ISP, and scaled by the resizer are captured.

Let's try to capture frames in NV16 format with a 800x600 resolution:

.. code-block:: none
   :emphasize-lines: 2

   $ v4l2-ctl -d /dev/video0 -v pixelformat=NV16,width=800,height=600 --stream-count 10 --stream-mmap
                   VIDIOC_STREAMON returned -1 (Broken pipe)

The kernel driver returns the `Broken pipe` error code, which indicates that
the pipeline isn't properly configured. The first possibly culprit to
investigate is the links.


Link Setup
----------

.. _EBNF metasyntax: https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form

We have seen that, unless immutable, links can be enabled or disabled. Enabling
or disabling links allows configuring data routing through the graph. For
instance, a device that has multiple camera sensors connected to an ISP, but
can only capture from one of the sensors at a time, could be controlled by
enabling one of the links from the camera sensors to select the source.

In the default configuration of the device, the link from the camera sensor to
the CSI-2 receiver is disabled. The pipeline is thus missing a source, which
causes the capture to fail with the `Broken pipe` error. To fix this, links
must be setup before starting capture. This is done with the media-ctl utility:

.. code-block:: none

   $ media-ctl -d /dev/media0 --link '"imx290 2-001a":0 -> "csis-32e40000.csi":0 [1]'

The ``-link`` option (or its shorter form ``-l``) takes a list of links,
expressed as follows (using a syntax close to the `EBNF metasyntax`_, found in
the output of ``media-ctl --help``):

.. code-block:: ebnf

   links           = link { ',' link } ;
   link            = pad '->' pad '[' flags ']' ;
   pad             = entity ':' pad-number ;
   entity          = entity-number | ( '"' entity-name '"' ) ;

In the above example, we enable (``[1]``) the link from the source pad of the
camera sensor entity (``'"imx290 2-001a":0``) to the sink pad of the CSI-2
receiver entity (``"csis-32e40000.csi":0``). Links can also be disabled by
clearing the ENABLED flag (using ``[0]``), and multiple links can be setup with
a single command, although this is discouraged in scripts as the resulting
syntax would be hard to read.

After running the above command, ``media-ctl -p`` reports the link between the
camera sensor and the CSI-2 receiver as enabled:

.. code-block:: none
   :linenos:
   :lineno-start: 73
   :emphasize-lines: 8

   - entity 34: imx290 2-001a (1 pad, 1 link)
                type V4L2 subdev subtype Sensor flags 0
                device node name /dev/v4l-subdev3
           pad0: Source
                   [fmt:SRGGB10_1X10/1920x1080 field:none
                    crop.bounds:(0,0)/1945x1097
                    crop:(12,8)/1920x1080]
                   -> "csis-32e40000.csi":0 [ENABLED]

This is also displayed in the graphical representation, with the corresponding
link now being a thin plain line instead of a dotted line:

.. graphviz:: imx8mp-isp-links-enabled.dot
   :caption: Media graph of the NXP i.MX8MP after enabling links

.. note::

   It is recommended, before setting up links in a pipeline, to reset all
   non-immutable links to their disabled state with ``media-ctl --reset``. This
   helps starting from a known state and, and avoids depending on a previous
   configuration of the media graph.  In this specific example, the links
   between the CSI-2 receiver and the ISP, and between the ISP and the resizer,
   would get disabled, and would need to be enabled manually to create a
   complete pipeline.

Let's try to capture frames in NV16 format with a 800x600 resolution again:

.. code-block:: none
   :emphasize-lines: 2

   $ v4l2-ctl -d /dev/video0 -v pixelformat=NV16,width=800,height=600 --stream-count 10 --stream-mmap
                   VIDIOC_STREAMON returned -1 (Broken pipe)

The kernel still returns the `Broken pipe` error, for an entirely different
reason: we haven't taken care of formats in the pipeline.


Formats in the Pipeline
-----------------------

.. _Media Bus Format: https://linuxtv.org/downloads/v4l-dvb-apis/userspace-api/v4l/subdev-formats.html>

It is time to stop ignoring the pad information specific to the entity type
that is printed by media-ctl. Let's have a look at the camera sensor entity
again:

.. code-block:: none
   :linenos:
   :lineno-start: 73
   :emphasize-lines: 5-7

   - entity 34: imx290 2-001a (1 pad, 1 link)
                type V4L2 subdev subtype Sensor flags 0
                device node name /dev/v4l-subdev3
           pad0: Source
                   [fmt:SRGGB10_1X10/1920x1080 field:none
                    crop.bounds:(0,0)/1945x1097
                    crop:(12,8)/1920x1080]
                   -> "csis-32e40000.csi":0 [ENABLED]

For entities corresponding to V4L2 subdevices, media-ctl prints the active
configuration for each pad (lines 68 to 78). The configuration is made of
multiple properties:

- The media bus format, expressed as

  .. code-block:: ebnf

     media bus format = "fmt:", fcc, "/", size ;
     size             = width, "x", height ;

  where ``fcc`` is the `media bus format`_ code. Format codes are listed in the
  ``linux/media-bus-format.h`` header file of the Linux kernel, and expressed
  here as a string without the ``MEDIA_BUS_FMT_`` prefix.

- The field, for interlaced video:

  .. code-block:: ebnf

     field      = "field:", v4l2-field ;
     v4l2-field = "any" | "none" | "top" | "bottom" | "interlaced"
                | "seq-tb" | "seq-bt" | "alternate" | "interlaced-tb"
                | "interlaced-bt" ;

- The color space, expressed as four properties, reporting the V4L2 color
  space, transfer function, YCbCr encoding and quantization range:

  .. code-block:: ebnf

     color space    = "colorspace:", v4l2-colorspace, " xfer:", v4l2-xfer-func,
                      " ycbcr:", v4l2-ycbcr-enc, " quantization:", v4l2-quant ;
     v4l2-colorspace = "default" | "smpte170m" | "smpte240m" | "rec709"
                     | "470m" | "470bg" | "jpeg" | "srgb" | "oprgb" | "bt2020"
                     | "raw" | "dcip3" ;
     v4l2-xfer-func  =  "default" | "709" | "srgb" | "oprgb" | "smpte240m"
                     | "smpte2084" | "dcip3" | "none" ;
     v4l2-ycbcr-enc  = "default" | "601" | "709" | "xv601" | "xv709" | "bt2020"
                     | "bt2020c" | "smpte240m" ;
     v4l2-quant      = "default" | "full-range" | "lim-range" ;

- The compose and crop rectangles:

  .. code-block:: ebnf

     rectangle = "(", left, ",", top, ")", "/", size ;
     size      = width, "x", height ;


In order for a pipeline to be valid, the configuration of pads on both sides of
every link must match. Unless drivers implement custom validation rules, the
default constraint is that the media bus format on both sides must be
identical. For interlaced video, the fields must also be identical, or the
field on the sink side must be equal to ``none`` (in order to support
interlaced sources connected to sinks that only support progressive formats).
The crop and compose rectangles are not taken into account when validating
pipelines, as they are internal to subdevices.

The default validation is performed by the ``v4l2_subdev_link_validate_default()``
function in the kernel. If dynamic debugging is enabled (through the
``CONFIG_DYNAMIC_DEBUG`` kernel configuration option), extra messages can be
enabled through debugfs to diagnose the problem more precisely:

.. code-block:: none

   $ mount -t debugfs none /sys/kernel/debug/
   $ echo 'func v4l2_subdev_link_validate_default +p' > /sys/kernel/debug/dynamic_debug/control

After trying to capture frames with v4l2-ctl and obtaining the `Broken pipe`
error, the kernel log (obtained with ``dmesg``) provides useful information:

.. code-block:: none

   rkisp1 32e10000.isp: Validating pad 'rkisp1_isp':0
   rkisp1 32e10000.isp: v4l2_subdev_link_validate_default: width does not match (source 640, sink 800)
   rkisp1 32e10000.isp: v4l2_subdev_link_validate_default: height does not match (source 480, sink 600)
   rkisp1 32e10000.isp: v4l2_subdev_link_validate_default: media bus code does not match (source 0x0000200f, sink 0x0000300f)
   rkisp1 32e10000.isp: v4l2_subdev_link_validate_default: link was "csis-32e40000.csi":1 -> "rkisp1_isp":0
   rkisp1 32e10000.isp: Link 'csis-32e40000.csi':1 -> 'rkisp1_isp':0 failed validation: -32

This indicates a mismatch between the source pad of the CSI-2 receiver and the
sink pad of the ISP, both in the resolution and in the format code. The CSI-2
receiver is configured to output UYVY8_1X16 in 640x480, and the ISP to receive
SRGGB10_1X10 in 800x600, leading to a broken pipeline.

To fix this, formats must be configuration through the pipeline with a process
referred to as `format propagation`.


Format Propagation
------------------

Format propagation is a pipeline configuration mechanism where the format is
first configured on the source of the pipeline (the camera sensor in this
case), and then propagated downstream through all subdevices until the video
node at the end of the pipeline. It involves two different types of operations:

- To ensure that formats on both ends of a link match, when configuring the
  format on a source pad of a subdevice, the same format must be set on the
  connected sink pad at the other end of the link. This is known as `format
  propagation across links`. Subdevices do not automatically propagate formats
  across links within the kernel in order to avoid hardcoding use cases in
  drivers and to simplify driver implementation. This format propagation is the
  responsibility of userspace.

- Within a subdevice, the kernel ensures that pads configuration stays valid at
  all times. When an application configures a format on a subdevice pad, the
  driver adjusts parameters that are not valid to the closest supported values.
  For instance, resolutions are clampedto the supported range, rounded if the
  device has alignment constraints, and unsupported format codes are replaced
  with supported values. This is known as `format negotiation` and is similar
  to how the kernel handles format setting on V4L2 video devices.

  In addition to the format negotiation at the pad level, the kernel also
  ensures that the configurations of all pads within a subdevice remain
  coherent with each other. When an application configures the format on a sink
  pad, the subdevice driver also adjusts the configuration of the source pads
  if the new sink pad configuration would otherwise result in an invalid
  subdevice configuration. For instance, the i.MX8MP resizer can scale images
  but can't convert between bus format codes, so if an application sets a
  format code on the resizer sink pad, the driver will automatically set the
  same format code on the resizer source pad. This is known as `format
  propagation inside subdevices`, and is the responsibility of the subdevice
  drivers.

  Unlike across links where the formats on the source and sink sides of a link
  must match, formats on the sink and source pads of a subdevice may be
  different. For instance, the i.MX8MP ISP interpolates the raw Bayer data
  provided by the camera sensor, and converts it to YUV. The format code on the
  source pad of the ISP will thus differ from the sink pad. When userspace
  configures the format on the ISP sink pad, the driver will propagate the sink
  resolution to the source pad, but will adjust the sink Bayer format code to a
  YUV format code on the source pad.

  Format propagation within subdevices ensures that their configuration remains
  coherent, but doesn't save applications from having to configure formats on
  source pads. Using the resizer example again, the driver will ensure that the
  format on the source pad gets adjusted to a value compatible with the format
  set on the sink pad, but applications will likely want to then configure the
  format on the source pad explicitly in order to change the resolution and
  select the scaling ratio. Format propagation within subdevices always operate
  `from sink to source`. When userspace sets the format on a source pad, the
  driver will adjust it to values compatible with the current configuration of
  the sink pads if needed, but will never modify the sink pads configuration by
  back-propagating the format from source pad to sink pad.

Subdevice pad formats can be set with the media-ctl utility, using the
``--set-v4l2`` option (shortened to ``-V``). The syntax is identical to the
format printed by media-ctl with the ``-p`` option. The first step in our
example is to configure the format on the sensor source pad. We use the default
format reported by the media graph (10-bit raw Bayer in 1920x1080), which
corresponds to the sensor native resolution:

.. code-block:: none

   $ media-ctl -d /dev/media0 -V '"imx290 2-001a":0 [fmt:SRGGB10_1X10/1920x1080 colorspace:raw xfer:none ycbcr:601 quantization:full-range]'

Running ``media-ctl -p`` again, the format on the sensor source pad has been
updated with the newly selected color space:

.. code-block:: none
   :linenos:
   :lineno-start: 73
   :emphasize-lines: 5

   - entity 34: imx290 2-001a (1 pad, 1 link)
                type V4L2 subdev subtype Sensor flags 0
                device node name /dev/v4l-subdev3
           pad0: Source
                   [fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range
                    crop.bounds:(0,0)/1945x1097
                    crop:(12,8)/1920x1080]
                   -> "csis-32e40000.csi":0 [ENABLED]

The format is otherwise the same, as we have selected a format code and
resolution identical to the previously configured value. However, this is not
the only change in the media graph. The configuration of the CSI-2 receiver is
now different:

.. code-block:: none
   :linenos:
   :lineno-start: 64
   :emphasize-lines: 5,8

   - entity 29: csis-32e40000.csi (2 pads, 2 links)
                type V4L2 subdev subtype Unknown flags 0
                device node name /dev/v4l-subdev2
           pad0: Sink
                   [fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range]
                   <- "imx290 2-001a":0 [ENABLED]
           pad1: Source
                   [fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range]
                   -> "rkisp1_isp":0 [ENABLED]

The change in the sink pad format seems to contradict what we have seen before,
as the kernel isn't supposed to propagate formats across links. The reason for
this lies in the media-ctl utility. When setting a format on a source pad,
media-ctl automatically reads back the format from the subdevice (to take into
account possible adjustments applied by the driver) and sets that format on all
sink pads connected through enabled links.

The source pad format is also modified, due to automatic format propagation by
drivers within subdevices. As the CSI-2 receiver can't transcode or scale, the
source pad format has thus been set to match the sink pad format.

These two effects simplify the format propagation procedure, as formats on sink
pads don't need to be set manually. Instead, we can read back the format on the
source pad of the next subdevice (the CSI-2 receiver in this case) using
``media-ctl -p``, and set it on the same pad to let media-ctl propagate it to
the next subdevice:

.. code-block:: none

   $ media-ctl -d /dev/media0 -V '"csis-32e40000.csi":1 [fmt:SRGGB10_1X10/1920x1080 colorspace:raw xfer:none ycbcr:601 quantization:full-range]'

We expect the next subdevice, ´´rkisp1_isp``, to output an image in a processed
YUV format with a 1920x1080 resolution. This is not what happens:

.. code-block:: none
   :linenos:
   :lineno-start: 14
   :emphasize-lines: 6-7,13

   - entity 1: rkisp1_isp (4 pads, 4 links)
               type V4L2 subdev subtype Unknown flags 0
               device node name /dev/v4l-subdev0
           pad0: Sink
                   [fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range
                    crop.bounds:(0,0)/1920x1080
                    crop:(0,0)/800x600]
                   <- "csis-32e40000.csi":1 [ENABLED]
           pad1: Sink
                   [fmt:unknown/0x0 field:none]
                   <- "rkisp1_params":0 [ENABLED,IMMUTABLE]
           pad2: Source
                   [fmt:YUYV8_2X8/800x600 field:none colorspace:raw xfer:none ycbcr:601 quantization:lim-range
                    crop.bounds:(0,0)/800x600
                    crop:(0,0)/800x600]
                   -> "rkisp1_resizer_mainpath":0 [ENABLED]
           pad3: Source
                   [fmt:unknown/0x0 field:none]
                   -> "rkisp1_stats":0 [ENABLED,IMMUTABLE]

The output format code (``YUYV8_2X8``) is fine, but the output resolution has
been set to 800x600. This is due to the crop capability of the sink pad. While
the crop bounds have been adjusted (line 19), the crop rectangle itself (line
20) hasn't been adjusted as its previous size (``(0,0)/800x600``) is compatible
with the new sink format. We must thus set the crop rectangle manually on the
sink pad:

.. code-block:: none

   $ media-ctl -d /dev/media0 -V '"rkisp1_isp":0 [crop:(0,0)/1920x1080]'

This improves the situation:

.. code-block:: none
   :linenos:
   :lineno-start: 14
   :emphasize-lines: 7,13-15

   - entity 1: rkisp1_isp (4 pads, 4 links)
               type V4L2 subdev subtype Unknown flags 0
               device node name /dev/v4l-subdev0
           pad0: Sink
                   [fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range
                    crop.bounds:(0,0)/1920x1080
                    crop:(0,0)/1920x1080]
                   <- "csis-32e40000.csi":1 [ENABLED]
           pad1: Sink
                   [fmt:unknown/0x0 field:none]
                   <- "rkisp1_params":0 [ENABLED,IMMUTABLE]
           pad2: Source
                   [fmt:YUYV8_2X8/800x600 field:none colorspace:raw xfer:none ycbcr:601 quantization:lim-range
                    crop.bounds:(0,0)/1920x1080
                    crop:(0,0)/800x600]
                   -> "rkisp1_resizer_mainpath":0 [ENABLED]
           pad3: Source
                   [fmt:unknown/0x0 field:none]
                   -> "rkisp1_stats":0 [ENABLED,IMMUTABLE]

The crop bounds on the source pad (line 27) now cover the full resolution, but
the source crop rectangle (line 28) hasn't been adjusted, for the same reason
as previously. Fixing this is simple:

.. code-block:: none

   $ media-ctl -d /dev/media0 -V '"rkisp1_isp":2 [crop:(0,0)/1920x1080]'

This gives us the configuration we want for the source resolution:

.. code-block:: none
   :linenos:
   :lineno-start: 14
   :emphasize-lines: 13,15

   - entity 1: rkisp1_isp (4 pads, 4 links)
               type V4L2 subdev subtype Unknown flags 0
               device node name /dev/v4l-subdev0
           pad0: Sink
                   [fmt:SRGGB10_1X10/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range
                    crop.bounds:(0,0)/1920x1080
                    crop:(0,0)/1920x1080]
                   <- "csis-32e40000.csi":1 [ENABLED]
           pad1: Sink
                   [fmt:unknown/0x0 field:none]
                   <- "rkisp1_params":0 [ENABLED,IMMUTABLE]
           pad2: Source
                   [fmt:YUYV8_2X8/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:lim-range
                    crop.bounds:(0,0)/1920x1080
                    crop:(0,0)/1920x1080]
                   -> "rkisp1_resizer_mainpath":0 [ENABLED]
           pad3: Source
                   [fmt:unknown/0x0 field:none]
                   -> "rkisp1_stats":0 [ENABLED,IMMUTABLE]

Finally, we set the format on the source pad to let media-ctl propagate it to
the next subdevice (``rkisp1_resizer_mainpath``):

.. code-block:: none

   $ media-ctl -d /dev/media0 -V '"rkisp1_isp":2 [fmt:YUYV8_2X8/1920x1080]'

The resizer sink pad format is configured correctly:

.. code-block:: none
   :linenos:
   :lineno-start: 34
   :emphasize-lines: 5,7,10

   - entity 6: rkisp1_resizer_mainpath (2 pads, 2 links)
               type V4L2 subdev subtype Unknown flags 0
               device node name /dev/v4l-subdev1
           pad0: Sink
                   [fmt:YUYV8_2X8/1920x1080 field:none colorspace:raw xfer:none ycbcr:601 quantization:lim-range
                    crop.bounds:(0,0)/1920x1080
                    crop:(0,0)/800x600]
                   <- "rkisp1_isp":2 [ENABLED]
           pad1: Source
                   [fmt:YUYV8_2X8/800x600 field:none colorspace:raw xfer:none ycbcr:601 quantization:lim-range]
                   -> "rkisp1_mainpath":0 [ENABLED,IMMUTABLE]

The resizer source pad (line 43) matches the resolution we want to capture
(``800x600``). However, this is not achieved by scaling, but by cropping the
input frame (line 40). This isn't the desired behaviour, so, even if frame
capture would work with this configuration, we must adjust the sink pad crop
rectangle:

.. code-block:: none

   $ media-ctl -d /dev/media0 -V '"rkisp1_resizer_mainpath":0 [crop:(0,0)/1920x1080]'

The source pad format is unchanged and still set to ``YUYV8_2X8/800x600``. If
we wanted to scale to a different resolution, we would need to set the format
on the resizer source pad at this point.

The next entity in the pipeline (``rkisp1_mainpath``) is not a subdevice but a
video device. There is no need to configure pad formats, as formats on video
devices are set through the classic V4L2 API. Care must be taken to configure
the video device with a pixel format compatible with the source pad of the last
subdevice in the pipeline, and an identical resolution. Which pixel formats
qualify as compatible is device-dependent, as explained in the
:ref:`v4l2-subdevice-formats` section. For the i.MX8MP, the DMA engine at the
output of the pipeline can write the YUV 4:2:2 data it receives from the
resizer in the semi-planar NV16 format:

.. code-block:: none

   $ v4l2-ctl -d /dev/video0 -v pixelformat=NV16,width=800,height=600 --stream-count 10 --stream-mmap
   <<<<<<<<<<

The pipeline is valid, and 10 frames have been captured successfully.


Summary
-------

Pipelines can be inspected with ``media-ctl -p`` and must configured by
userspace before being used.

The first configuration step covers link setup. Links should be reset with
``media-ctl -r`` to avoid any influence from a previous configuration, and
individual links should then be enabled with ``media-ctl -l``.

The second configuration step covers format configuration. Formats are set with
``media-ctl -V`` and must be propagated through the pipeline from source to
sink. The combination of automatic format propagation across links in media-ctl
with the automatic format propagation inside subdevices in the kernel
simplifies format propagation. The generic procedure is as follows:

#. Set the format on the source pad of the first subdevice in the pipeline.
#. The kernel adjusts the format, and media-ctl automatically propagates it
   over the link to the connected sink pad of the next subdevice.
#. If the next subdevice has crop or compose rectangleon its sink or source
   pads, sets them as necessary, in the following order:

   - Sink crop
   - Sink compose
   - Source crop

#. The kernel automatically propagates the format to the source pad of the
   subdevice, adjusting it if needed.
#. Retrieve the propagated format on the source pad of the subdevice, modify it
   if required (for instance to configure scaling), and set of on the same
   source pad to let media-ctl propagate it across the next link.
#. Repeat this procedure from subdevice to subdevice, until the last subdevice
   in the pipeline is reached.

After configuring the pipeline, frames can be captured from the video device at
the pipeline output with the classic V4L2 API, in a pixel format and resolution
that matches the pipeline configuration.