go4vl: Cannot retrieve pixel format info from device [Error While Encoding v4l2 command via ioctl]

Error

device.GetPixFormat() always fails with error device: pix format failed: unsupported error if we do a system call trace i get following

ioctl(3, _IOC(_IOC_READ|_IOC_WRITE, 0x56, 0x4, 0xcc), 0xc000076ca8) = -1 ENOTTY (Inappropriate ioctl for device)
write(1, "failed to get pix format\n", 25failed to get pix format

It looks like encoded command is not VIDIOC_G_FMT and is not recognized by kernel.

package main

import (
	"fmt"

	"github.com/vladimirvivien/go4vl/v4l2"
)

func main() {
	device, err := v4l2.Open("/dev/video0")
	if err != nil {
		panic(err)
	}

	_, err = device.GetPixFormat()
	if err != nil {
		fmt.Println("failed to get pix format")
		panic(err)
	}
}

My kernel is

Linux endless 5.14.14-arch1-1 #1 SMP PREEMPT Wed, 20 Oct 2021 21:35:18 +0000 x86_64 GNU/Linux

Cause

I don’t think this problem is caused by kernel. I can use <linux/videodev2.h> and it does not cause this error

With the C API I get

ioctl(3, VIDIOC_G_FMT, {type=V4L2_BUF_TYPE_VIDEO_CAPTURE, fmt.pix={width=1280, height=720, pixelformat=v4l2_fourcc('M', 'J', 'P', 'G') /* V4L2_PIX_FMT_MJPEG */, field=V4L2_FIELD_NONE, bytesperline=0, sizeimage=1843200, colorspace=V4L2_COLORSPACE_SRGB}}) = 0

It looks like the problem is caused in ioctl encoding functions. I rechecked the ioct.go but could not find the problem

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 1
  • Comments: 22 (8 by maintainers)

Most upvoted comments

There is no missing struct member. The problem is go compiler sometimes treats alignment differently depending on arc targeted. I ran into that issue (cant remember where) in other part of the code and it’s tricky. I will reboot the project this weekend to investigate how this can be fixed once and for all.

is short of 4 bytes . It looks like this missing 4 bytes are causing above discussed errors. It looks like a field (possibly __u32 which is of size 4 bytes) is missing in golang implementation of v4l2_format

I think it would be great if we can add some unit testing to important parts of project like (ioctl commands , structs etc) , this would help the project to avoid future errors and keep up the standards with v4l2 api. Also the unit testing should use cgo , something similar to above program . I intend to use this project for my upcoming projects , let me know if I can help speed up the process

@EtienneBruines @vladimirvivien Of all implementations of V4l2, this is my favorite. It is more simple, readable, and has more functions implemented. It would be great if we can overcome this issue

@EtienneBruines that is great!!! This confirms that cgo works (better than crafting Go types manually for C counter parts). So this means I will do a refactor of current code to integrate cgo-generated types.

Again, thank you considering using this code.

@vladimirvivien I played around with it a little bit, and it seems to have done wonders!

I was able to setFormat and then verify the settings using getFormat reliably now. 🎉

@tarunKoyalwar that snippet is really helpful! (Especially with debugging)

From the looks of it (earlier on), those 4 bytes seem to be in between the StreamType and the fmt [200]byte - possibly to help define which of the union types it is.

@vladimirvivien @EtienneBruines I believe following data would help.

package main

/*
#include <linux/videodev2.h>
#include <stdio.h>

struct v4l2_format fmt;

int mains(){
    printf("Size of v4l2_format(official) struct in c is %d\n",sizeof(fmt));
    return 0;
}
*/
import "C"
import (
	"fmt"
	"unsafe"
)

type v4l2Format struct {
	StreamType uint32
	fmt        [200]byte
}

func main() {
	// type C.v4l2_format
	var vformat v4l2Format
	C.mains()
	fmt.Printf("Size of v4l2_struct(official) in golang is %v\n", unsafe.Sizeof(C.fmt))
	fmt.Printf("Size of golang defined v4l2format struct in golang is %v\n", unsafe.Sizeof(vformat))
}

This program returns Screenshot_10

It looks like the v4l2format defined here(https://github.com/vladimirvivien/go4vl/blob/aab6d9c4a2496f2e9bc90c2763e94eba389bde9d/v4l2/format.go#L289)

is short of 4 bytes . It looks like this missing 4 bytes are causing above discussed errors. It looks like a field (possibly __u32 which is of size 4 bytes) is missing in golang implementation of v4l2_format

@EtienneBruines @tarunKoyalwar Apologies for late reply, I have been on vacation and got busy at work.

This is an awesome thread and appreciate all the great information/comments you both have provided. But, I must start my reply with the following disclaimers:

  • This is a highly early and alpha Go project with great aspiration, but it’s not there yet.
  • All code have been tested solely on Linux running on a Raspberry pi 3 with latest Kernel release
  • I have been able to successfully create a webcam using the code, the Pi, and a webcam

So as you can see this is pretty early stuff. Having said all of that, I welcome your great feedback and will be investigating this issue this week. My lofty aspiration for this project is to provide a great idiomatic Go experience using the API without cgo. However, I havent used it in enough cases to know if that’s a possibility.

I will spend time on this issue to see if it’s something that can be quickly resolved or need to completely change direction of the project (using cgo).

Thanks.

@vladimirvivien any comment about this issue would be great !

I am actually working on a generalized pam module with face auth . I intended to use this package for webcam . But it doesnot seem stable right now.

It looks like only stable way to get all features of webcam in linux is to use cgo

The only idea I think now is implement all logic in c and just get buffers using cgo