v4l2decoder: Add helpers to queue buffer and requests

This commit is contained in:
Nicolas Dufresne 2020-02-14 22:03:17 -05:00
parent db787adfa1
commit a307499437
2 changed files with 190 additions and 0 deletions

View file

@ -21,6 +21,8 @@
#include <config.h>
#endif
#include "gstv4l2codecallocator.h"
#include "gstv4l2codecpool.h"
#include "gstv4l2decoder.h"
#include "gstv4l2format.h"
#include "linux/media.h"
@ -41,6 +43,13 @@ enum
PROP_VIDEO_DEVICE,
};
struct _GstV4l2Request
{
GstV4l2Decoder *decoder;
gint fd;
GstMemory *bitstream;
};
struct _GstV4l2Decoder
{
GstObject parent;
@ -48,6 +57,7 @@ struct _GstV4l2Decoder
gboolean opened;
gint media_fd;
gint video_fd;
GstAtomicQueue *request_pool;
/* properties */
gchar *media_device;
@ -67,6 +77,7 @@ gst_v4l2_decoder_finalize (GObject * obj)
g_free (self->media_device);
g_free (self->video_device);
gst_atomic_queue_unref (self->request_pool);
G_OBJECT_CLASS (gst_v4l2_decoder_parent_class)->finalize (obj);
}
@ -74,6 +85,7 @@ gst_v4l2_decoder_finalize (GObject * obj)
static void
gst_v4l2_decoder_init (GstV4l2Decoder * self)
{
self->request_pool = gst_atomic_queue_new (16);
}
static void
@ -128,6 +140,11 @@ gst_v4l2_decoder_open (GstV4l2Decoder * self)
gboolean
gst_v4l2_decoder_close (GstV4l2Decoder * self)
{
GstV4l2Request *request;
while ((request = gst_atomic_queue_pop (self->request_pool)))
gst_v4l2_request_free (request);
if (self->media_fd)
close (self->media_fd);
if (self->video_fd)
@ -302,6 +319,90 @@ gst_v4l2_decoder_export_buffer (GstV4l2Decoder * self,
return TRUE;
}
gboolean
gst_v4l2_decoder_queue_sink_mem (GstV4l2Decoder * self,
GstV4l2Request * request, GstMemory * mem, guint32 frame_num)
{
gint ret;
struct v4l2_plane plane = {
.bytesused = gst_memory_get_sizes (mem, NULL, NULL),
};
struct v4l2_buffer buf = {
.type = direction_to_buffer_type (GST_PAD_SINK),
.memory = V4L2_MEMORY_MMAP,
.index = gst_v4l2_codec_memory_get_index (mem),
.timestamp.tv_usec = frame_num,
.request_fd = request->fd,
.flags = V4L2_BUF_FLAG_REQUEST_FD,
.length = 1,
.m.planes = &plane,
};
ret = ioctl (self->video_fd, VIDIOC_QBUF, &buf);
if (ret < 0) {
GST_ERROR_OBJECT (self, "VIDIOC_QBUF failed: %s", g_strerror (errno));
return FALSE;
}
request->bitstream = gst_memory_ref (mem);
return TRUE;
}
gboolean
gst_v4l2_decoder_queue_src_buffer (GstV4l2Decoder * self, GstBuffer * buffer,
guint32 frame_num)
{
gint i, ret;
struct v4l2_plane plane[GST_VIDEO_MAX_PLANES];
struct v4l2_buffer buf = {
.type = direction_to_buffer_type (GST_PAD_SRC),
.memory = V4L2_MEMORY_MMAP,
.index = gst_v4l2_codec_buffer_get_index (buffer),
.length = gst_buffer_n_memory (buffer),
.m.planes = plane,
};
for (i = 0; i < buf.length; i++) {
GstMemory *mem = gst_buffer_peek_memory (buffer, i);
/* *INDENT-OFF* */
plane[i] = (struct v4l2_plane) {
.bytesused = gst_memory_get_sizes (mem, NULL, NULL),
};
/* *INDENT-ON* */
}
ret = ioctl (self->video_fd, VIDIOC_QBUF, &buf);
if (ret < 0) {
GST_ERROR_OBJECT (self, "VIDIOC_QBUF failed: %s", g_strerror (errno));
return FALSE;
}
return TRUE;
}
gboolean
gst_v4l2_decoder_set_controls (GstV4l2Decoder * self, GstV4l2Request * request,
struct v4l2_ext_control * control, guint count)
{
gint ret;
struct v4l2_ext_controls controls = {
.controls = control,
.count = count,
.request_fd = request->fd,
.which = V4L2_CTRL_WHICH_REQUEST_VAL,
};
ret = ioctl (self->video_fd, VIDIOC_S_EXT_CTRLS, &controls);
if (ret < 0) {
GST_ERROR_OBJECT (self, "VIDIOC_S_EXT_CTRLS failed: %s",
g_strerror (errno));
return FALSE;
}
return TRUE;
}
void
gst_v4l2_decoder_install_properties (GObjectClass * gobject_class,
gint prop_offset, GstV4l2CodecDevice * device)
@ -364,3 +465,69 @@ gst_v4l2_decoder_get_property (GObject * object, guint prop_id,
break;
}
}
GstV4l2Request *
gst_v4l2_decoder_alloc_request (GstV4l2Decoder * self)
{
GstV4l2Request *request = gst_atomic_queue_pop (self->request_pool);
gint ret;
if (!request) {
request = g_new0 (GstV4l2Request, 1);
ret = ioctl (self->media_fd, MEDIA_IOC_REQUEST_ALLOC, &request->fd);
if (ret < 0) {
GST_ERROR_OBJECT (self, "MEDIA_IOC_REQUEST_ALLOC failed: %s",
g_strerror (errno));
return NULL;
}
}
request->decoder = g_object_ref (self);
return request;
}
void
gst_v4l2_request_free (GstV4l2Request * request)
{
GstV4l2Decoder *decoder;
gint ret;
if (!request->decoder) {
close (request->fd);
g_free (request);
return;
}
if (request->bitstream)
g_clear_pointer (&request->bitstream, gst_memory_unref);
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);
return;
}
decoder = request->decoder;
request->decoder = NULL;
gst_atomic_queue_push (decoder->request_pool, request);
g_object_unref (decoder);
}
gboolean
gst_v4l2_request_queue (GstV4l2Request * request)
{
gint ret;
ret = ioctl (request->fd, MEDIA_REQUEST_IOC_QUEUE, NULL);
if (ret < 0) {
GST_ERROR_OBJECT (request->decoder, "MEDIA_REQUEST_IOC_QUEUE, failed: %s",
g_strerror (errno));
return FALSE;
}
return TRUE;
}

View file

@ -24,12 +24,15 @@
#include <gst/video/video.h>
#include "gstv4l2codecdevice.h"
#include "linux/videodev2.h"
G_BEGIN_DECLS
#define GST_TYPE_V4L2_DECODER gst_v4l2_decoder_get_type ()
G_DECLARE_FINAL_TYPE (GstV4l2Decoder, gst_v4l2_decoder, GST, V4L2_DECODER, GstObject);
typedef struct _GstV4l2Request GstV4l2Request;
GstV4l2Decoder * gst_v4l2_decoder_new (GstV4l2CodecDevice * device);
gboolean gst_v4l2_decoder_open (GstV4l2Decoder * decoder);
@ -57,6 +60,20 @@ gboolean gst_v4l2_decoder_export_buffer (GstV4l2Decoder * self,
gsize * offsets,
guint *num_fds);
gboolean gst_v4l2_decoder_queue_sink_mem (GstV4l2Decoder * self,
GstV4l2Request * request,
GstMemory * mem,
guint32 frame_num);
gboolean gst_v4l2_decoder_queue_src_buffer (GstV4l2Decoder * self,
GstBuffer * buffer,
guint32 frame_num);
gboolean gst_v4l2_decoder_set_controls (GstV4l2Decoder * self,
GstV4l2Request * request,
struct v4l2_ext_control *control,
guint count);
void gst_v4l2_decoder_install_properties (GObjectClass * gobject_class,
gint prop_offset,
GstV4l2CodecDevice * device);
@ -67,6 +84,12 @@ void gst_v4l2_decoder_set_property (GObject * object, guint prop_id
void gst_v4l2_decoder_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
GstV4l2Request *gst_v4l2_decoder_alloc_request (GstV4l2Decoder * self);
void gst_v4l2_request_free (GstV4l2Request * request);
gboolean gst_v4l2_request_queue (GstV4l2Request * request);
G_END_DECLS
#endif /* __GST_V4L2_DECODER_H__ */