From 3cc6643050345cb2ceb3782182a6bc863a97823f Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Sun, 16 Feb 2020 14:51:37 -0500 Subject: [PATCH] v4l2codecdecoder: Add support for dequeuing buffers This includings polling of the request and streamon/streamoff. --- sys/v4l2codecs/gstv4l2decoder.c | 146 ++++++++++++++++++++++++++++---- sys/v4l2codecs/gstv4l2decoder.h | 17 ++++ 2 files changed, 146 insertions(+), 17 deletions(-) diff --git a/sys/v4l2codecs/gstv4l2decoder.c b/sys/v4l2codecs/gstv4l2decoder.c index f35e468d49..a438108768 100644 --- a/sys/v4l2codecs/gstv4l2decoder.c +++ b/sys/v4l2codecs/gstv4l2decoder.c @@ -48,6 +48,9 @@ struct _GstV4l2Request GstV4l2Decoder *decoder; gint fd; GstMemory *bitstream; + GstPoll *poll; + GstPollFD pollfd; + gboolean pending; }; struct _GstV4l2Decoder @@ -68,6 +71,15 @@ G_DEFINE_TYPE_WITH_CODE (GstV4l2Decoder, gst_v4l2_decoder, GST_TYPE_OBJECT, GST_DEBUG_CATEGORY_INIT (v4l2_decoder_debug, "v4l2codecs-decoder", 0, "V4L2 stateless decoder helper")); +static guint32 +direction_to_buffer_type (GstPadDirection direction) +{ + if (direction == GST_PAD_SRC) + return V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + else + return V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; +} + static void gst_v4l2_decoder_finalize (GObject * obj) { @@ -125,7 +137,7 @@ gst_v4l2_decoder_open (GstV4l2Decoder * self) return FALSE; } - self->video_fd = open (self->video_device, 0); + self->video_fd = open (self->video_device, O_NONBLOCK); if (self->video_fd < 0) { GST_ERROR_OBJECT (self, "Failed to open '%s': %s", self->video_device, g_strerror (errno)); @@ -157,6 +169,36 @@ gst_v4l2_decoder_close (GstV4l2Decoder * self) return TRUE; } +gboolean +gst_v4l2_decoder_streamon (GstV4l2Decoder * self, GstPadDirection direction) +{ + gint ret; + guint32 type = direction_to_buffer_type (direction); + + ret = ioctl (self->video_fd, VIDIOC_STREAMON, &type); + if (ret < 0) { + GST_ERROR_OBJECT (self, "VIDIOC_STREAMON failed: %s", g_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +gboolean +gst_v4l2_decoder_streamoff (GstV4l2Decoder * self, GstPadDirection direction) +{ + gint ret; + guint32 type = direction_to_buffer_type (direction); + + ret = ioctl (self->video_fd, VIDIOC_STREAMOFF, &type); + if (ret < 0) { + GST_ERROR_OBJECT (self, "VIDIOC_STREAMOFF failed: %s", g_strerror (errno)); + return FALSE; + } + + return TRUE; +} + gboolean gst_v4l2_decoder_enum_sink_fmt (GstV4l2Decoder * self, gint i, guint32 * out_fmt) @@ -239,15 +281,6 @@ gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstVideoInfo * info) return TRUE; } -static guint32 -direction_to_buffer_type (GstPadDirection direction) -{ - if (direction == GST_PAD_SRC) - return V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - else - return V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; -} - gint gst_v4l2_decoder_request_buffers (GstV4l2Decoder * self, GstPadDirection direction, guint num_buffers) @@ -381,6 +414,49 @@ gst_v4l2_decoder_queue_src_buffer (GstV4l2Decoder * self, GstBuffer * buffer, return TRUE; } +gboolean +gst_v4l2_decoder_dequeue_sink (GstV4l2Decoder * self) +{ + gint ret; + struct v4l2_plane plane[GST_VIDEO_MAX_PLANES] = { {0} }; + struct v4l2_buffer buf = { + .type = direction_to_buffer_type (GST_PAD_SINK), + .memory = V4L2_MEMORY_MMAP, + .length = GST_VIDEO_MAX_PLANES, + .m.planes = plane, + }; + + ret = ioctl (self->video_fd, VIDIOC_DQBUF, &buf); + if (ret < 0) { + GST_ERROR_OBJECT (self, "VIDIOC_DQBUF failed: %s", g_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +gboolean +gst_v4l2_decoder_dequeue_src (GstV4l2Decoder * self, guint32 * out_frame_num) +{ + gint ret; + struct v4l2_plane plane[GST_VIDEO_MAX_PLANES] = { {0} }; + struct v4l2_buffer buf = { + .type = direction_to_buffer_type (GST_PAD_SRC), + .memory = V4L2_MEMORY_MMAP, + .length = GST_VIDEO_MAX_PLANES, + .m.planes = plane, + }; + + ret = ioctl (self->video_fd, VIDIOC_DQBUF, &buf); + if (ret < 0) { + GST_ERROR_OBJECT (self, "VIDIOC_DQBUF failed: %s", g_strerror (errno)); + return FALSE; + } + + *out_frame_num = buf.timestamp.tv_usec; + return TRUE; +} + gboolean gst_v4l2_decoder_set_controls (GstV4l2Decoder * self, GstV4l2Request * request, struct v4l2_ext_control * control, guint count) @@ -481,6 +557,12 @@ gst_v4l2_decoder_alloc_request (GstV4l2Decoder * self) g_strerror (errno)); return NULL; } + + request->poll = gst_poll_new (FALSE); + gst_poll_fd_init (&request->pollfd); + request->pollfd.fd = request->fd; + gst_poll_add_fd (request->poll, &request->pollfd); + gst_poll_fd_ctl_pri (request->poll, &request->pollfd, TRUE); } request->decoder = g_object_ref (self); @@ -490,29 +572,34 @@ gst_v4l2_decoder_alloc_request (GstV4l2Decoder * self) void gst_v4l2_request_free (GstV4l2Request * request) { - GstV4l2Decoder *decoder; + GstV4l2Decoder *decoder = request->decoder; gint ret; - if (!request->decoder) { + if (!decoder) { close (request->fd); + gst_poll_free (request->poll); g_free (request); return; } - if (request->bitstream) - g_clear_pointer (&request->bitstream, gst_memory_unref); + g_clear_pointer (&request->bitstream, gst_memory_unref); + request->decoder = NULL; + + if (request->pending) { + gst_v4l2_request_free (request); + g_object_unref (decoder); + return; + } ret = ioctl (request->fd, MEDIA_REQUEST_IOC_REINIT, NULL); if (ret < 0) { GST_ERROR_OBJECT (request->decoder, "MEDIA_REQUEST_IOC_REINIT failed: %s", g_strerror (errno)); - request->decoder = NULL; gst_v4l2_request_free (request); + g_object_unref (decoder); return; } - decoder = request->decoder; - request->decoder = NULL; gst_atomic_queue_push (decoder->request_pool, request); g_object_unref (decoder); } @@ -529,5 +616,30 @@ gst_v4l2_request_queue (GstV4l2Request * request) return FALSE; } + request->pending = TRUE; + return TRUE; } + +gint +gst_v4l2_request_poll (GstV4l2Request * request, GstClockTime timeout) +{ + return gst_poll_wait (request->poll, timeout); +} + +void +gst_v4l2_request_set_done (GstV4l2Request * request) +{ + if (request->bitstream) { + gst_v4l2_decoder_dequeue_sink (request->decoder); + g_clear_pointer (&request->bitstream, gst_memory_unref); + } + + request->pending = FALSE; +} + +gboolean +gst_v4l2_request_is_done (GstV4l2Request * request) +{ + return !request->pending; +} diff --git a/sys/v4l2codecs/gstv4l2decoder.h b/sys/v4l2codecs/gstv4l2decoder.h index c3c93e4f98..33faed2af9 100644 --- a/sys/v4l2codecs/gstv4l2decoder.h +++ b/sys/v4l2codecs/gstv4l2decoder.h @@ -39,6 +39,12 @@ gboolean gst_v4l2_decoder_open (GstV4l2Decoder * decoder); gboolean gst_v4l2_decoder_close (GstV4l2Decoder * decoder); +gboolean gst_v4l2_decoder_streamon (GstV4l2Decoder * self, + GstPadDirection direction); + +gboolean gst_v4l2_decoder_streamoff (GstV4l2Decoder * self, + GstPadDirection direction); + gboolean gst_v4l2_decoder_enum_sink_fmt (GstV4l2Decoder * self, gint i, guint32 * out_fmt); @@ -65,10 +71,15 @@ gboolean gst_v4l2_decoder_queue_sink_mem (GstV4l2Decoder * self, GstMemory * mem, guint32 frame_num); +gboolean gst_v4l2_decoder_dequeue_sink (GstV4l2Decoder * self); + gboolean gst_v4l2_decoder_queue_src_buffer (GstV4l2Decoder * self, GstBuffer * buffer, guint32 frame_num); +gboolean gst_v4l2_decoder_dequeue_src (GstV4l2Decoder * self, + guint32 *out_frame_num); + gboolean gst_v4l2_decoder_set_controls (GstV4l2Decoder * self, GstV4l2Request * request, struct v4l2_ext_control *control, @@ -90,6 +101,12 @@ void gst_v4l2_request_free (GstV4l2Request * request); gboolean gst_v4l2_request_queue (GstV4l2Request * request); +gint gst_v4l2_request_poll (GstV4l2Request * request, GstClockTime timeout); + +void gst_v4l2_request_set_done (GstV4l2Request * request); + +gboolean gst_v4l2_request_is_done (GstV4l2Request * request); + G_END_DECLS #endif /* __GST_V4L2_DECODER_H__ */