The V4L2 media-ctl toolkit, or simply mctk, is a collection of routines to capture, manipulate, and restore the state of a Video4Linux2 “media controller” and all of its related devices, within the framework/API of V4L2.
By design, the tool works primarily on an in-memory representation of a tree of a media-ctl device and its subnodes, hereforth called a “model”. Secondarily, it may also send any changes to this model back to real devices, accessible via /dev/*.
There is always only one “active” media-ctl tree/model being updated/worked on.
Whether updates are sent to the kernel depends on the origin of the active model:
If the model was loaded from a real /dev/mediaX device, then the tool will keep all its file descriptors to the associated devices open, and changes to the model will be propagated to the kernel.
NOTE: The tool does not refresh its model with new kernel values after setting a value in the kernel. That is, an *_S_* ioctl() is NOT followed by one or more *_G_* ioctl()s. It is up to the user to know about any intricacies of the V4L2 device being manipulated.
If the model was loaded from a dump file, then any changes will be reflected only in memory.
In both cases, the final state of the memory model can be dumped to a new file.
The parameters to this toolkit are processed sequentially, in the order they are given on the command line. In effect, they form a “script” to be executed.
The idea is that # ./mctk --action1 paramX --action2 --action3 paramY
will first do action 1 with parameter X, then action 2 which does not take a parameter, and finally action 3, which takes parameter Y.
A load action is always the first.
It opens either a kernel device or a dump file, and creates an in-memory model of a media-ctl device. All further operations will be executed on this in-memory model.
If the model has been loaded from a kernel device, then actions will ALSO be fed back to the kernel, via appropriate ioctl()s.
If the model has been loaded from a file, then that file will not be modified. Please use the dump action to write the modified state to a new file.
If a new load action follows a previous one, then the tool will abort.
The following command opens a real media-ctl device for processing, and then quits without performing any action on it:
# ./mctk --load-device /dev/media0
The following command does the same, but takes a bus_info string instead. The tool will iterate over all /dev/media* devices until it finds one with the given bus_info string in its struct media_device_info.
# ./mctk --load-by-businfo usb-0000:04:00.3-1
The following command opens a virtual media-ctl device from a YAML dump, and then quits without performing any action on the resulting model:
# ./mctk --load-yaml dump.yaml
Internally known as “Tool-1”.
The currently active model is serialised to a file.
The following command line prints a YAML formatted dump of /dev/media0 and its child nodes to stdout:
# ./mctk --load-device /dev/media0 --dump-yaml /proc/self/fd/1
Internally known as “Tool-3”.
A (part of a) serialised state is read and applied to the currently active in-memory model. If the active model is a kernel device, then the configuration is also sent to the hardware (minus quirks in the driver/hardware that make the restoration work less than 100% - it is up to the user to know these details).
If the input file to the merge action contains a remap section, then the entities to be modified in the active model are identified by names rather than by entity ID number.
The following command line opens a real media-ctl device, disables all links where possible, and then applies a configuration from a YAML file:
# ./mctk --load-device /dev/media0 --reset-links --merge-yaml config.yaml
During a merge, it is assumed that the entities, pads, links, properties, controls, etc. being configured actually exist in the target, and that the identifiers (id, name, index, etc.) refer to the same things as when the configuration file was created.
For example, if “CSI 0” and “CSI 1” refer to the front and back camera, respectively, and then a driver update swaps these two numbers, then the tool will be unable to detect this, and blindly attempt to apply one camera's configuration to the other.
It is ultimately up to the user to ensure that the intended semantics of a configuration file match the device being configured.
In addition to the media_ctl node, configuration files to be merged may contain a remap_entity_by_name node.
This node lists tuples of numerical entity IDs, and for each an associated entity name, and/or a regular expression to match an entity name.
For example:
remap_entity_by_name: - id: 8 name: Extension 3 - id: 11 name: Processing 2 - id: 14 name: Camera 1
When merging, configuration changes mentioning any entity ID that is listed in remap_entity_by_name will instead apply to an entity with the name mentioned in remap_entity_by_name. In the above example, any mention of entity ID 8, be it in V4L properties or in links, will be replaced with the ID of an entity in the target that has the name Extension 3.
In some media-ctl targets, entity names may change slightly between reboots or kernel updates. In this case, config files may be manually extended by a regular expression to match the entity name:
remap_entity_by_name: - id: 11 name_regex: Processing [0-9]
In this case, a target node called “Processing X”, where X is a single digit, will be used as a substitute for ID 11.
If a remap entry contains both a name and a name_regex, mctk will attempt to match by exact name first, and by name_regex second.
A remap entry with neither a name or a name_regex is invalid and mctk will abort.
If an entity ID is mentioned in the remap table, then the remapping must succeed. For example, if ID 11 is remapped to the name Processing 2, then the target media-ctl MUST contain an entity named Processing 2. There is no fall-back to applying the changes to entity 11, that is, matching by ID, once an entity is listed in the remap table.
If e.g. a control being configured is absent, then the tool may either skip updating the control in question, or abort.
If e.g. an integer control is to be assigned a string, then the tool may either skip updating the parameter in question, or abort.
But if there has simply been a reordering between otherwise identical entities, and both have the same controls, then the tool cannot detect this and will blindly update the controls.
V4L2 drivers are not configured atomically. Changing one value can result in a driver updating other values, too.
The tool will blindly configure parameters in the order in which they are listed in the configuration file. If the V4L2 device is not in the desired state afterwards, then a deeper understanding of the driver is needed, and a manual reordering of configuration steps is required.
To this end, an entity may be named multiple times in a configuration file, allowing parameters to be set in a specific order (and even multiple times).
NOTE: Unfinished old code and outdated documentation!
This tool attempts to detect sensors and route them to viable outputs on the specified V4L media controller device.
# ./mctk --load-device /dev/media0 --reset-links --auto-route Resetting links. Autorouting sensors. SetSelection: ioctl(VIDIOC_SUBDEV_S_SELECTION): Inappropriate ioctl for device SetSelection: ioctl(VIDIOC_SUBDEV_S_SELECTION): Inappropriate ioctl for device SetSelection: ioctl(VIDIOC_SUBDEV_S_SELECTION): Inappropriate ioctl for device SetSelection: ioctl(VIDIOC_SUBDEV_S_SELECTION): Invalid argument SetFmtVideoCapture: ioctl(VIDIOC_S_FMT): Invalid argument SetSelection: ioctl(VIDIOC_S_SELECTION): Inappropriate ioctl for device Routed: /dev/video8 = ov8856 13-0036 # yavta -c /dev/video8 [ ... capture follows ... ]
NOTE: The above error messages are benign - the autorouter attempts to set properties, whether they are supported or not.
The tool requests the entire topology of entities and links exposed by the media controller via MEDIA_IOC_ENUM_ENTITIES and MEDIA_IOC_ENUM_LINKS.
It disables all links between entities.
It picks the entities marked as MEDIA_ENT_T_V4L2_SUBDEV_SENSOR, and for each one, tries to find a path from one of their output pads to a /dev/videoX device.
It recurses through the tree of links in a DFS fashion, writing down a path successfully found.
If a device name matches one of a few known patterns, it is ignored as a routing hop - see v4l_mc_hack_is_ipu6_ignored_entity().
It enables the links along each path found.
It reads the sensor's picture format, and attempts to set the same format on each device along the path.
For the final V4L /dev/videoX device, it takes a guess at the format, but only Bayer raw formats are currently translated.
It also sets each V4L selection, using two strategies (to allow for drivers that support one or the other).
It disables IPU6 image compression on any /dev/videoX device enabled in this process, in case it supports this feature.
Units that are already connected to something are ignored in any further routing. That is, if there are multiple sensors, then multiple paths will be generated, but they will never cross by using an entity twice.
It is assumed that DFS routing can result in valid paths for all sensors. If sensor 0 can only be assigned to outputs {0,1} and sensor 1 can only be assigned to output 0, then routing the second sensor will fail because its only viable output will already be in use by sensor 0.
This program is written with the assumption that it is run single-threaded.