V4L2 H.264 encoder uses a different /dev/videoX interface upon reboot

It seems that upon every reboot of the DB410c the video pipelines must be configured with media-ctl to re-enable the use of the codec. When the user runs the media-ctl commands for video encoder support, the interfaces for the hardware codec seem to move between /dev/video4 and /dev/video5.

It almost seems like the encoder and decoder swap their interfaces in an unpredictable way each time the video pipeline is initialized.

Is there a way to commit these pipelines in a way that they persist across multiple restarts?
Can I specify what interface the encoder and decoder uses so that they stay static and do not move around upon restart?

hi,

no, it is not possible to control how the numbers are allocated, they are assigned by the kernel as devices are processed during the boot.

it might be possible to write some udev rules to create symlink for decoder and encode, though, but i have not tried…

Hmm, so something like this would probably do the trick:
Device Filenames and udev Examples from MythTV

I’m going to run through the udev parts of this guide and see what happens. I’ll report back here with my results.

yes, this is exactly what I was thinking about!

I gave it a shot with this new udev rule created in /etc/udev/rules.d/10.qcom.rules:
KERNEL==“video?”,SUBSYSTEM=“video4linux”,ATTRS={index}==0,SYMLINK+=“qcom-video-encoder”

It seems not to want to create the new device symlink called qcom-video-encoder. I think that it might be easier if the kernel filled in the name attribute for the video codec it might make things a little easier to match.

If you’re interested, here’s the output from udevadm info -a -p $(udevadm info -q path -n /dev/video4):
looking at device ‘/devices/platform/soc/1d00000.video-codec/video4linux/video4’:
KERNEL==“video4”
SUBSYSTEM==“video4linux”
DRIVER==""
ATTR{dev_debug}==“0”
ATTR{index}==“0”
ATTR{name}==""

looking at parent device ‘/devices/platform/soc/1d00000.video-codec’:
KERNELS==“1d00000.video-codec”
SUBSYSTEMS==“platform”
DRIVERS==“qcom-venus”
ATTRS{driver_override}=="(null)"

looking at parent device ‘/devices/platform/soc’:
KERNELS==“soc”
SUBSYSTEMS==“platform”
DRIVERS==""
ATTRS{driver_override}=="(null)"

looking at parent device ‘/devices/platform’:
KERNELS==“platform”
SUBSYSTEMS==""
DRIVERS==""

so, it looks like udev does not have enough information to decide if it is the decoder or the encoder… so this method won’t work as we thought…

you can use v4l2-ctl to check the capabilities of the /dev/video* and find who is who at boot time.

So, out of interest…

Why do the venus drivers use different names for the driver depending on whether they are telling platform bus (“qcom-venus-decoder”) or V4L2 (“qcom-venus”)?

Obviously I’m only asking because it we used the platform bus names for V4L2 then we’d be able to use udev as expected.

Obviously I’m only asking because it we used the platform bus names for V4L2 then we’d be able to use udev as expected.

Let me add an “I think” in this sentence (I didn’t spot the extra instance of qcom-venus in the core of the driver)…

Taking several steps back… the reason I was interested in this problem is because my gst-launch-1.0 commands are unreliable (sometimes the decoder is called v4l2video0dec and sometimes it is v4l2video1dec) which makes it hard to share them as examples.

I guess I should start expressing gst-launch command lines with a backquoted gst-inspect to ensure we find a video decoder?

Could you try following diff, it should fill ATTR{name}==“qcom-venus-encoder”.

diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index d76e7957be1d…ef19602ed0db 100644
— a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -1075,6 +1075,7 @@ static int vdec_probe(struct platform_device *pdev)
vdev->vfl_dir = VFL_DIR_M2M;
vdev->v4l2_dev = &core->v4l2_dev;
vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;

  •   strlcpy(vdev->name, "qcom-venus-decoder", sizeof(vdev->name));
    
      ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
      if (ret)
    

diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index 39748e7a08e4…d0907b3b06b6 100644
— a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -1196,6 +1196,7 @@ static int venc_probe(struct platform_device *pdev)
vdev->vfl_dir = VFL_DIR_M2M;
vdev->v4l2_dev = &core->v4l2_dev;
vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;

  •   strlcpy(vdev->name, "qcom-venus-encoder", sizeof(vdev->name));
    
      ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
      if (ret)

Due to formatting issues I couldn’t run your patches automatically, but when I added the new lines to the venc/vdec.c files and recompiled the modules I was then able to see that the name attribute has been added.

With the patch that svarbanov provided this rule adds a new symlink in the /dev folder for venusEnc:
KERNEL==“video[0-9]*”, SUBSYSTEM==“video4linux”, ATTR{name}==“qcom-venus-encoder”, SYMLINK+=“venusEnc”

Now I think I’m at the point where I need to start looking into how gstreamer points to the video interfaces so that it can use the new symlink created with udev rules.

Sorry for formatting issues, that was ugly but I realized it after post the reply.

If I remember correctly the gstreamer calls enum_fmt in order to distinguish between decoder and encoder.