v4l2: drop frames for those dequeued buffer with error flag

Some frames are dequeued with error flag, which may cause AV unsync if decoder
does not drop them as soon as possible. So add "output-error-dequeued" and
"capture-error-dequeued" signal for v4l2 to drop such frames.

Fixes #3031

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5479>
This commit is contained in:
Hou Qi 2024-02-21 17:19:45 +09:00 committed by GStreamer Marge Bot
parent 3f0808a910
commit bf87ad72e4
2 changed files with 43 additions and 0 deletions

View File

@ -80,6 +80,15 @@ enum _GstV4l2BufferState
BUFFER_STATE_QUEUED = 2,
};
enum
{
OUTPUT_ERROR_DEQUEUED,
CAPTURE_ERROR_DEQUEUED,
LAST_SIGNAL
};
static guint gst_v4l2_buffer_pool_signals[LAST_SIGNAL] = { 0 };
static void gst_v4l2_buffer_pool_complete_release_buffer (GstBufferPool * bpool,
GstBuffer * buffer, gboolean queued);
@ -1279,6 +1288,16 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer,
GST_LOG_OBJECT (pool, "dequeueing a buffer");
res = gst_v4l2_allocator_dqbuf (pool->vallocator, &group);
if (group->buffer.flags & V4L2_BUF_FLAG_ERROR) {
if (V4L2_TYPE_IS_OUTPUT (obj->type))
g_signal_emit (pool, gst_v4l2_buffer_pool_signals[OUTPUT_ERROR_DEQUEUED],
0, (guint) group->buffer.timestamp.tv_sec);
else
g_signal_emit (pool, gst_v4l2_buffer_pool_signals[CAPTURE_ERROR_DEQUEUED],
0, (guint) group->buffer.timestamp.tv_sec);
}
if (res == GST_V4L2_FLOW_LAST_BUFFER)
goto eos;
if (res != GST_FLOW_OK)
@ -1765,6 +1784,14 @@ gst_v4l2_buffer_pool_class_init (GstV4l2BufferPoolClass * klass)
bufferpool_class->flush_start = gst_v4l2_buffer_pool_flush_start;
bufferpool_class->flush_stop = gst_v4l2_buffer_pool_flush_stop;
gst_v4l2_buffer_pool_signals[OUTPUT_ERROR_DEQUEUED] =
g_signal_new ("output-error-dequeued", G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT);
gst_v4l2_buffer_pool_signals[CAPTURE_ERROR_DEQUEUED] =
g_signal_new ("capture-error-dequeued", G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT);
GST_DEBUG_CATEGORY_INIT (v4l2bufferpool_debug, "v4l2bufferpool", 0,
"V4L2 Buffer Pool");
GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE");

View File

@ -180,6 +180,16 @@ gst_v4l2_video_dec_close (GstVideoDecoder * decoder)
return TRUE;
}
static void
gst_v4l2_video_dec_drop_frame (GstVideoDecoder * decoder, guint frame_number)
{
GstVideoCodecFrame *frame =
gst_video_decoder_get_frame (decoder, frame_number);
if (frame)
gst_video_decoder_drop_frame (decoder, frame);
}
static gboolean
gst_v4l2_video_dec_start (GstVideoDecoder * decoder)
{
@ -538,6 +548,9 @@ use_acquired_caps:
if (!active)
goto activate_failed;
g_signal_connect_swapped (self->v4l2capture->pool, "capture-error-dequeued",
G_CALLBACK (gst_v4l2_video_dec_drop_frame), decoder);
return TRUE;
not_negotiated:
@ -1004,6 +1017,9 @@ gst_v4l2_video_dec_handle_frame (GstVideoDecoder * decoder,
if (!gst_buffer_pool_set_active (pool, TRUE))
goto activate_failed;
g_signal_connect_swapped (self->v4l2output->pool, "output-error-dequeued",
G_CALLBACK (gst_v4l2_video_dec_drop_frame), decoder);
GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
GST_LOG_OBJECT (decoder, "Passing buffer with system frame number %u",
processed ? frame->system_frame_number : 0);