format_frameintervals.go 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. package v4l2
  2. /*
  3. #cgo linux CFLAGS: -I ${SRCDIR}/../include/
  4. #include <linux/videodev2.h>
  5. */
  6. import "C"
  7. import (
  8. "fmt"
  9. "unsafe"
  10. )
  11. // FrameIntervalType (v4l2_frmivaltypes)
  12. // See https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L845
  13. type FrameIntervalType = uint32
  14. const (
  15. FrameIntervalTypeDiscrete FrameIntervalType = C.V4L2_FRMIVAL_TYPE_DISCRETE
  16. FrameIntervalTypeContinuous FrameIntervalType = C.V4L2_FRMIVAL_TYPE_CONTINUOUS
  17. FrameIntervalTypeStepwise FrameIntervalType = C.V4L2_FRMIVAL_TYPE_STEPWISE
  18. )
  19. // FrameIntervalEnum is used to store v4l2_frmivalenum values.
  20. // See https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L857
  21. // See https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/vidioc-enum-frameintervals.html
  22. type FrameIntervalEnum struct {
  23. Index uint32
  24. PixelFormat FourCCType
  25. Width uint32
  26. Height uint32
  27. Type FrameIntervalType
  28. Interval FrameInterval
  29. }
  30. // FrameInterval stores all frame interval values regardless of its type. This type maps to v4l2_frmival_stepwise.
  31. // See https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L851
  32. // See https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/vidioc-enum-frameintervals.html
  33. type FrameInterval struct {
  34. Min Fract
  35. Max Fract
  36. Step Fract
  37. }
  38. // getFrameInterval retrieves the supported frame interval info from following union based on the type:
  39. // union {
  40. // struct v4l2_fract discrete;
  41. // struct v4l2_frmival_stepwise stepwise;
  42. // }
  43. // See https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/vidioc-enum-frameintervals.html
  44. func getFrameInterval(interval C.struct_v4l2_frmivalenum) (FrameIntervalEnum, error) {
  45. frmInterval := FrameIntervalEnum{
  46. Index: uint32(interval.index),
  47. Type: FrameIntervalType(interval._type),
  48. PixelFormat: FourCCType(interval.pixel_format),
  49. Width: uint32(interval.width),
  50. Height: uint32(interval.height),
  51. }
  52. intervalType := uint32(interval._type)
  53. switch intervalType {
  54. case FrameIntervalTypeDiscrete:
  55. fiDiscrete := *(*Fract)(unsafe.Pointer(&interval.anon0[0]))
  56. frmInterval.Interval.Min = fiDiscrete
  57. frmInterval.Interval.Max = fiDiscrete
  58. frmInterval.Interval.Step.Numerator = 1
  59. frmInterval.Interval.Step.Denominator = 1
  60. case FrameIntervalTypeStepwise, FrameIntervalTypeContinuous:
  61. // Calculate pointer to stepwise member of union
  62. frmInterval.Interval = *(*FrameInterval)(unsafe.Pointer(uintptr(unsafe.Pointer(&interval.anon0[0])) + unsafe.Sizeof(Fract{})))
  63. default:
  64. return FrameIntervalEnum{}, fmt.Errorf("unsupported frame interval type: %d", intervalType)
  65. }
  66. return frmInterval, nil
  67. }
  68. // GetFormatFrameInterval returns a supported device frame interval for a specified encoding at index and format
  69. func GetFormatFrameInterval(fd uintptr, index uint32, encoding FourCCType, width, height uint32) (FrameIntervalEnum, error) {
  70. var interval C.struct_v4l2_frmivalenum
  71. interval.index = C.uint(index)
  72. interval.pixel_format = C.uint(encoding)
  73. interval.width = C.uint(width)
  74. interval.height = C.uint(height)
  75. if err := send(fd, C.VIDIOC_ENUM_FRAMEINTERVALS, uintptr(unsafe.Pointer(&interval))); err != nil {
  76. return FrameIntervalEnum{}, fmt.Errorf("frame interval: index %d: %w", index, err)
  77. }
  78. return getFrameInterval(interval)
  79. }