3.5. 缓冲区

缓冲区包含应用程序和驱动程序使用一种流式 I/O 方法交换的数据。在多平面 API 中,数据保存在平面中,而缓冲区结构充当平面的容器。只交换指向缓冲区(平面)的指针,数据本身不复制。这些指针以及诸如时间戳或场奇偶校验之类的元信息存储在结构体 v4l2_buffer 中,它是 ioctl VIDIOC_QUERYBUFVIDIOC_QBUFVIDIOC_DQBUF ioctl 的参数。在多平面 API 中,结构体 v4l2_buffer 的一些特定于平面的成员,例如每个平面的指针和大小,存储在结构体 v4l2_plane 中。在这种情况下,结构体 v4l2_buffer 包含一个平面结构数组。

出队的视频缓冲区带有时间戳。驱动程序决定在帧的哪个部分以及使用哪个时钟获取时间戳。请参阅 缓冲区标志V4L2_BUF_FLAG_TIMESTAMP_MASKV4L2_BUF_FLAG_TSTAMP_SRC_MASK 掩码中的标志。这些标志始终有效,并且在整个视频流中对所有缓冲区都是恒定的。这些标志的更改可能会作为 VIDIOC_S_INPUTVIDIOC_S_OUTPUT 的副作用发生。例如,在 mem-to-mem 设备上使用的 V4L2_BUF_FLAG_TIMESTAMP_COPY 时间戳类型是此规则的例外:时间戳源标志从 OUTPUT 视频缓冲区复制到 CAPTURE 视频缓冲区。

3.5.1. 格式、控件和缓冲区之间的交互

V4L2 公开了影响缓冲区大小或数据在缓冲区中布局方式的参数。这些参数通过格式和控件公开。这种控件的一个例子是 V4L2_CID_ROTATE 控件,它修改了像素存储在缓冲区中的方向,以及当所选格式包含行尾的填充时修改了缓冲区大小。

解释缓冲区内容所需的一组信息(例如,像素格式、行步幅、平铺方向或旋转)在本节的其余部分中统称为缓冲区布局。

可以修改缓冲区布局的控件应设置 V4L2_CTRL_FLAG_MODIFY_LAYOUT 标志。

修改影响缓冲区大小或布局的格式或控件需要停止流。在流活动时尝试进行此类修改应导致设置格式或控件的 ioctl 返回 EBUSY 错误代码。在这种情况下,驱动程序在调用 VIDIOC_QUERYCTRL()VIDIOC_QUERY_EXT_CTRL() 时,也应为流活动时此类控件设置 V4L2_CTRL_FLAG_GRABBED 标志。

注意

VIDIOC_S_SELECTION() ioctl 可以根据硬件(例如,如果设备不包含缩放器)修改格式以及选择矩形。类似地,VIDIOC_S_INPUT()VIDIOC_S_OUTPUT()VIDIOC_S_STD()VIDIOC_S_DV_TIMINGS() ioctl 也可以修改格式和选择矩形。当这些 ioctl 导致缓冲区大小或布局更改时,驱动程序应像处理 VIDIOC_S_FMT() ioctl 中描述的所有情况一样处理这种情况。

仅影响缓冲区布局的控件可以在停止流时随时修改。由于它们不影响缓冲区大小,因此无需特殊处理即可将这些控件与缓冲区分配同步,并且一旦流停止,V4L2_CTRL_FLAG_GRABBED 标志将被清除。

影响缓冲区大小的格式和控件与缓冲区分配交互。处理此问题的最简单方法是让驱动程序始终要求重新分配缓冲区,以便更改这些格式或控件。在这种情况下,要执行此类更改,用户空间应用程序应首先使用 VIDIOC_STREAMOFF() ioctl 停止视频流(如果正在运行),并使用 VIDIOC_REQBUFS() ioctl 释放所有缓冲区(如果已分配)。释放所有缓冲区后,将清除控件的 V4L2_CTRL_FLAG_GRABBED 标志。然后可以修改格式或控件,然后应重新分配缓冲区并重新启动流。一个典型的 ioctl 序列是

  1. VIDIOC_STREAMOFF

  2. VIDIOC_REQBUFS(0)

  3. VIDIOC_S_EXT_CTRLS

  4. VIDIOC_S_FMT

  5. VIDIOC_REQBUFS(n)

  6. VIDIOC_QBUF

  7. VIDIOC_STREAMON

第二个 VIDIOC_REQBUFS() 调用将考虑新的格式和控件值,以计算要分配的缓冲区大小。如果需要,应用程序还可以通过调用 VIDIOC_G_FMT() ioctl 来检索大小。

注意

API 不强制执行上述控制(3.)和格式(4.)更改的顺序。格式和控件可以根据设备和用例以不同的顺序设置,甚至可以交错设置。例如,某些控件对于不同的像素格式可能会表现不同,在这种情况下,可能需要首先设置格式。

当需要重新分配时,任何尝试在分配缓冲区时修改影响缓冲区大小的格式或控件都应导致格式或控件设置 ioctl 返回 EBUSY 错误。任何尝试排队对于当前格式或控件而言太小的缓冲区都应导致 VIDIOC_QBUF() ioctl 返回 EINVAL 错误。

缓冲区重新分配是一项昂贵的操作。为了避免这种成本,鼓励驱动程序允许在分配缓冲区的情况下更改影响缓冲区大小的格式或控件。在这种情况下,修改格式和控件的典型 ioctl 序列是

  1. VIDIOC_STREAMOFF

  2. VIDIOC_S_EXT_CTRLS

  3. VIDIOC_S_FMT

  4. VIDIOC_QBUF

  5. VIDIOC_STREAMON

为了使此序列正确运行,排队的缓冲区需要足够大,以适应新的格式或控件。如果当前排队的缓冲区对于新格式而言太小,则驱动程序应返回 ENOSPC 错误以响应格式更改 (VIDIOC_S_FMT()) 或控件更改 (VIDIOC_S_CTRL()VIDIOC_S_EXT_CTRLS())。作为一种简化,如果当前已排队任何缓冲区,则允许驱动程序从这些 ioctl 返回 EBUSY 错误,而无需检查排队缓冲区的大小。

此外,如果正在排队的缓冲区对于当前格式或控件而言太小,则驱动程序应从 VIDIOC_QBUF() ioctl 返回 EINVAL 错误。这些要求共同确保排队的缓冲区始终足够大,以适应配置的格式和控件。

用户空间应用程序可以通过首先设置所需的控件值,然后尝试所需的格式,来查询给定格式和控件所需的缓冲区大小。VIDIOC_TRY_FMT() ioctl 将返回所需的缓冲区大小。

  1. VIDIOC_S_EXT_CTRLS(x)

  2. VIDIOC_TRY_FMT()

  3. VIDIOC_S_EXT_CTRLS(y)

  4. VIDIOC_TRY_FMT()

然后可以使用 VIDIOC_CREATE_BUFS() ioctl 根据查询的大小分配缓冲区(例如,通过分配一组足够大的缓冲区以适应所有所需的格式和控件,或者通过为每个用例分配单独的一组大小合适的缓冲区)。

类型 v4l2_buffer

3.5.2. struct v4l2_buffer

struct v4l2_buffer

__u32

index

缓冲区的编号,由应用程序设置,但在调用 VIDIOC_DQBUF 时除外,此时由驱动程序设置。该字段的范围可以从零到使用 ioctl VIDIOC_REQBUFS ioctl(struct v4l2_requestbuffers count)分配的缓冲区数量,加上使用 ioctl VIDIOC_CREATE_BUFS 分配的任何缓冲区减一。

__u32

type

缓冲区的类型,与 struct v4l2_format type 或 struct v4l2_requestbuffers type 相同,由应用程序设置。请参阅 v4l2_buf_type

__u32

bytesused

缓冲区中数据占用的字节数。它取决于协商的数据格式,并且对于压缩的可变大小数据(如 JPEG 图像)可能会随每个缓冲区而变化。当 type 指的是捕获流时,驱动程序必须设置此字段;当它指的是输出流时,应用程序必须设置此字段。对于多平面格式,此字段将被忽略,而是使用 planes 指针。

__u32

flags

由应用程序或驱动程序设置的标志,请参阅 缓冲区标志

__u32

field

指示缓冲区中图像的场序,请参阅 v4l2_field。当缓冲区包含 VBI 数据时,不使用此字段。当 type 指的是捕获流时,驱动程序必须设置它;当它指的是输出流时,应用程序必须设置它。

struct timeval

timestamp

对于捕获流,这是捕获第一个数据字节的时间,由相关时钟 ID 的 clock_gettime() 函数返回;请参阅 缓冲区标志 中的 V4L2_BUF_FLAG_TIMESTAMP_*。对于输出流,驱动程序将实际发送出最后一个数据字节的时间存储在 timestamp 字段中。这允许应用程序监视视频和系统时钟之间的漂移。对于使用 V4L2_BUF_FLAG_TIMESTAMP_COPY 的输出流,应用程序必须填写时间戳,该时间戳将由驱动程序复制到捕获流。

struct v4l2_timecode

timecode

flags 中设置了 V4L2_BUF_FLAG_TIMECODE 标志时,此结构包含帧时间码。在 V4L2_FIELD_ALTERNATE 模式下,顶部和底部场包含相同的时间码。时间码旨在帮助视频编辑,通常记录在录像带上,但也嵌入在诸如 MPEG 之类的压缩格式中。此字段独立于 timestampsequence 字段。

__u32

sequence

由驱动程序设置,按顺序计数帧(不是场!)。为输入和输出设备设置此字段。

V4L2_FIELD_ALTERNATE 模式下,顶部和底部场具有相同的序列号。计数从零开始,包括丢弃或重复的帧。丢弃的帧由输入设备接收,但由于缺少可用缓冲区空间而无法存储。重复的帧由输出设备再次显示,因为应用程序没有及时传递新数据。

注意

这可能会计数通过 USB 接收的帧,而无需考虑由于有限的压缩吞吐量或总线带宽而被远程硬件丢弃的帧。这些设备通过不枚举任何视频标准来识别,请参阅 视频标准

__u32

memory

必须由应用程序和/或驱动程序根据所选的 I/O 方法设置此字段。请参阅 v4l2_memory

union {

m

__u32

offset

对于单平面 API,并且当 memoryV4L2_MEMORY_MMAP 时,这是缓冲区相对于设备内存起始位置的偏移量。该值由驱动程序返回,并且作为 mmap() 函数的参数,对应用程序没有用处。有关详细信息,请参阅 流式 I/O(内存映射)

unsigned long

userptr

对于单平面 API,并且当 memoryV4L2_MEMORY_USERPTR 时,这是指向虚拟内存中缓冲区(强制转换为 unsigned long 类型)的指针,由应用程序设置。有关详细信息,请参阅 流式 I/O(用户指针)

struct v4l2_plane

*planes

使用多平面 API 时,包含指向 struct v4l2_plane 数组的用户空间指针。数组的大小应放在此 struct v4l2_buffer 结构的 length 字段中。

int

fd

对于单平面 API,并且当 memoryV4L2_MEMORY_DMABUF 时,这是与 DMABUF 缓冲区关联的文件描述符。

}

__u32

length

单平面 API 的缓冲区大小(不是有效负载),以字节为单位。这是由驱动程序根据对 ioctl VIDIOC_REQBUFS 和/或 ioctl VIDIOC_CREATE_BUFS 的调用设置的。对于多平面 API,应用程序将其设置为 planes 数组中的元素数。驱动程序将填写该数组中有效元素的实际数量。

__u32

reserved2

用于将来扩展的占位符。驱动程序和应用程序必须将其设置为 0。

__u32

request_fd

要将缓冲区排队到的请求的文件描述符。如果设置了标志 V4L2_BUF_FLAG_REQUEST_FD,则会将缓冲区排队到此请求。如果未设置该标志,则将忽略此字段。

V4L2_BUF_FLAG_REQUEST_FD 标志和此字段仅由 ioctl VIDIOC_QBUF 使用,并且被其他将 v4l2_buffer 作为参数的 ioctl 忽略。

对于除 VIDIOC_QBUF 之外的任何 ioctl,应用程序不应设置 V4L2_BUF_FLAG_REQUEST_FD

如果设备不支持请求,则将返回 EBADR。如果支持请求但给出了无效的请求文件描述符,则将返回 EINVAL

类型 v4l2_plane

3.5.3. struct v4l2_plane

__u32

bytesused

平面中数据占用的字节数(其有效负载)。当 type 指的是捕获流时,驱动程序必须设置此字段;当它指的是输出流时,应用程序必须设置此字段。

注意

请注意,实际图像数据从 data_offset 开始,它可能不是 0。

__u32

length

平面(而非其有效负载)的大小,以字节为单位。 该值由驱动程序根据对 ioctl VIDIOC_REQBUFS 和/或 ioctl VIDIOC_CREATE_BUFS 的调用进行设置。

union {

m

__u32

mem_offset

当包含的结构体 v4l2_buffer 中的内存类型为 V4L2_MEMORY_MMAP 时,该值应传递给 mmap(),类似于结构体 v4l2_buffer 中的 offset 字段。

unsigned long

userptr

当包含的结构体 v4l2_buffer 中的内存类型为 V4L2_MEMORY_USERPTR 时,这是一个用户空间指针,指向应用程序为此平面分配的内存。

int

fd

当包含的结构体 v4l2_buffer 中的内存类型为 V4L2_MEMORY_DMABUF 时,这是一个与 DMABUF 缓冲区关联的文件描述符,类似于结构体 v4l2_buffer 中的 fd 字段。

}

__u32

data_offset

平面中视频数据的偏移量(以字节为单位)。 当 type 指的是捕获流时,驱动程序必须设置此字段;当指的是输出流时,应用程序必须设置此字段。

注意

该 data_offset 包含在 bytesused 中。因此,平面中图像的大小为 bytesused-data_offset,偏移量为从平面开始的 data_offset

__u32

reserved[11]

保留供将来使用。 驱动程序和应用程序应将其归零。

type v4l2_buf_type

3.5.4. enum v4l2_buf_type

V4L2_BUF_TYPE_VIDEO_CAPTURE

1

单平面视频捕获流的缓冲区,请参阅 视频捕获接口

V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE

9

多平面视频捕获流的缓冲区,请参阅 视频捕获接口

V4L2_BUF_TYPE_VIDEO_OUTPUT

2

单平面视频输出流的缓冲区,请参阅 视频输出接口

V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE

10

多平面视频输出流的缓冲区,请参阅 视频输出接口

V4L2_BUF_TYPE_VIDEO_OVERLAY

3

视频覆盖的缓冲区,请参阅 视频覆盖接口

V4L2_BUF_TYPE_VBI_CAPTURE

4

原始 VBI 捕获流的缓冲区,请参阅 原始 VBI 数据接口

V4L2_BUF_TYPE_VBI_OUTPUT

5

原始 VBI 输出流的缓冲区,请参阅 原始 VBI 数据接口

V4L2_BUF_TYPE_SLICED_VBI_CAPTURE

6

切片 VBI 捕获流的缓冲区,请参阅 切片 VBI 数据接口

V4L2_BUF_TYPE_SLICED_VBI_OUTPUT

7

切片 VBI 输出流的缓冲区,请参阅 切片 VBI 数据接口

V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY

8

视频输出覆盖 (OSD) 的缓冲区,请参阅 视频输出覆盖接口

V4L2_BUF_TYPE_SDR_CAPTURE

11

软件定义无线电 (SDR) 捕获流的缓冲区,请参阅 软件定义无线电接口 (SDR)

V4L2_BUF_TYPE_SDR_OUTPUT

12

软件定义无线电 (SDR) 输出流的缓冲区,请参阅 软件定义无线电接口 (SDR)

V4L2_BUF_TYPE_META_CAPTURE

13

元数据捕获的缓冲区,请参阅 元数据接口

V4L2_BUF_TYPE_META_OUTPUT

14

元数据输出的缓冲区,请参阅 元数据接口

3.5.5. 缓冲区标志

V4L2_BUF_FLAG_MAPPED

0x00000001

该缓冲区位于设备内存中,并且已映射到应用程序的地址空间中,有关详细信息,请参阅 流式 I/O (内存映射)。 调用 ioctl VIDIOC_QUERYBUFioctl VIDIOC_QBUF, VIDIOC_DQBUFVIDIOC_DQBUF ioctl 时,驱动程序会设置或清除此标志。 由驱动程序设置。

V4L2_BUF_FLAG_QUEUED

0x00000002

在内部,驱动程序维护两个缓冲区队列,一个传入队列和一个传出队列。 设置此标志后,该缓冲区当前位于传入队列中。缓冲区填充(捕获设备)或显示(输出设备)后,它会自动移至传出队列。 调用 VIDIOC_QUERYBUF ioctl 时,驱动程序会设置或清除此标志。 在(成功)调用 VIDIOC_QBUFioctl 之后,它始终设置为已设置,并在 VIDIOC_DQBUF 之后始终清除。

V4L2_BUF_FLAG_DONE

0x00000004

设置此标志后,该缓冲区当前位于传出队列中,可以从驱动程序中出队。 调用 VIDIOC_QUERYBUF ioctl 时,驱动程序会设置或清除此标志。 调用 VIDIOC_QBUFVIDIOC_DQBUF 之后,它始终会被清除。 当然,一个缓冲区不能同时位于两个队列中,V4L2_BUF_FLAG_QUEUEDV4L2_BUF_FLAG_DONE 标志是互斥的。 但是,它们可以都被清除,那么该缓冲区将处于“已出队”状态,也就是说,它位于应用程序域中。

V4L2_BUF_FLAG_ERROR

0x00000040

设置此标志后,缓冲区已成功出队,但数据可能已损坏。 这是可恢复的,流式传输可以像往常一样继续,并且可以正常重复使用该缓冲区。 调用 VIDIOC_DQBUF ioctl 时,驱动程序会设置此标志。

V4L2_BUF_FLAG_IN_REQUEST

0x00000080

此缓冲区是尚未排队的请求的一部分。

V4L2_BUF_FLAG_KEYFRAME

0x00000008

调用 VIDIOC_DQBUF ioctl 时,驱动程序会设置或清除此标志。 当缓冲区包含压缩图像时,视频捕获设备可能会设置该标志,该压缩图像是一个关键帧(或字段),即可自行解压缩。 也称为 I 帧。 当 type 指的是输出流时,应用程序可以设置此位。

V4L2_BUF_FLAG_PFRAME

0x00000010

V4L2_BUF_FLAG_KEYFRAME 类似,此标志预测帧或字段,其中仅包含与先前关键帧的差异。 当 type 指的是输出流时,应用程序可以设置此位。

V4L2_BUF_FLAG_BFRAME

0x00000020

V4L2_BUF_FLAG_KEYFRAME 类似,此标志一个双向预测帧或字段,其中仅包含当前帧与前面和后面的关键帧之间的差异,以指定其内容。 当 type 指的是输出流时,应用程序可以设置此位。

V4L2_BUF_FLAG_TIMECODE

0x00000100

timecode 字段有效。 调用 VIDIOC_DQBUF ioctl 时,驱动程序会设置或清除此标志。 当 type 指的是输出流时,应用程序可以设置此位和相应的 timecode 结构。

V4L2_BUF_FLAG_PREPARED

0x00000400

该缓冲区已准备好进行 I/O,并且可以由应用程序排队。 调用 VIDIOC_QUERYBUFVIDIOC_PREPARE_BUFVIDIOC_QBUFVIDIOC_DQBUF ioctl 时,驱动程序会设置或清除此标志。

V4L2_BUF_FLAG_NO_CACHE_INVALIDATE

0x00000800

不必使此缓冲区的缓存失效。 通常,如果 CPU 不会接触缓冲区中捕获的数据,则应用程序应使用此标志,相反,可能会将缓冲区传递给支持 DMA 的硬件单元以进行进一步处理或输出。 除非队列用于 内存映射 流式 I/O 并报告 V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS 功能,否则将忽略此标志。

V4L2_BUF_FLAG_NO_CACHE_CLEAN

0x00001000

不必为此缓冲区清理缓存。 通常,如果此缓冲区中的数据不是由 CPU 创建而是由某些支持 DMA 的单元创建的,在这种情况下未使用缓存,则应用程序应将此标志用于输出缓冲区。 除非队列用于 内存映射 流式 I/O 并报告 V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS 功能,否则将忽略此标志。

V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF

0x00000200

仅当设置了结构体 v4l2_requestbuffers 标志 V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF 时才有效。 它通常与无状态解码器一起使用,其中多个输出缓冲区各自解码为解码帧的一部分。 应用程序可以在对输出缓冲区进行排队时设置此标志,以防止驱动程序在解码输出缓冲区之后对捕获缓冲区进行出队(即,捕获缓冲区是“保留的”)。 如果此输出缓冲区的时间戳与前一个输出缓冲区的时间戳不同,则表示新帧的开始,并且先前保留的捕获缓冲区将出队。

V4L2_BUF_FLAG_LAST

0x00100000

硬件生成的最后一个缓冲区。 当调用 ioctl VIDIOC_QUERYBUFVIDIOC_DQBUF ioctl 时,mem2mem 编解码器驱动程序会在捕获队列上设置此标志。 由于硬件限制,最后一个缓冲区可能为空。 在这种情况下,无论格式如何,驱动程序都会将 bytesused 字段设置为 0。 随后对 VIDIOC_DQBUF ioctl 的任何调用都不会再阻塞,而是返回 EPIPE 错误代码。

V4L2_BUF_FLAG_REQUEST_FD

0x00800000

request_fd 字段包含有效的文件描述符。

V4L2_BUF_FLAG_TIMESTAMP_MASK

0x0000e000

用于以下时间戳类型的掩码。 要测试时间戳类型,请通过对缓冲区标志和时间戳掩码执行逻辑与运算来屏蔽掉不属于时间戳类型的位。

V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN

0x00000000

未知时间戳类型。 Linux 3.9 之前的驱动程序使用此类型,并且它可能是单调的(请参见下文)或实时的(挂钟时间)。 单调时钟在嵌入式系统中很受欢迎,而大多数驱动程序都使用实时时钟。 两种类型的时间戳都可通过使用时钟 ID CLOCK_MONOTONICCLOCK_REALTIMEclock_gettime() 在用户空间中使用。

V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC

0x00002000

缓冲区时间戳取自 CLOCK_MONOTONIC 时钟。 要在 V4L2 之外访问同一时钟,请使用 clock_gettime()

V4L2_BUF_FLAG_TIMESTAMP_COPY

0x00004000

CAPTURE 缓冲区时间戳取自相应的 OUTPUT 缓冲区。 此标志仅适用于 mem2mem 设备。

V4L2_BUF_FLAG_TSTAMP_SRC_MASK

0x00070000

用于以下时间戳源的掩码。 时间戳源定义了时间戳相对于帧的获取时间点。 flags 字段与 V4L2_BUF_FLAG_TSTAMP_SRC_MASK 之间的逻辑“与”运算会生成时间戳源的值。 当 type 指的是输出流并且设置了 V4L2_BUF_FLAG_TIMESTAMP_COPY 时,应用程序必须设置时间戳源。

V4L2_BUF_FLAG_TSTAMP_SRC_EOF

0x00000000

帧结束。 当接收到帧的最后一个像素或已传输帧的最后一个像素时,将获取缓冲区时间戳。 实际上,软件生成的时间戳通常会在接收或传输最后一个像素之后的一小段时间内从时钟读取,具体取决于系统及其中的其他活动。

V4L2_BUF_FLAG_TSTAMP_SRC_SOE

0x00010000

曝光开始。 缓冲区时间戳是在帧的曝光开始时获取的。 这仅对 V4L2_BUF_TYPE_VIDEO_CAPTURE 缓冲区类型有效。

3.5.6. enum v4l2_memory

V4L2_MEMORY_MMAP

1

该缓冲区用于 内存映射 I/O。

V4L2_MEMORY_USERPTR

2

该缓冲区用于 用户指针 I/O。

V4L2_MEMORY_OVERLAY

3

[待办]

V4L2_MEMORY_DMABUF

4

该缓冲区用于 DMA 共享缓冲区 I/O。

3.5.7. 时间码

v4l2_buffer_timecode 结构旨在保存 SMPTE 12M 或类似的时间码。(timeval 时间戳存储在结构 v4l2_buffer timestamp 字段中。)

type v4l2_timecode

3.5.7.1. struct v4l2_timecode

__u32

type

时间码基于的帧速率,请参阅 时间码类型

__u32

flags

时间码标志,请参阅 时间码标志

__u8

frames

帧计数,0 ... 23/24/29/49/59,具体取决于时间码的类型。

__u8

seconds

秒数,0 ... 59。这是一个二进制数,而不是 BCD 数字。

__u8

minutes

分钟数,0 ... 59。这是一个二进制数,而不是 BCD 数字。

__u8

hours

小时数,0 ... 29。这是一个二进制数,而不是 BCD 数字。

__u8

userbits[4]

时间码中的“用户组”位。

3.5.7.2. 时间码类型

V4L2_TC_TYPE_24FPS

1

每秒 24 帧,即电影。

V4L2_TC_TYPE_25FPS

2

每秒 25 帧,即 PAL 或 SECAM 视频。

V4L2_TC_TYPE_30FPS

3

每秒 30 帧,即 NTSC 视频。

V4L2_TC_TYPE_50FPS

4

V4L2_TC_TYPE_60FPS

5

3.5.7.3. 时间码标志

V4L2_TC_FLAG_DROPFRAME

0x0001

表示 29.97 fps 素材中用于计算帧的“丢帧”语义。 设置后,从每分钟开始,从计数中省略帧号 0 和 1,但 0、10、20、30、40、50 分钟除外。

V4L2_TC_FLAG_COLORFRAME

0x0002

“彩色帧”标志。

V4L2_TC_USERBITS_field

0x000C

“二进制组标志”的字段掩码。

V4L2_TC_USERBITS_USERDEFINED

0x0000

未指定的格式。

V4L2_TC_USERBITS_8BITCHARS

0x0008

8 位 ISO 字符。