format.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. package v4l2
  2. // #include <linux/videodev2.h>
  3. import "C"
  4. import (
  5. "fmt"
  6. "unsafe"
  7. )
  8. // FourCCType represents the four character encoding value
  9. type FourCCType = uint32
  10. // Some Predefined pixel format definitions
  11. // https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/pixfmt.html
  12. // https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L518
  13. var (
  14. PixelFmtRGB24 FourCCType = C.V4L2_PIX_FMT_RGB24
  15. PixelFmtGrey FourCCType = C.V4L2_PIX_FMT_GREY
  16. PixelFmtYUYV FourCCType = C.V4L2_PIX_FMT_YUYV
  17. PixelFmtYYUV FourCCType = C.V4L2_PIX_FMT_YYUV
  18. PixelFmtYVYU FourCCType = C.V4L2_PIX_FMT_YVYU
  19. PixelFmtUYVY FourCCType = C.V4L2_PIX_FMT_UYVY
  20. PixelFmtVYUY FourCCType = C.V4L2_PIX_FMT_VYUY
  21. PixelFmtMJPEG FourCCType = C.V4L2_PIX_FMT_MJPEG
  22. PixelFmtJPEG FourCCType = C.V4L2_PIX_FMT_JPEG
  23. PixelFmtMPEG FourCCType = C.V4L2_PIX_FMT_MPEG
  24. PixelFmtH264 FourCCType = C.V4L2_PIX_FMT_H264
  25. PixelFmtMPEG4 FourCCType = C.V4L2_PIX_FMT_MPEG4
  26. )
  27. // PixelFormats provides a map of FourCCType encoding description
  28. var PixelFormats = map[FourCCType]string{
  29. PixelFmtRGB24: "24-bit RGB 8-8-8",
  30. PixelFmtGrey: "8-bit Greyscale",
  31. PixelFmtYUYV: "YUYV 4:2:2",
  32. PixelFmtMJPEG: "Motion-JPEG",
  33. PixelFmtJPEG: "JFIF JPEG",
  34. PixelFmtMPEG: "MPEG-1/2/4",
  35. PixelFmtH264: "H.264",
  36. PixelFmtMPEG4: "MPEG-4 Part 2 ES",
  37. }
  38. // IsPixYUVEncoded returns true if the pixel format is a chrome+luminance YUV format
  39. func IsPixYUVEncoded(pixFmt FourCCType) bool {
  40. switch pixFmt {
  41. case
  42. PixelFmtYUYV,
  43. PixelFmtYYUV,
  44. PixelFmtYVYU,
  45. PixelFmtUYVY,
  46. PixelFmtVYUY:
  47. return true
  48. default:
  49. return false
  50. }
  51. }
  52. // ColorspaceType
  53. // See https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L195
  54. type ColorspaceType = uint32
  55. const (
  56. ColorspaceDefault ColorspaceType = C.V4L2_COLORSPACE_DEFAULT
  57. ColorspaceSMPTE170M ColorspaceType = C.V4L2_COLORSPACE_SMPTE170M
  58. ColorspaceSMPTE240M ColorspaceType = C.V4L2_COLORSPACE_SMPTE240M
  59. ColorspaceREC709 ColorspaceType = C.V4L2_COLORSPACE_REC709
  60. ColorspaceBT878 ColorspaceType = C.V4L2_COLORSPACE_BT878 //(absolete)
  61. Colorspace470SystemM ColorspaceType = C.V4L2_COLORSPACE_470_SYSTEM_M //(absolete)
  62. Colorspace470SystemBG ColorspaceType = C.V4L2_COLORSPACE_470_SYSTEM_BG
  63. ColorspaceJPEG ColorspaceType = C.V4L2_COLORSPACE_JPEG
  64. ColorspaceSRGB ColorspaceType = C.V4L2_COLORSPACE_SRGB
  65. ColorspaceOPRGB ColorspaceType = C.V4L2_COLORSPACE_OPRGB
  66. ColorspaceBT2020 ColorspaceType = C.V4L2_COLORSPACE_BT2020
  67. ColorspaceRaw ColorspaceType = C.V4L2_COLORSPACE_RAW
  68. ColorspaceDCIP3 ColorspaceType = C.V4L2_COLORSPACE_DCI_P3
  69. )
  70. // Colorspaces is a map of colorspace to its respective description
  71. var Colorspaces = map[ColorspaceType]string{
  72. ColorspaceDefault: "Default",
  73. ColorspaceREC709: "Rec. 709",
  74. Colorspace470SystemBG: "470 System BG",
  75. ColorspaceJPEG: "JPEG",
  76. ColorspaceSRGB: "sRGB",
  77. ColorspaceOPRGB: "opRGB",
  78. ColorspaceBT2020: "BT.2020",
  79. ColorspaceRaw: "Raw",
  80. ColorspaceDCIP3: "DCI-P3",
  81. }
  82. // YCbCrEncodingType (v4l2_ycbcr_encoding)
  83. // https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/colorspaces-defs.html?highlight=v4l2_ycbcr_encoding
  84. // https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L300
  85. type YCbCrEncodingType = uint32
  86. const (
  87. YCbCrEncodingDefault YCbCrEncodingType = C.V4L2_YCBCR_ENC_DEFAULT
  88. YCbCrEncoding601 YCbCrEncodingType = C.V4L2_YCBCR_ENC_601
  89. YCbCrEncoding709 YCbCrEncodingType = C.V4L2_YCBCR_ENC_709
  90. YCbCrEncodingXV601 YCbCrEncodingType = C.V4L2_YCBCR_ENC_XV601
  91. YCbCrEncodingXV709 YCbCrEncodingType = C.V4L2_YCBCR_ENC_XV709
  92. _ YCbCrEncodingType = C.V4L2_YCBCR_ENC_SYCC //(absolete)
  93. YCbCrEncodingBT2020 YCbCrEncodingType = C.V4L2_YCBCR_ENC_BT2020
  94. YCbCrEncodingBT2020ConstLum YCbCrEncodingType = C.V4L2_YCBCR_ENC_BT2020_CONST_LUM
  95. )
  96. var YCbCrEncodings = map[YCbCrEncodingType]string{
  97. YCbCrEncodingDefault: "Default",
  98. YCbCrEncoding601: "ITU-R 601",
  99. YCbCrEncoding709: "Rec. 709",
  100. YCbCrEncodingXV601: "xvYCC 601",
  101. YCbCrEncodingXV709: "xvYCC 709",
  102. YCbCrEncodingBT2020: "BT.2020",
  103. YCbCrEncodingBT2020ConstLum: "BT.2020 constant luminance",
  104. HSVEncoding180: "HSV 0-179",
  105. HSVEncoding256: "HSV 0-255",
  106. }
  107. // ColorspaceToYCbCrEnc is used to get the YCbCrEncoding when only a default YCbCr and the colorspace is known
  108. func ColorspaceToYCbCrEnc(cs ColorspaceType) YCbCrEncodingType {
  109. switch cs {
  110. case ColorspaceREC709, ColorspaceDCIP3:
  111. return YCbCrEncoding709
  112. case ColorspaceBT2020:
  113. return YCbCrEncodingBT2020
  114. default:
  115. return YCbCrEncoding601
  116. }
  117. }
  118. // HSVEncodingType (v4l2_hsv_encoding)
  119. // See https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L352
  120. type HSVEncodingType = YCbCrEncodingType
  121. const (
  122. HSVEncoding180 HSVEncodingType = C.V4L2_HSV_ENC_180
  123. HSVEncoding256 HSVEncodingType = C.V4L2_HSV_ENC_256
  124. )
  125. // QuantizationType (v4l2_quantization)
  126. // https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/colorspaces-defs.html?highlight=v4l2_quantization#c.V4L.v4l2_quantization
  127. // https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L372
  128. type QuantizationType = uint32
  129. const (
  130. QuantizationDefault QuantizationType = C.V4L2_QUANTIZATION_DEFAULT
  131. QuantizationFullRange QuantizationType = C.V4L2_QUANTIZATION_FULL_RANGE
  132. QuantizationLimitedRange QuantizationType = C.V4L2_QUANTIZATION_LIM_RANGE
  133. )
  134. var Quantizations = map[QuantizationType]string{
  135. QuantizationDefault: "Default",
  136. QuantizationFullRange: "Full range",
  137. QuantizationLimitedRange: "Limited range",
  138. }
  139. func ColorspaceToQuantization(cs ColorspaceType) QuantizationType {
  140. // TODO any RGB/HSV pixel formats should also return full-range
  141. switch cs {
  142. case ColorspaceOPRGB, ColorspaceSRGB, ColorspaceJPEG:
  143. return QuantizationFullRange
  144. default:
  145. return QuantizationLimitedRange
  146. }
  147. }
  148. // XferFunctionType (v4l2_xfer_func)
  149. // https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/colorspaces-defs.html?highlight=v4l2_xfer_func#c.V4L.v4l2_xfer_func
  150. // https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L259
  151. type XferFunctionType = uint32
  152. const (
  153. XferFuncDefault XferFunctionType = C.V4L2_XFER_FUNC_DEFAULT
  154. XferFunc709 XferFunctionType = C.V4L2_XFER_FUNC_709
  155. XferFuncSRGB XferFunctionType = C.V4L2_XFER_FUNC_SRGB
  156. XferFuncOpRGB XferFunctionType = C.V4L2_XFER_FUNC_OPRGB
  157. XferFuncSMPTE240M XferFunctionType = C.V4L2_XFER_FUNC_SMPTE240M
  158. XferFuncNone XferFunctionType = C.V4L2_XFER_FUNC_NONE
  159. XferFuncDCIP3 XferFunctionType = C.V4L2_XFER_FUNC_DCI_P3
  160. XferFuncSMPTE2084 XferFunctionType = C.V4L2_XFER_FUNC_SMPTE2084
  161. )
  162. var XferFunctions = map[XferFunctionType]string{
  163. XferFuncDefault: "Default",
  164. XferFunc709: "Rec. 709",
  165. XferFuncSRGB: "sRGB",
  166. XferFuncOpRGB: "opRGB",
  167. XferFuncSMPTE240M: "SMPTE 240M",
  168. XferFuncNone: "None",
  169. XferFuncDCIP3: "DCI-P3",
  170. XferFuncSMPTE2084: "SMPTE 2084",
  171. }
  172. // ColorspaceToXferFunc used to get true XferFunc when only colorspace and default XferFuc are known.
  173. func ColorspaceToXferFunc(cs ColorspaceType) XferFunctionType {
  174. switch cs {
  175. case ColorspaceOPRGB:
  176. return XferFuncOpRGB
  177. case ColorspaceSMPTE240M:
  178. return XferFuncSMPTE240M
  179. case ColorspaceDCIP3:
  180. return XferFuncDCIP3
  181. case ColorspaceRaw:
  182. return XferFuncNone
  183. case ColorspaceSRGB:
  184. return XferFuncSRGB
  185. case ColorspaceJPEG:
  186. return XferFuncSRGB
  187. default:
  188. return XferFunc709
  189. }
  190. }
  191. // FieldType (v4l2_field)
  192. // https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/field-order.html?highlight=v4l2_field#c.v4l2_field
  193. // https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L88
  194. type FieldType = uint32
  195. const (
  196. FieldAny FieldType = C.V4L2_FIELD_ANY
  197. FieldNone FieldType = C.V4L2_FIELD_NONE
  198. FieldTop FieldType = C.V4L2_FIELD_TOP
  199. FieldBottom FieldType = C.V4L2_FIELD_BOTTOM
  200. FieldInterlaced FieldType = C.V4L2_FIELD_INTERLACED
  201. FieldSequentialTopBottom FieldType = C.V4L2_FIELD_SEQ_TB
  202. FieldSequentialBottomTop FieldType = C.V4L2_FIELD_SEQ_BT
  203. FieldAlternate FieldType = C.V4L2_FIELD_ALTERNATE
  204. FieldInterlacedTopBottom FieldType = C.V4L2_FIELD_INTERLACED_TB
  205. FieldInterlacedBottomTop FieldType = C.V4L2_FIELD_INTERLACED_BT
  206. )
  207. // Fields is a map of FieldType description
  208. var Fields = map[FieldType]string{
  209. FieldAny: "any",
  210. FieldNone: "none",
  211. FieldTop: "top",
  212. FieldBottom: "bottom",
  213. FieldInterlaced: "interlaced",
  214. FieldSequentialTopBottom: "sequential top-bottom",
  215. FieldSequentialBottomTop: "Sequential botton-top",
  216. FieldAlternate: "alternating",
  217. FieldInterlacedTopBottom: "interlaced top-bottom",
  218. FieldInterlacedBottomTop: "interlaced bottom-top",
  219. }
  220. // PixFormat contains video image format from v4l2_pix_format.
  221. // https://www.kernel.org/doc/html/v4.9/media/uapi/v4l/pixfmt-002.html?highlight=v4l2_pix_format
  222. // https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L496
  223. type PixFormat struct {
  224. Width uint32
  225. Height uint32
  226. PixelFormat FourCCType
  227. Field FieldType
  228. BytesPerLine uint32
  229. SizeImage uint32
  230. Colorspace ColorspaceType
  231. Priv uint32
  232. Flags uint32
  233. YcbcrEnc YCbCrEncodingType
  234. HSVEnc HSVEncodingType
  235. Quantization QuantizationType
  236. XferFunc XferFunctionType
  237. }
  238. func (f PixFormat) String() string {
  239. return fmt.Sprintf(
  240. "%s [%dx%d]; field=%s; bytes per line=%d; size image=%d; colorspace=%s; YCbCr=%s; Quant=%s; XferFunc=%s",
  241. PixelFormats[f.PixelFormat],
  242. f.Width, f.Height,
  243. Fields[f.Field],
  244. f.BytesPerLine,
  245. f.SizeImage,
  246. Colorspaces[f.Colorspace],
  247. YCbCrEncodings[f.YcbcrEnc],
  248. Quantizations[f.Quantization],
  249. XferFunctions[f.XferFunc],
  250. )
  251. }
  252. // GetPixFormat retrieves pixel information for the specified driver (via v4l2_format and v4l2_pix_format)
  253. // See https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/videodev2.h#L2331
  254. // and https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/vidioc-g-fmt.html#ioctl-vidioc-g-fmt-vidioc-s-fmt-vidioc-try-fmt
  255. func GetPixFormat(fd uintptr) (PixFormat, error) {
  256. var v4l2Format C.struct_v4l2_format
  257. v4l2Format._type = C.uint(BufTypeVideoCapture)
  258. if err := send(fd, C.VIDIOC_G_FMT, uintptr(unsafe.Pointer(&v4l2Format))); err != nil {
  259. return PixFormat{}, fmt.Errorf("pix format failed: %w", err)
  260. }
  261. v4l2PixFmt := *(*C.struct_v4l2_pix_format)(unsafe.Pointer(&v4l2Format.fmt[0]))
  262. return PixFormat{
  263. Width: uint32(v4l2PixFmt.width),
  264. Height: uint32(v4l2PixFmt.height),
  265. PixelFormat: uint32(v4l2PixFmt.pixelformat),
  266. Field: uint32(v4l2PixFmt.field),
  267. BytesPerLine: uint32(v4l2PixFmt.bytesperline),
  268. SizeImage: uint32(v4l2PixFmt.sizeimage),
  269. Colorspace: uint32(v4l2PixFmt.colorspace),
  270. Priv: uint32(v4l2PixFmt.priv),
  271. Flags: uint32(v4l2PixFmt.flags),
  272. YcbcrEnc: *(*uint32)(unsafe.Pointer(&v4l2PixFmt.anon0[0])),
  273. HSVEnc: *(*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(&v4l2PixFmt.anon0[0])) + unsafe.Sizeof(C.uint(0)))),
  274. Quantization: uint32(v4l2PixFmt.quantization),
  275. XferFunc: uint32(v4l2PixFmt.xfer_func),
  276. }, nil
  277. }
  278. // SetPixFormat sets the pixel format information for the specified driver
  279. // See https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/vidioc-g-fmt.html#ioctl-vidioc-g-fmt-vidioc-s-fmt-vidioc-try-fmt
  280. func SetPixFormat(fd uintptr, pixFmt PixFormat) error {
  281. var v4l2Format C.struct_v4l2_format
  282. v4l2Format._type = C.uint(BufTypeVideoCapture)
  283. *(*C.struct_v4l2_pix_format)(unsafe.Pointer(&v4l2Format.fmt[0])) = *(*C.struct_v4l2_pix_format)(unsafe.Pointer(&pixFmt))
  284. if err := send(fd, C.VIDIOC_S_FMT, uintptr(unsafe.Pointer(&v4l2Format))); err != nil {
  285. return fmt.Errorf("pix format failed: %w", err)
  286. }
  287. return nil
  288. }