浏览代码

Support for v4l2_fmtdesc

Vladimir Vivien 4 年之前
父节点
当前提交
591509c891
共有 3 个文件被更改,包括 114 次插入3 次删除
  1. 8 3
      v4l2/format.go
  2. 105 0
      v4l2/format_desc.go
  3. 1 0
      v4l2/ioctl.go

+ 8 - 3
v4l2/format.go

@@ -6,6 +6,9 @@ import (
 	"unsafe"
 )
 
+// FourCCEncoding represents the four character encoding value
+type FourCCEncoding = uint32
+
 // Some Predefined pixel format definitions
 // https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/pixfmt.html
 // https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L518
@@ -28,7 +31,7 @@ var (
 // https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L81
 // #define v4l2_fourcc(a, b, c, d)\
 // 	 ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24))
-func fourcc(a, b, c, d uint32) uint32 {
+func fourcc(a, b, c, d uint32) FourCCEncoding {
 	return (a | b<<8) | c<<16 | d<<24
 }
 
@@ -96,8 +99,8 @@ const (
 type PixFormat struct {
 	Width        uint32
 	Height       uint32
-	PixelFormat  uint32
-	Field        uint32
+	PixelFormat  FourCCEncoding
+	Field        Field
 	BytesPerLine uint32
 	SizeImage    uint32
 	Colorspace   uint32
@@ -132,11 +135,13 @@ type v4l2Format struct {
 	fmt        [200]byte
 }
 
+// getPixFormat returns the PixFormat by casting the pointer to the union type
 func (f v4l2Format) getPixFormat() PixFormat {
 	pixfmt := (*PixFormat)(unsafe.Pointer(&f.fmt[0]))
 	return *pixfmt
 }
 
+// setPixFormat sets the PixFormat by casting the pointer to the fmt union and set its value
 func (f v4l2Format) setPixFormat(newPix PixFormat) {
 	*(*PixFormat)(unsafe.Pointer(&f.fmt[0])) = newPix
 }

+ 105 - 0
v4l2/format_desc.go

@@ -0,0 +1,105 @@
+package v4l2
+
+import (
+	"errors"
+	"fmt"
+	"unsafe"
+)
+
+// FmtDescFlag image format description flags
+// https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L794
+// https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/vidioc-enum-fmt.html#fmtdesc-flags
+type FmtDescFlag = uint32
+
+const (
+	FmtDescFlagCompressed           FmtDescFlag = 0x0001                 // V4L2_FMT_FLAG_COMPRESSED
+	FmtDescFlagEmulated             FmtDescFlag = 0x0002                 // V4L2_FMT_FLAG_EMULATED
+	FmtDescFlagContinuousBytestream FmtDescFlag = 0x0004                 // V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM
+	FmtDescFlagDynResolution        FmtDescFlag = 0x0008                 // V4L2_FMT_FLAG_DYN_RESOLUTION
+	FmtDescFlagEncCapFrameInterval  FmtDescFlag = 0x0010                 //  V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL
+	FmtDescFlagCscColorspace        FmtDescFlag = 0x0020                 //  V4L2_FMT_FLAG_CSC_COLORSPACE
+	FmtDescFlagCscXferFunc          FmtDescFlag = 0x0040                 // V4L2_FMT_FLAG_CSC_XFER_FUNC
+	FmtDescFlagCscYcbcrEnc          FmtDescFlag = 0x0080                 //  V4L2_FMT_FLAG_CSC_YCBCR_ENC
+	FmtDescFlagCscHsvEnc            FmtDescFlag = FmtDescFlagCscYcbcrEnc // V4L2_FMT_FLAG_CSC_HSV_ENC
+	FmtDescFlagCscQuantization      FmtDescFlag = 0x0100                 // V4L2_FMT_FLAG_CSC_QUANTIZATION
+)
+
+// v4l2FormatDesc  (v4l2_fmtdesc)
+// https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L784
+// https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/vidioc-enum-fmt.html
+type v4l2FormatDesc struct {
+	index       uint32  // format number
+	bufType     BufType // stream type BufType
+	flags       FmtDescFlag
+	description [32]uint8      // string description
+	pixelFormat FourCCEncoding // Format fourcc value
+	mbusCode    uint32         // media bus code
+	reserved    [3]uint32
+}
+
+// FormatDescription provides access to the device format description
+// See v4l2FormatDesc
+type FormatDescription struct {
+	v4l2FormatDesc
+}
+
+// GetIndex returns the format number
+func (d FormatDescription) GetIndex() uint32 {
+	return d.index
+}
+
+// GetBufType returns the type for the buffer (see v4l2_buf_type)
+func (d FormatDescription) GetBufType() BufType {
+	return d.bufType
+}
+
+// GetFlags returns image description flags (see FmtDescFlag)
+func (d FormatDescription) GetFlags() FmtDescFlag {
+	return d.flags
+}
+
+// GetDescription returns a string value for the format description
+func (d FormatDescription) GetDescription() string {
+	return toGoString(d.description[:])
+}
+
+// GetPixelFormat returns the four character encoding for the format
+func (d FormatDescription) GetPixelFormat() FourCCEncoding {
+	return d.pixelFormat
+}
+
+// GetBusCode returns the media bus code for drivers that advertise v4l2_cap_io_mc
+func (d FormatDescription) GetBusCode() uint32 {
+	return d.mbusCode
+}
+
+// GetFormatDescription returns a device format description at index
+func GetFormatDescription(fd uintptr, index uint32) (FormatDescription, error) {
+	desc := v4l2FormatDesc{index: index, bufType: BufTypeVideoCapture}
+	if err := Send(fd, VidiocGetFormat, uintptr(unsafe.Pointer(&desc))); err != nil {
+		switch {
+		case errors.Is(err, ErrorUnsupported):
+			return FormatDescription{}, fmt.Errorf("format desc: index %d: not found %w", index, err)
+		default:
+			return FormatDescription{}, fmt.Errorf("format desc failed: %w", err)
+		}
+	}
+	return FormatDescription{v4l2FormatDesc:desc}, nil
+}
+
+// GetAllFormatDescriptions attempts to retrieve all device format descriptions by
+// iterating from 0 upto an index that returns an error. At that point, the function
+// will return the collected descriptions and the error.
+// So if len(result) > 0, then error could be ignored.
+func GetAllFormatDescriptions(fd uintptr) (result []FormatDescription, err error){
+	index := uint32(0)
+	for {
+		desc := v4l2FormatDesc{index: index, bufType: BufTypeVideoCapture}
+		if err = Send(fd, VidiocGetFormat, uintptr(unsafe.Pointer(&desc))); err != nil {
+			break
+		}
+		result = append(result, FormatDescription{v4l2FormatDesc:desc})
+		index++
+	}
+	return result, err
+}

+ 1 - 0
v4l2/ioctl.go

@@ -73,6 +73,7 @@ func ioctl(fd, req, arg uintptr) (err error) {
 
 var (
 	VidiocQueryCap   = iocEncRead('V', 0, uintptr(unsafe.Sizeof(v4l2Capability{})))       // Represents command VIDIOC_QUERYCAP
+	VidioEnumFmt     = iocEncReadWrite('V', 2, uintptr(unsafe.Sizeof(v4l2FormatDesc{})))  // Represents command VIDIOC_ENUM_FMT
 	VidiocGetFormat  = iocEncReadWrite('V', 4, uintptr(unsafe.Sizeof(v4l2Format{})))      // Represents command VIDIOC_G_FMT
 	VidiocSetFormat  = iocEncReadWrite('V', 5, uintptr(unsafe.Sizeof(v4l2Format{})))      // Represents command VIDIOC_S_FMT
 	VidiocReqBufs    = iocEncReadWrite('V', 8, uintptr(unsafe.Sizeof(RequestBuffers{})))  // Represents command VIDIOC_REQBUFS