mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-30 04:45:36 +00:00
v4l2codecdecoder: Add support for dequeuing buffers
This includings polling of the request and streamon/streamoff.
This commit is contained in:
parent
4305771178
commit
3cc6643050
2 changed files with 146 additions and 17 deletions
|
@ -48,6 +48,9 @@ struct _GstV4l2Request
|
||||||
GstV4l2Decoder *decoder;
|
GstV4l2Decoder *decoder;
|
||||||
gint fd;
|
gint fd;
|
||||||
GstMemory *bitstream;
|
GstMemory *bitstream;
|
||||||
|
GstPoll *poll;
|
||||||
|
GstPollFD pollfd;
|
||||||
|
gboolean pending;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstV4l2Decoder
|
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,
|
GST_DEBUG_CATEGORY_INIT (v4l2_decoder_debug, "v4l2codecs-decoder", 0,
|
||||||
"V4L2 stateless decoder helper"));
|
"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
|
static void
|
||||||
gst_v4l2_decoder_finalize (GObject * obj)
|
gst_v4l2_decoder_finalize (GObject * obj)
|
||||||
{
|
{
|
||||||
|
@ -125,7 +137,7 @@ gst_v4l2_decoder_open (GstV4l2Decoder * self)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->video_fd = open (self->video_device, 0);
|
self->video_fd = open (self->video_device, O_NONBLOCK);
|
||||||
if (self->video_fd < 0) {
|
if (self->video_fd < 0) {
|
||||||
GST_ERROR_OBJECT (self, "Failed to open '%s': %s",
|
GST_ERROR_OBJECT (self, "Failed to open '%s': %s",
|
||||||
self->video_device, g_strerror (errno));
|
self->video_device, g_strerror (errno));
|
||||||
|
@ -157,6 +169,36 @@ gst_v4l2_decoder_close (GstV4l2Decoder * self)
|
||||||
return TRUE;
|
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
|
gboolean
|
||||||
gst_v4l2_decoder_enum_sink_fmt (GstV4l2Decoder * self, gint i,
|
gst_v4l2_decoder_enum_sink_fmt (GstV4l2Decoder * self, gint i,
|
||||||
guint32 * out_fmt)
|
guint32 * out_fmt)
|
||||||
|
@ -239,15 +281,6 @@ gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstVideoInfo * info)
|
||||||
return TRUE;
|
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
|
gint
|
||||||
gst_v4l2_decoder_request_buffers (GstV4l2Decoder * self,
|
gst_v4l2_decoder_request_buffers (GstV4l2Decoder * self,
|
||||||
GstPadDirection direction, guint num_buffers)
|
GstPadDirection direction, guint num_buffers)
|
||||||
|
@ -381,6 +414,49 @@ gst_v4l2_decoder_queue_src_buffer (GstV4l2Decoder * self, GstBuffer * buffer,
|
||||||
return TRUE;
|
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
|
gboolean
|
||||||
gst_v4l2_decoder_set_controls (GstV4l2Decoder * self, GstV4l2Request * request,
|
gst_v4l2_decoder_set_controls (GstV4l2Decoder * self, GstV4l2Request * request,
|
||||||
struct v4l2_ext_control * control, guint count)
|
struct v4l2_ext_control * control, guint count)
|
||||||
|
@ -481,6 +557,12 @@ gst_v4l2_decoder_alloc_request (GstV4l2Decoder * self)
|
||||||
g_strerror (errno));
|
g_strerror (errno));
|
||||||
return NULL;
|
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);
|
request->decoder = g_object_ref (self);
|
||||||
|
@ -490,29 +572,34 @@ gst_v4l2_decoder_alloc_request (GstV4l2Decoder * self)
|
||||||
void
|
void
|
||||||
gst_v4l2_request_free (GstV4l2Request * request)
|
gst_v4l2_request_free (GstV4l2Request * request)
|
||||||
{
|
{
|
||||||
GstV4l2Decoder *decoder;
|
GstV4l2Decoder *decoder = request->decoder;
|
||||||
gint ret;
|
gint ret;
|
||||||
|
|
||||||
if (!request->decoder) {
|
if (!decoder) {
|
||||||
close (request->fd);
|
close (request->fd);
|
||||||
|
gst_poll_free (request->poll);
|
||||||
g_free (request);
|
g_free (request);
|
||||||
return;
|
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);
|
ret = ioctl (request->fd, MEDIA_REQUEST_IOC_REINIT, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
GST_ERROR_OBJECT (request->decoder, "MEDIA_REQUEST_IOC_REINIT failed: %s",
|
GST_ERROR_OBJECT (request->decoder, "MEDIA_REQUEST_IOC_REINIT failed: %s",
|
||||||
g_strerror (errno));
|
g_strerror (errno));
|
||||||
request->decoder = NULL;
|
|
||||||
gst_v4l2_request_free (request);
|
gst_v4l2_request_free (request);
|
||||||
|
g_object_unref (decoder);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder = request->decoder;
|
|
||||||
request->decoder = NULL;
|
|
||||||
gst_atomic_queue_push (decoder->request_pool, request);
|
gst_atomic_queue_push (decoder->request_pool, request);
|
||||||
g_object_unref (decoder);
|
g_object_unref (decoder);
|
||||||
}
|
}
|
||||||
|
@ -529,5 +616,30 @@ gst_v4l2_request_queue (GstV4l2Request * request)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request->pending = TRUE;
|
||||||
|
|
||||||
return 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;
|
||||||
|
}
|
||||||
|
|
|
@ -39,6 +39,12 @@ gboolean gst_v4l2_decoder_open (GstV4l2Decoder * decoder);
|
||||||
|
|
||||||
gboolean gst_v4l2_decoder_close (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,
|
gboolean gst_v4l2_decoder_enum_sink_fmt (GstV4l2Decoder * self,
|
||||||
gint i, guint32 * out_fmt);
|
gint i, guint32 * out_fmt);
|
||||||
|
|
||||||
|
@ -65,10 +71,15 @@ gboolean gst_v4l2_decoder_queue_sink_mem (GstV4l2Decoder * self,
|
||||||
GstMemory * mem,
|
GstMemory * mem,
|
||||||
guint32 frame_num);
|
guint32 frame_num);
|
||||||
|
|
||||||
|
gboolean gst_v4l2_decoder_dequeue_sink (GstV4l2Decoder * self);
|
||||||
|
|
||||||
gboolean gst_v4l2_decoder_queue_src_buffer (GstV4l2Decoder * self,
|
gboolean gst_v4l2_decoder_queue_src_buffer (GstV4l2Decoder * self,
|
||||||
GstBuffer * buffer,
|
GstBuffer * buffer,
|
||||||
guint32 frame_num);
|
guint32 frame_num);
|
||||||
|
|
||||||
|
gboolean gst_v4l2_decoder_dequeue_src (GstV4l2Decoder * self,
|
||||||
|
guint32 *out_frame_num);
|
||||||
|
|
||||||
gboolean gst_v4l2_decoder_set_controls (GstV4l2Decoder * self,
|
gboolean gst_v4l2_decoder_set_controls (GstV4l2Decoder * self,
|
||||||
GstV4l2Request * request,
|
GstV4l2Request * request,
|
||||||
struct v4l2_ext_control *control,
|
struct v4l2_ext_control *control,
|
||||||
|
@ -90,6 +101,12 @@ void gst_v4l2_request_free (GstV4l2Request * request);
|
||||||
|
|
||||||
gboolean gst_v4l2_request_queue (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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GST_V4L2_DECODER_H__ */
|
#endif /* __GST_V4L2_DECODER_H__ */
|
||||||
|
|
Loading…
Reference in a new issue