mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-27 02:30:35 +00:00
v4l2codecs: Avoid QBUF/DQBUF struct timeval .tv_usec wrap-around at frame 1000000
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]. " 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 A test case using stateless hardware h264 decoder, the WARN/ERROR output in gstreamer log indicates a failure occurred. With this change, that error no longer occurs and the WARN/ERROR are not present: ``` pc$ gst-launch-1.0 videotestsrc num-buffers=1001001 pattern=6 ! \ video/x-raw,width=16,height=16,format=I420 ! \ x264enc ! filesink location=/tmp/test.h264 dut$ GST_DEBUG="*:3" gst-launch-1.0 filesrc location=/tmp/test.h264 ! \ h264parse ! v4l2slh264dec ! fakesink ... 0:03:51.393677606 12111 0x370df400 WARN \ v4l2codecs-decoder gstv4l2decoder.c:1157:gst_v4l2_request_set_done:<v4l2decoder2> \ Requested frame 1000000, but driver returned frame 0. 0:03:51.394140597 12111 0x370df400 WARN \ v4l2codecs-decoder gstv4l2decoder.c:1157:gst_v4l2_request_set_done:<v4l2decoder2> \ Requested frame 1000001, but driver returned frame 1. 0:03:51.394425216 12111 0x370df400 WARN \ v4l2codecs-decoder gstv4l2decoder.c:1157:gst_v4l2_request_set_done:<v4l2decoder2> \ Requested frame 1000002, but driver returned frame 2. 0:03:51.394665211 12111 0x370df400 WARN \ v4l2codecs-decoder gstv4l2decoder.c:1157:gst_v4l2_request_set_done:<v4l2decoder2> \ Requested frame 1000003, but driver returned frame 3. 0:03:51.394785833 12111 0x370df400 WARN \ v4l2codecs-h264dec gstv4l2codech264dec.c:1059:gst_v4l2_codec_h264_dec_output_picture:<v4l2slh264dec0> \ error: Failed to decode frame 1000000 ERROR: from element /GstPipeline:pipeline0/v4l2slh264dec:v4l2slh264dec0: Failed to decode frame 1000000 ``` Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5603>
This commit is contained in:
parent
f44f36482c
commit
a0755e5d74
1 changed files with 3 additions and 2 deletions
|
@ -640,7 +640,8 @@ gst_v4l2_decoder_queue_sink_mem (GstV4l2Decoder * self,
|
|||
.type = self->sink_buf_type,
|
||||
.memory = V4L2_MEMORY_MMAP,
|
||||
.index = gst_v4l2_codec_memory_get_index (mem),
|
||||
.timestamp.tv_usec = frame_num,
|
||||
.timestamp.tv_sec = frame_num / 1000000,
|
||||
.timestamp.tv_usec = frame_num % 1000000,
|
||||
.request_fd = request->fd,
|
||||
.flags = V4L2_BUF_FLAG_REQUEST_FD | flags,
|
||||
};
|
||||
|
@ -747,7 +748,7 @@ gst_v4l2_decoder_dequeue_src (GstV4l2Decoder * self, guint32 * out_frame_num)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
*out_frame_num = buf.timestamp.tv_usec;
|
||||
*out_frame_num = buf.timestamp.tv_usec + buf.timestamp.tv_sec * 1000000;
|
||||
|
||||
GST_TRACE_OBJECT (self, "Dequeued picture buffer %i", buf.index);
|
||||
|
||||
|
|
Loading…
Reference in a new issue