v4l2codecdecoder: Add support for dequeuing buffers

This includings polling of the request and streamon/streamoff.
This commit is contained in:
Nicolas Dufresne 2020-02-16 14:51:37 -05:00
parent 4305771178
commit 3cc6643050
2 changed files with 146 additions and 17 deletions

View file

@ -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;
}

View file

@ -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__ */