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
|
Config file format
==================
Libmegapixels gets its camera pipeline definitions from config files stored in one of the config directories.
For finding config files libmegapixels will scan a few preconfigured path from the "compatible" names of the device.
The first part of this puzzle is the compatible names, these can be found at runtime from
the :code:`/proc/device-tree/compatible` file or otherwise from the top-most "compatible" node in the device tree.
As an example the Xiaomi Mi Note 2 will be used. The compatible list for the device tree for this device is at
https://github.com/torvalds/linux/blob/b85ea95d086471afb4ad062012a4d73cd328fa86/arch/arm64/boot/dts/qcom/msm8996pro-xiaomi-scorpio.dts#L17
The relevant line here is this:
.. code-block:: device-tree
compatible = "xiaomi,scorpio", "qcom,msm8996pro", "qcom,msm8996";
The second part is the lookup paths. They are checked in this order:
* :code:`config/$model.conf` in the current working directory
* :code:`/etc/megapixels/config/$model.conf`
* :code:`/usr/share/megapixels/config/$model.conf`
So on this device the file will be looked up in this order:
* :code:`config/xiaomi,scorpio.conf`
* :code:`/etc/megapixels/config/xiaomi,scorpio.conf`
* :code:`/usr/share/megapixels/config/xiaomi,scorpio.conf`
* :code:`config/qcom,msm8996pro.conf`
* :code:`/etc/megapixels/config/qcom,msm8996pro.conf`
* :code:`/usr/share/megapixels/config/qcom,msm8996pro.conf`
* :code:`config/qcom,msm8996.conf`
* :code:`/etc/megapixels/config/qcom,msm8996.conf`
* :code:`/usr/share/megapixels/config/qcom,msm8996.conf`
The first matched file will be used.
The file format
---------------
The config files are parsed by `libconfig <https://hyperrealm.github.io/libconfig/libconfig_manual.html#Configuration-Files>`_
and define all the cameras present on the specific device and the modes that are possible on this hardware.
An example of a minimal config is this:
.. code-block:: config
Version = 1;
Make: "Xiaomi";
Model: "Scorpio";
Rear: {
SensorDriver: "imx318";
BridgeDriver: "qcom-camss";
Modes: (
{
Width: 3840;
Height: 2160;
Rate: 30;
Format: "RGGB10";
Rotate: 90;
Pipeline: (
{Type: "Link", From: "imx318", FromPad: 0, To: "msm_csiphy0", ToPad: 0},
{Type: "Link", From: "msm_csiphy0", FromPad: 1, To: "msm_csid0", ToPad: 0},
{Type: "Link", From: "msm_csid0", FromPad: 1, To: "msm_ispif0", ToPad: 0},
{Type: "Link", From: "msm_ispif0", FromPad: 1, To: "msm_vfe0_rdi0", ToPad: 0},
{Type: "Mode", Entity: "imx318"},
{Type: "Mode", Entity: "msm_csiphy0"},
{Type: "Mode", Entity: "msm_csid0"},
{Type: "Mode", Entity: "msm_ispif0"},
);
},
);
};
The only top-level keys are Version, Make and Model. The Version should always be 1 and is reserved for possible future
breaking updates.
The Make and Model keys set the human-readable name for the device which will be written in the EXIF data of pictures as
he camera model.
Camera definitions
------------------
All the other top-level keys in the config file are definitions for cameras. The name is not very important and is for
documentation purposes.
The keys in the camera block are:
* :code:`BridgeDriver`: The name of the driver that provides the /dev/media and /dev/video node for this camera
* :code:`SensorDriver`: The name of the sensor entity in the media graph
* :code:`FlashPath`: optional, defines the path to a LED device to use as the flash for this camera.
* :code:`FlashDisplay`: optional, defines that there is no LED that can be used as flash, use the display as the
light-source instead.
The camera section requires a :code:`SensorDriver` and :code:`BridgeDriver` key. The BridgeDriver will identify the bridge device (eg.
/dev/video0) and media device (eg. /dev/media0). This combination should uniquely identify a single camera on the device.
These values can be found using the :code:`media-ctl` utility.
.. code-block:: shell-session
$ media-ctl --device 0 --print-topology
Media controller API version 6.1.14
Media device information
------------------------
driver qcom-camss
model Qualcomm Camera Subsystem
serial
bus info platform:a34000.camss
hw revision 0x0
driver version 6.1.14
Device topology
- entity 1: msm_csiphy0 (2 pads, 5 links)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev0
pad0: Sink
[fmt:UYVY8_2X8/1920x1080 field:none colorspace:srgb]
<- "imx318 3-001a":0 [ENABLED,IMMUTABLE]
pad1: Source
[fmt:UYVY8_2X8/1920x1080 field:none colorspace:srgb]
-> "msm_csid0":0 []
-> "msm_csid1":0 []
-> "msm_csid2":0 []
-> "msm_csid3":0 []
[ Removed A LOT of entities here for brevity ]
- entity 226: imx318 3-001a (1 pad, 1 link)
type V4L2 subdev subtype Sensor flags 0
device node name /dev/v4l-subdev19
pad0: Source
[fmt:SRGGB10_1X10/5488x4112@1/30 field:none colorspace:raw xfer:none]
-> "msm_csiphy0":0 [ENABLED,IMMUTABLE]
- entity 228: ak7375 3-000c (0 pad, 0 link)
type V4L2 subdev subtype Lens flags 0
device node name /dev/v4l-subdev20
The BridgeDriver config node needs to match the driver listed at the top of the output. In this case :code:`qcom-camss`.
For the SensorDriver the entity needs to be found that represents the sensor. This is mentioned as
:code:`subtype Sensor` in the list and in the example is entity 226. The entity will be matched by the name listed
directly after the number which is :code:`imx318 3-001a`. The full name doesn't need to be used but is matched by prefix
to avoid the config needing to hardcode the i2c bus number for the sensor which might change on enabling/disabling
kernel modules.
Camera modes
------------
Every camera block requires to have at least one mode block but can have multiple. This is required since different
usecases of the camera need different modes. Usually the maximum resolution of the sensor will be used for taking
pictures but at that resolution the framerate will generally be too low for realtime preview.
For example the OV5640 sensor can run at 2592x1944 resolution for decently sharp pictures, but at that resolution is
limited to 15fps which will be quite annoying for the live-preview and not fast enough for smooth video recording. This
is why the PinePhone defines a 2592x1944@15fps mode and a 1280x720@30fps mode for the preview. The Megapixels application
will default to the highest defined resolution for taking pictures and will take the resolution closest to the display
resolution as the preview mode.
The required configuration keys for the mode are:
* :code:`Width` and :code:`Height` for the resolution of image _after_ any processing by the ISP.
* :code:`Rate` the frame interval in frames-per-second for this mode.
* :code:`Format` is the pixelformat for the data after ISP processing.
The optional keys are:
* :code:`Transfer` sets the transfer curve of the image data, can be "srgb" or "raw".
* :code:`Rotate` defines the rotation for matching up the orientation of the sensor and the display of the device.
* :code:`Mirror` can be set to :code:`true` to flip the image for the front-facing sensors.
* :code:`FocalLength` sets the effective focal length of the camera in this mode. Sensors generally crop the image
slightly depending on the resolution which changes the focal length for the mode. This is only used for EXIF metadata
and is defined in milimeters.
* :code:`FNumber` sets the aperture size of the lens. 3.0 will mean F/3 as aperture size, this is only used for EXIF
Mode pipeline
-------------
To make the mode actually work the pipeline has to be added. This is a small script that defines the ioctls that need to
be sent to the drivers to set up all the hardware in this mode. This is a full scripting system to deal with
inconsistencies in the Linux drivers, especially the staging drivers for sensors.
The pipeline script is a list of command objects. The specific command is set using the :code:`Type` key in this object.
All other keys in the command object depend on the specific command.
The possible commands are:
* `Link`_
* `Mode`_
* `Rate`_
* `Crop`_
The commands all accept the name of an entity from MediaCtl and these are prefix matched by default. This is because
for things like sensors there might be an i2c bus ID in the name of the entity and the bus ID is not stable across
reboots and kernel changes. There is one case though where the prefix match doesn't work when the name of one entity
is the exact prefix of one with a longer name. For this case prefix matching can be disabled with the `ExactName`
key in every command.
Cascading values
^^^^^^^^^^^^^^^^
In order to not repeat the values for resolutions, formats and framerates in every command values are cascaded
internally if nothing is specified. These cascading values are initialized to the resolution and mode for the Mode
block that contains this pipeline. If any command in the pipeline hardcodes another value then that new default will
also be used for the following commands. This means that if the pipeline script is defined in strict source->sink order
the minimum amount of repetitions of these values are required.
For example this pipeline:
.. code-block:: config
Modes: (
{
Width: 4208;
Height: 3120;
Rate: 30;
Format: "RGGB8";
Pipeline: (
{Type: "Mode", Entity: "imx258", Format: "RGGB10P"},
{Type: "Mode", Entity: "rkisp1_csi"},
{Type: "Mode", Entity: "rkisp1_isp"},
{Type: "Mode", Entity: "rkisp1_isp", Pad: 2, Format: "RGGB8"},
{Type: "Crop", Entity: "rkisp1_isp"},
{Type: "Crop", Entity: "rkisp1_isp", Pad: 2},
{Type: "Mode", Entity: "rkisp1_resizer_mainpath"},
{Type: "Mode", Entity: "rkisp1_resizer_mainpath", Pad: 1}
);
},
The resolution and framerate is never defined in any of the pipeline commands and are inherited from the values set in
the mode. The pixelformat is specified twice here since the ISP will convert between RGGB10P and RGGB8 formats. Once to
set the format of the sensor and once on the ISP to return it to the value of the Mode block.
This pipeline will be interpreted as:
.. code-block:: config
{Type: "Mode", Entity: "imx258", Width: 4208, Height: 3120, Format: "RGGB10P"},
{Type: "Mode", Entity: "rkisp1_csi", Width: 4208, Height: 3120, Format: "RGGB10P"},
{Type: "Mode", Entity: "rkisp1_isp", Width: 4208, Height: 3120, Format: "RGGB10P"},
{Type: "Mode", Entity: "rkisp1_isp", Pad: 2, Width: 4208, Height: 3120, Format: "RGGB8"},
{Type: "Crop", Entity: "rkisp1_isp", Width: 4208, Height: 3120, Top: 0, Left: 0},
{Type: "Crop", Entity: "rkisp1_isp", Pad: 2, , Width: 4208, Height: 3120, Top: 0, Left: 0},
{Type: "Mode", Entity: "rkisp1_resizer_mainpath", Width: 4208, Height: 3120, Format: "RGGB8"},
{Type: "Mode", Entity: "rkisp1_resizer_mainpath", Pad: 1, Width: 4208, Height: 3120, Format: "RGGB8"}
Link
^^^^
The Link command is the most important one, this defines the media pipeline itself by specifying which links should be
created and broken. This is equivalent to the :code:`MEDIA_IOC_SETUP_LINK` ioctl.
Parameters:
* :code:`From` source entity name
* :code:`To` sink entity name
* :code:`FromPad` pad index on the source entity
* :code:`ToPad` pad index on the sink entity
* :code:`ExactName` match the exact From/To names instead of just a prefix.
Example:
.. code-block:: config
{Type: "Link", From: "ov5640", FromPad: 0, To: "sun6i-csi-bridge", ToPad: 0},
Is equivalent to:
.. code-block:: shell-session
$ media-ctl -l "'ov5640':0 -> 'sun6i-csi-bridge':0 [1]"
Mode
^^^^
The mode sets the V4L2 format on the entity pad, some drivers in V4L2 will cascade these values down the pipeline and
some will need the mode to be set on every entity in the pipeline to make the pipeline start streaming correctly.
The most minimal option is specifying just the entity name here and the rest of the values are used from the resolution
and format specified in the mode block this pipeline is in, or the values of the previous Mode command if one hardcodes
a value. This is for pipelines where an ISP changes the format or resolution halfway through the pipeline.
This command is equivalent to the :code:`VIDIOC_SUBDEV_S_FMT` ioctl.
Parameters:
* :code:`Entity` media entity to set the mode on
* :code:`Pad` pad index on the entity, defaults to 0
* :code:`Width` Resolution width, if not specified it will use value of the previous command
* :code:`Height` Resolution width, if not specified it will use value of the previous command
* :code:`Format` Pixelformat for the mode, if not specified it will use the value of the previous command
* :code:`SkipTry` disables the use of the VIDIOC_SUBDEV_S_FMT ioctl with V4L2_SUBDEV_FORMAT_TRY. This is for drivers
that don't implement the V4L2_SUBDEV_FORMAT_TRY functionality or where it returns the wrong data.
* :code:`ExactName` match the exact Entity name instead of just a prefix.
Example:
.. code-block:: config
{Type: "Mode", Entity: "ov5640", Pad: 0, Width: 640, Height: 480, Format: "BGGR8"},
{Type: "Mode", Entity: "sun6i-csi-bridge"},
Is equivalent to:
.. code-block:: shell-session
$ media-ctl --set-v4l2 '"ov5640":0 [fmt:SBBGR8_1X8/640x480]'
$ media-ctl --set-v4l2 '"sun6i-csi-bridge":0 [fmt:SBBGR8_1X8/640x480]'
Rate
^^^^
The mode sets the framerate on the entity for the drivers that believe in such things, some drivers will require this
to be set and some will reject this ioctl altogether.
Just like the Mode command the rate value will cascade from the rate specified in the Mode block that contains this
pipeline and previous Rate calls that changes the pipeline framerate.
This command is equivalent to the :code:`VIDIOC_SUBDEV_S_FRAME_INTERVAL` ioctl.
Parameters:
* :code:`Entity` media entity to set the mode on
* :code:`Rate` frame interval, if not specified it will use value of the previous command
* :code:`ExactName` match the exact Entity name instead of just a prefix.
Example:
.. code-block:: config
{Type: "Rate", Entity: "ov5640", Rate: 30},
Is equivalent to:
.. code-block:: shell-session
// Only the @30 part here is relevant
$ media-ctl --set-v4l2 '"ov5640":0 [fmt:SBBGR8_1X8/640x480@30]'
Crop
^^^^
Some drivers will allow cropping out a section of the frame, usually this is to remove dummy pixels from the edge of the
sensor. Some drivers will internally set the cropping automatically when setting the capture resolution and some will
fail to start until you specify the cropping to be 0 on all edges instead of having that as default. There are also
drivers that don't update the crop values when changing resolution so the crop ioctl needs to be called.
This command is equivalent to the :code:`VIDIOC_SUBDEV_S_CROP` ioctl.
Parameters:
* :code:`Entity` media entity to set the crop on
* :code:`Pad` pad index on the entity, defaults to 0
* :code:`Width` Crop width, if not specified it will use the mode width
* :code:`Height` Crop height, if not specified it will use the mode height
* :code:`Top` Top offset of the cropped region, defaults to 0
* :code:`Left` Left offset of the cropped region, defaults to 0
* :code:`ExactName` match the exact Entity name instead of just a prefix.
Example:
.. code-block:: config
{Type: "Crop", Entity: "rkisp1_isp", Width: 640, Height: 480, Top: 0, Left: 0},
Is equivalent to:
.. code-block:: shell-session
// Only the last crop: part here is relevant
$ media-ctl --set-v4l2 '"rkisp1_isp":0 [fmt:SBBGR8_1X8/640x480 crop:(0,0)/640x480]'
|