Skip to content

v4l2codecs: Avoid QBUF/DQBUF struct timeval .tv_usec wrap-around at frame 1000000

Marek Vasut requested to merge marex/gstreamer:v4l2-decoder-rollover into main

When decoding stream using hardware V4L2 decoder element, in any of the currently supported formats, the decoding will fail once frame number 1000000 is reached. The reported error clearly indicates a wrap-around occured, instead of receiving decoded frame 1000000, frame 0 is received from the hardware V4L2 decoder driver.

The problem is actually not in the driver itself, but rather in gstreamer, which uses struct v4l2_buffer member .timestamp in a special way. The timestamp of buffers with encoded data added to the SINK (input) queue of the driver is copied by the driver into matching buffers with decoded data added to the SOURCE (output) queue of the driver. In fact, the timestamp is not a timestamp at all, but rather in this special case, only part of it is used as an incrementing frame counter.

The .timestamp is of type struct timeval, which is defined in sys/time.h [1]. Only the tv_usec member of this structure is used for the incrementing frame counter. However, suseconds_t tv_usec [2] may be limited to range [-1, 1000000]:

[XSI] The type suseconds_t shall be a signed integer type capable of
      storing values at least in the range [-1, 1000000]. [Option End]

Therefore, once frame 1000000 is reached, a rollover occurs and decoding fails.

Fix this by using both struct timeval members, .tv_sec and .tv_usec with matching modular arithmetic, this way the failure would occur again just short of 2^84 frames, which should be plenty.

[1] https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_time.h.html [2] https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_types.h.html

Merge request reports