mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
v4l2: Let the device object manage the pool
Rename start and stop methods to open and close because that is what they do. After setting the format on the device object, setup the bufferpools. Move this code from the v4l2src_calls.c file, it is shared between source and sink. Make new device start and stop method that merges various bits of common code spread over several files.
This commit is contained in:
parent
398001f20d
commit
d9e61954a1
10 changed files with 213 additions and 327 deletions
|
@ -22,11 +22,17 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GSTV4L2BUFFER_H__
|
||||
#define __GSTV4L2BUFFER_H__
|
||||
#ifndef __GST_V4L2_BUFFER_POOL_H__
|
||||
#define __GST_V4L2_BUFFER_POOL_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "v4l2_calls.h"
|
||||
|
||||
typedef struct _GstV4l2BufferPool GstV4l2BufferPool;
|
||||
typedef struct _GstV4l2BufferPoolClass GstV4l2BufferPoolClass;
|
||||
typedef struct _GstMetaV4l2 GstMetaV4l2;
|
||||
|
||||
#include "gstv4l2object.h"
|
||||
//#include "v4l2_calls.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (v4l2buffer_debug);
|
||||
|
||||
|
@ -38,10 +44,6 @@ GType gst_v4l2_buffer_pool_get_type (void);
|
|||
#define GST_IS_V4L2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_BUFFER_POOL))
|
||||
#define GST_V4L2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_BUFFER_POOL, GstV4l2BufferPool))
|
||||
|
||||
typedef struct _GstV4l2BufferPool GstV4l2BufferPool;
|
||||
typedef struct _GstV4l2BufferPoolClass GstV4l2BufferPoolClass;
|
||||
typedef struct _GstMetaV4l2 GstMetaV4l2;
|
||||
|
||||
#define GST_V4L2_BUFFER_POOL_LOCK(pool) g_mutex_lock ((pool)->lock)
|
||||
#define GST_V4L2_BUFFER_POOL_UNLOCK(pool) g_mutex_unlock ((pool)->lock)
|
||||
|
||||
|
@ -91,4 +93,4 @@ gint gst_v4l2_buffer_pool_available_buffers (GstV4l2BufferPool *p
|
|||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSTV4L2BUFFER_H__ */
|
||||
#endif /*__GST_V4L2_BUFFER_POOL_H__ */
|
||||
|
|
|
@ -751,7 +751,7 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
|
|||
}
|
||||
|
||||
gboolean
|
||||
gst_v4l2_object_start (GstV4l2Object * v4l2object)
|
||||
gst_v4l2_object_open (GstV4l2Object * v4l2object)
|
||||
{
|
||||
if (gst_v4l2_open (v4l2object))
|
||||
gst_v4l2_set_defaults (v4l2object);
|
||||
|
@ -766,7 +766,7 @@ gst_v4l2_object_start (GstV4l2Object * v4l2object)
|
|||
}
|
||||
|
||||
gboolean
|
||||
gst_v4l2_object_stop (GstV4l2Object * v4l2object)
|
||||
gst_v4l2_object_close (GstV4l2Object * v4l2object)
|
||||
{
|
||||
#ifdef HAVE_XVIDEO
|
||||
gst_v4l2_xoverlay_stop (v4l2object);
|
||||
|
@ -2041,6 +2041,65 @@ gst_v4l2_object_get_nearest_size (GstV4l2Object * v4l2object,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_v4l2_object_setup_pool (GstV4l2Object * v4l2object)
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "initializing the capture system");
|
||||
|
||||
GST_V4L2_CHECK_OPEN (v4l2object);
|
||||
GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
|
||||
|
||||
if (v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
|
||||
gboolean requeuebuf;
|
||||
|
||||
requeuebuf = v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
|
||||
/* Map the buffers */
|
||||
GST_LOG_OBJECT (v4l2object->element, "initiating buffer pool");
|
||||
|
||||
if (!(v4l2object->pool = gst_v4l2_buffer_pool_new (v4l2object,
|
||||
v4l2object->num_buffers, requeuebuf)))
|
||||
goto buffer_pool_new_failed;
|
||||
|
||||
GST_INFO_OBJECT (v4l2object->element, "capturing buffers via mmap()");
|
||||
v4l2object->use_mmap = TRUE;
|
||||
|
||||
if (v4l2object->num_buffers != v4l2object->pool->buffer_count) {
|
||||
v4l2object->num_buffers = v4l2object->pool->buffer_count;
|
||||
g_object_notify (G_OBJECT (v4l2object->element), "queue-size");
|
||||
}
|
||||
|
||||
} else if (v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) {
|
||||
GST_INFO_OBJECT (v4l2object->element, "capturing buffers via read()");
|
||||
v4l2object->use_mmap = FALSE;
|
||||
v4l2object->pool = NULL;
|
||||
} else {
|
||||
goto no_supported_capture_method;
|
||||
}
|
||||
|
||||
GST_V4L2_SET_ACTIVE (v4l2object);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
buffer_pool_new_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
|
||||
(_("Could not map buffers from device '%s'"),
|
||||
v4l2object->videodev),
|
||||
("Failed to create buffer pool: %s", g_strerror (errno)));
|
||||
return FALSE;
|
||||
}
|
||||
no_supported_capture_method:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
|
||||
(_("The driver of device '%s' does not support any known capture "
|
||||
"method."), v4l2object->videodev), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Note about fraction simplification
|
||||
* * n1/d1 == n2/d2 is also written as n1 == ( n2 * d1 ) / d2
|
||||
* */
|
||||
|
@ -2198,6 +2257,10 @@ done:
|
|||
v4l2object->info = info;
|
||||
v4l2object->fmtdesc = fmtdesc;
|
||||
|
||||
/* now configure ther pools */
|
||||
if (!gst_v4l2_object_setup_pool (v4l2object))
|
||||
goto pool_failed;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
|
@ -2257,22 +2320,66 @@ get_parm_failed:
|
|||
set_parm_failed:
|
||||
{
|
||||
GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
|
||||
(_("Video input device did not accept new frame rate setting.")),
|
||||
(_("Video device did not accept new frame rate setting.")),
|
||||
GST_ERROR_SYSTEM);
|
||||
goto done;
|
||||
}
|
||||
pool_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
|
||||
(_("Video device could not create buffer pool.")), GST_ERROR_SYSTEM);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_v4l2_object_start_streaming (GstV4l2Object * v4l2object)
|
||||
gst_v4l2_object_start (GstV4l2Object * v4l2object)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "starting");
|
||||
|
||||
GST_V4L2_CHECK_OPEN (v4l2object);
|
||||
GST_V4L2_CHECK_ACTIVE (v4l2object);
|
||||
|
||||
if (v4l2object->use_mmap) {
|
||||
switch (v4l2object->type) {
|
||||
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
||||
/* for capture, queue all the buffers so the device can start filling
|
||||
* them */
|
||||
while ((buf =
|
||||
gst_v4l2_buffer_pool_get (v4l2object->pool, FALSE)) != NULL)
|
||||
if (!gst_v4l2_buffer_pool_qbuf (v4l2object->pool, buf))
|
||||
goto queue_failed;
|
||||
|
||||
if (!v4l2object->streaming) {
|
||||
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_STREAMON,
|
||||
&(v4l2object->type)) < 0)
|
||||
goto start_failed;
|
||||
|
||||
v4l2object->streaming = TRUE;
|
||||
}
|
||||
break;
|
||||
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
||||
/* for output, do nothing. We will start streaming when we get the
|
||||
* first buffer */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
queue_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
|
||||
(_("Could not enqueue buffers in device '%s'."),
|
||||
v4l2object->videodev),
|
||||
("enqueing buffer %d/%d failed: %s",
|
||||
GST_META_V4L2_GET (buf)->vbuffer.index, v4l2object->num_buffers,
|
||||
g_strerror (errno)));
|
||||
return FALSE;
|
||||
}
|
||||
start_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ,
|
||||
|
@ -2283,12 +2390,35 @@ start_failed:
|
|||
}
|
||||
|
||||
gboolean
|
||||
gst_v4l2_object_stop_streaming (GstV4l2Object * v4l2object)
|
||||
gst_v4l2_object_stop (GstV4l2Object * v4l2object)
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2object->element, "stopping");
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2object))
|
||||
goto done;
|
||||
if (!GST_V4L2_IS_ACTIVE (v4l2object))
|
||||
goto done;
|
||||
|
||||
if (v4l2object->use_mmap) {
|
||||
if (v4l2object->streaming) {
|
||||
/* we actually need to sync on all queued buffers but not
|
||||
* on the non-queued ones */
|
||||
if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_STREAMOFF,
|
||||
&(v4l2object->type)) < 0)
|
||||
goto stop_failed;
|
||||
|
||||
v4l2object->streaming = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (v4l2object->pool) {
|
||||
gst_v4l2_buffer_pool_destroy (v4l2object->pool);
|
||||
v4l2object->pool = NULL;
|
||||
}
|
||||
|
||||
GST_V4L2_SET_INACTIVE (v4l2object);
|
||||
|
||||
done:
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
|
|
|
@ -54,6 +54,11 @@
|
|||
#include <gst/video/video.h>
|
||||
#include <gst/interfaces/propertyprobe.h>
|
||||
|
||||
typedef struct _GstV4l2Object GstV4l2Object;
|
||||
typedef struct _GstV4l2ObjectClassHelper GstV4l2ObjectClassHelper;
|
||||
typedef struct _GstV4l2Xv GstV4l2Xv;
|
||||
|
||||
#include <gstv4l2bufferpool.h>
|
||||
|
||||
/* size of v4l2 buffer pool in streaming case */
|
||||
#define GST_V4L2_MAX_BUFFERS 16
|
||||
|
@ -62,15 +67,10 @@
|
|||
/* max frame width/height */
|
||||
#define GST_V4L2_MAX_SIZE (1<<15) /* 2^15 == 32768 */
|
||||
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_V4L2_OBJECT(obj) (GstV4l2Object *)(obj)
|
||||
|
||||
typedef struct _GstV4l2Object GstV4l2Object;
|
||||
typedef struct _GstV4l2ObjectClassHelper GstV4l2ObjectClassHelper;
|
||||
typedef struct _GstV4l2Xv GstV4l2Xv;
|
||||
|
||||
typedef gboolean (*GstV4l2GetInOutFunction) (GstV4l2Object * v4l2object, gint * input);
|
||||
typedef gboolean (*GstV4l2SetInOutFunction) (GstV4l2Object * v4l2object, gint input);
|
||||
|
@ -104,15 +104,21 @@ struct _GstV4l2Object {
|
|||
gboolean can_poll_device;
|
||||
|
||||
gboolean active;
|
||||
gboolean streaming;
|
||||
|
||||
/* the current format */
|
||||
struct v4l2_fmtdesc *fmtdesc;
|
||||
GstVideoInfo info;
|
||||
guint32 bytesperline;
|
||||
|
||||
guint32 bytesperline;
|
||||
guint size;
|
||||
GstClockTime duration;
|
||||
|
||||
/* optional pool */
|
||||
guint32 num_buffers;
|
||||
gboolean use_mmap;
|
||||
GstV4l2BufferPool *pool;
|
||||
|
||||
/* the video device's capabilities */
|
||||
struct v4l2_capability vcap;
|
||||
|
||||
|
@ -181,9 +187,9 @@ gboolean gst_v4l2_object_set_property_helper (GstV4l2Object *v4l2object,
|
|||
gboolean gst_v4l2_object_get_property_helper (GstV4l2Object *v4l2object,
|
||||
guint prop_id, GValue * value,
|
||||
GParamSpec * pspec);
|
||||
/* starting/stopping */
|
||||
gboolean gst_v4l2_object_start (GstV4l2Object *v4l2object);
|
||||
gboolean gst_v4l2_object_stop (GstV4l2Object *v4l2object);
|
||||
/* open/close */
|
||||
gboolean gst_v4l2_object_open (GstV4l2Object *v4l2object);
|
||||
gboolean gst_v4l2_object_close (GstV4l2Object *v4l2object);
|
||||
|
||||
/* probing */
|
||||
const GList* gst_v4l2_probe_get_properties (GstPropertyProbe * probe);
|
||||
|
@ -209,8 +215,8 @@ GstStructure* gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc);
|
|||
|
||||
gboolean gst_v4l2_object_set_format (GstV4l2Object *v4l2object, GstCaps * caps);
|
||||
|
||||
gboolean gst_v4l2_object_start_streaming (GstV4l2Object *v4l2object);
|
||||
gboolean gst_v4l2_object_stop_streaming (GstV4l2Object *v4l2object);
|
||||
gboolean gst_v4l2_object_start (GstV4l2Object *v4l2object);
|
||||
gboolean gst_v4l2_object_stop (GstV4l2Object *v4l2object);
|
||||
|
||||
|
||||
#define GST_IMPLEMENT_V4L2_PROBE_METHODS(Type_Class, interface_as_function) \
|
||||
|
|
|
@ -417,7 +417,7 @@ gst_v4l2radio_start (GstV4l2Radio * radio)
|
|||
static gboolean
|
||||
gst_v4l2radio_stop (GstV4l2Radio * radio)
|
||||
{
|
||||
if (!gst_v4l2_object_stop (radio->v4l2object))
|
||||
if (!gst_v4l2_object_close (radio->v4l2object))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
|
|
|
@ -246,7 +246,7 @@ gst_v4l2sink_init (GstV4l2Sink * v4l2sink)
|
|||
g_object_set (v4l2sink, "device", "/dev/video1", NULL);
|
||||
|
||||
/* number of buffers requested */
|
||||
v4l2sink->num_buffers = PROP_DEF_QUEUE_SIZE;
|
||||
v4l2sink->v4l2object->num_buffers = PROP_DEF_QUEUE_SIZE;
|
||||
v4l2sink->min_queued_bufs = PROP_DEF_MIN_QUEUED_BUFS;
|
||||
|
||||
v4l2sink->probed_caps = NULL;
|
||||
|
@ -254,7 +254,6 @@ gst_v4l2sink_init (GstV4l2Sink * v4l2sink)
|
|||
|
||||
v4l2sink->overlay_fields_set = 0;
|
||||
v4l2sink->crop_fields_set = 0;
|
||||
v4l2sink->state = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -284,16 +283,6 @@ gst_v4l2sink_finalize (GstV4l2Sink * v4l2sink)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* State values
|
||||
*/
|
||||
enum
|
||||
{
|
||||
STATE_OFF = 0,
|
||||
STATE_PENDING_STREAMON,
|
||||
STATE_STREAMING
|
||||
};
|
||||
|
||||
/*
|
||||
* flags to indicate which overlay/crop properties the user has set (and
|
||||
* therefore which ones should override the defaults from the driver)
|
||||
|
@ -405,7 +394,7 @@ gst_v4l2sink_set_property (GObject * object,
|
|||
prop_id, value, pspec)) {
|
||||
switch (prop_id) {
|
||||
case PROP_QUEUE_SIZE:
|
||||
v4l2sink->num_buffers = g_value_get_uint (value);
|
||||
v4l2sink->v4l2object->num_buffers = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_MIN_QUEUED_BUFS:
|
||||
v4l2sink->min_queued_bufs = g_value_get_uint (value);
|
||||
|
@ -468,7 +457,7 @@ gst_v4l2sink_get_property (GObject * object,
|
|||
prop_id, value, pspec)) {
|
||||
switch (prop_id) {
|
||||
case PROP_QUEUE_SIZE:
|
||||
g_value_set_uint (value, v4l2sink->num_buffers);
|
||||
g_value_set_uint (value, v4l2sink->v4l2object->num_buffers);
|
||||
break;
|
||||
case PROP_MIN_QUEUED_BUFS:
|
||||
g_value_set_uint (value, v4l2sink->min_queued_bufs);
|
||||
|
@ -517,7 +506,7 @@ gst_v4l2sink_change_state (GstElement * element, GstStateChange transition)
|
|||
switch (transition) {
|
||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||
/* open the device */
|
||||
if (!gst_v4l2_object_start (v4l2sink->v4l2object))
|
||||
if (!gst_v4l2_object_open (v4l2sink->v4l2object))
|
||||
return GST_STATE_CHANGE_FAILURE;
|
||||
break;
|
||||
default:
|
||||
|
@ -528,21 +517,19 @@ gst_v4l2sink_change_state (GstElement * element, GstStateChange transition)
|
|||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
#if 0
|
||||
if (v4l2sink->state == STATE_STREAMING) {
|
||||
if (!gst_v4l2_object_stop_streaming (v4l2sink->v4l2object)) {
|
||||
return GST_STATE_CHANGE_FAILURE;
|
||||
}
|
||||
v4l2sink->state = STATE_PENDING_STREAMON;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
if (NULL != v4l2sink->pool)
|
||||
gst_v4l2_buffer_pool_destroy (v4l2sink->pool);
|
||||
v4l2sink->pool = NULL;
|
||||
/* close the device */
|
||||
if (!gst_v4l2_object_stop (v4l2sink->v4l2object))
|
||||
if (!gst_v4l2_object_close (v4l2sink->v4l2object))
|
||||
return GST_STATE_CHANGE_FAILURE;
|
||||
v4l2sink->state = STATE_OFF;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -617,7 +604,7 @@ static gboolean
|
|||
gst_v4l2sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||
{
|
||||
GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink);
|
||||
GstV4l2BufferPool *newpool;
|
||||
GstV4l2Object *obj = v4l2sink->v4l2object;
|
||||
|
||||
LOG_CAPS (v4l2sink, caps);
|
||||
|
||||
|
@ -636,31 +623,12 @@ gst_v4l2sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
|||
GST_DEBUG_OBJECT (v4l2sink, "no they aren't!");
|
||||
}
|
||||
|
||||
if (v4l2sink->pool) {
|
||||
/* we have a pool already, stop and destroy the old pool */
|
||||
if (v4l2sink->state == STATE_STREAMING) {
|
||||
if (!gst_v4l2_object_stop_streaming (v4l2sink->v4l2object))
|
||||
if (!gst_v4l2_object_stop (obj))
|
||||
goto stop_failed;
|
||||
|
||||
v4l2sink->state = STATE_PENDING_STREAMON;
|
||||
}
|
||||
gst_v4l2_buffer_pool_destroy (v4l2sink->pool);
|
||||
v4l2sink->pool = NULL;
|
||||
}
|
||||
|
||||
if (!gst_v4l2_object_set_format (v4l2sink->v4l2object, caps))
|
||||
goto invalid_format;
|
||||
|
||||
if (!(v4l2sink->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING))
|
||||
goto no_streaming;
|
||||
|
||||
newpool = gst_v4l2_buffer_pool_new (v4l2sink->v4l2object,
|
||||
v4l2sink->num_buffers, FALSE);
|
||||
if (newpool == NULL)
|
||||
goto no_pool;
|
||||
|
||||
v4l2sink->pool = newpool;
|
||||
|
||||
gst_v4l2sink_sync_overlay_fields (v4l2sink);
|
||||
gst_v4l2sink_sync_crop_fields (v4l2sink);
|
||||
|
||||
|
@ -668,15 +636,8 @@ gst_v4l2sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
|||
gst_v4l2_xoverlay_prepare_xwindow_id (v4l2sink->v4l2object, TRUE);
|
||||
#endif
|
||||
|
||||
v4l2sink->state = STATE_PENDING_STREAMON;
|
||||
|
||||
GST_INFO_OBJECT (v4l2sink, "outputting buffers via mmap()");
|
||||
|
||||
if (v4l2sink->num_buffers != v4l2sink->pool->buffer_count) {
|
||||
v4l2sink->num_buffers = v4l2sink->pool->buffer_count;
|
||||
g_object_notify (G_OBJECT (v4l2sink), "queue-size");
|
||||
}
|
||||
|
||||
v4l2sink->video_width = GST_V4L2_WIDTH (v4l2sink->v4l2object);
|
||||
v4l2sink->video_height = GST_V4L2_HEIGHT (v4l2sink->v4l2object);
|
||||
|
||||
|
@ -702,16 +663,6 @@ invalid_format:
|
|||
GST_DEBUG_OBJECT (v4l2sink, "can't set format");
|
||||
return FALSE;
|
||||
}
|
||||
no_streaming:
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2sink, "we don't support streaming");
|
||||
return FALSE;
|
||||
}
|
||||
no_pool:
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2sink, "can't create new pool");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* called after A/V sync to render frame */
|
||||
|
@ -733,7 +684,7 @@ gst_v4l2sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
|
|||
|
||||
/* not our buffer */
|
||||
GST_DEBUG_OBJECT (v4l2sink, "slow-path.. need to memcpy");
|
||||
newbuf = gst_v4l2_buffer_pool_get (v4l2sink->pool, TRUE);
|
||||
newbuf = gst_v4l2_buffer_pool_get (obj->pool, TRUE);
|
||||
|
||||
if (obj->info.finfo) {
|
||||
GstVideoFrame src_frame, dest_frame;
|
||||
|
@ -757,14 +708,13 @@ gst_v4l2sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
|
|||
buf = newbuf;
|
||||
}
|
||||
|
||||
if (!gst_v4l2_buffer_pool_qbuf (v4l2sink->pool, buf))
|
||||
if (!gst_v4l2_buffer_pool_qbuf (obj->pool, buf))
|
||||
goto queue_failed;
|
||||
|
||||
if (v4l2sink->state == STATE_PENDING_STREAMON) {
|
||||
if (!gst_v4l2_object_start_streaming (v4l2sink->v4l2object)) {
|
||||
if (!obj->streaming) {
|
||||
if (!gst_v4l2_object_start (obj)) {
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
v4l2sink->state = STATE_STREAMING;
|
||||
}
|
||||
|
||||
if (!newbuf) {
|
||||
|
@ -775,9 +725,9 @@ gst_v4l2sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
|
|||
* just queued, then dequeue one immediately to make it available via
|
||||
* _buffer_alloc():
|
||||
*/
|
||||
if (gst_v4l2_buffer_pool_available_buffers (v4l2sink->pool) >
|
||||
if (gst_v4l2_buffer_pool_available_buffers (obj->pool) >
|
||||
v4l2sink->min_queued_bufs) {
|
||||
GstBuffer *v4l2buf = gst_v4l2_buffer_pool_dqbuf (v4l2sink->pool);
|
||||
GstBuffer *v4l2buf = gst_v4l2_buffer_pool_dqbuf (obj->pool);
|
||||
|
||||
/* note: if we get a buf, we don't want to use it directly (because
|
||||
* someone else could still hold a ref).. but instead we release our
|
||||
|
|
|
@ -56,8 +56,7 @@ struct _GstV4l2Sink {
|
|||
GstV4l2Object * v4l2object;
|
||||
GstCaps *probed_caps; /* all supported caps of underlying v4l2 device */
|
||||
GstCaps *current_caps; /* the current negotiated caps */
|
||||
GstV4l2BufferPool *pool;
|
||||
guint32 num_buffers;
|
||||
|
||||
guint32 min_queued_bufs;
|
||||
|
||||
gint video_width, video_height; /* original (unscaled) video w/h */
|
||||
|
@ -73,8 +72,6 @@ struct _GstV4l2Sink {
|
|||
* setting properties:
|
||||
*/
|
||||
guint8 overlay_fields_set, crop_fields_set;
|
||||
|
||||
guint8 state;
|
||||
};
|
||||
|
||||
struct _GstV4l2SinkClass {
|
||||
|
|
|
@ -215,13 +215,11 @@ gst_v4l2src_init (GstV4l2Src * v4l2src)
|
|||
gst_v4l2_get_input, gst_v4l2_set_input, NULL);
|
||||
|
||||
/* number of buffers requested */
|
||||
v4l2src->num_buffers = PROP_DEF_QUEUE_SIZE;
|
||||
v4l2src->v4l2object->num_buffers = PROP_DEF_QUEUE_SIZE;
|
||||
|
||||
v4l2src->always_copy = PROP_DEF_ALWAYS_COPY;
|
||||
v4l2src->decimate = PROP_DEF_DECIMATE;
|
||||
|
||||
v4l2src->is_capturing = FALSE;
|
||||
|
||||
gst_base_src_set_format (GST_BASE_SRC (v4l2src), GST_FORMAT_TIME);
|
||||
gst_base_src_set_live (GST_BASE_SRC (v4l2src), TRUE);
|
||||
}
|
||||
|
@ -258,7 +256,7 @@ gst_v4l2src_set_property (GObject * object,
|
|||
prop_id, value, pspec)) {
|
||||
switch (prop_id) {
|
||||
case PROP_QUEUE_SIZE:
|
||||
v4l2src->num_buffers = g_value_get_uint (value);
|
||||
v4l2src->v4l2object->num_buffers = g_value_get_uint (value);
|
||||
break;
|
||||
case PROP_ALWAYS_COPY:
|
||||
v4l2src->always_copy = g_value_get_boolean (value);
|
||||
|
@ -283,7 +281,7 @@ gst_v4l2src_get_property (GObject * object,
|
|||
prop_id, value, pspec)) {
|
||||
switch (prop_id) {
|
||||
case PROP_QUEUE_SIZE:
|
||||
g_value_set_uint (value, v4l2src->num_buffers);
|
||||
g_value_set_uint (value, v4l2src->v4l2object->num_buffers);
|
||||
break;
|
||||
case PROP_ALWAYS_COPY:
|
||||
g_value_set_boolean (value, v4l2src->always_copy);
|
||||
|
@ -458,12 +456,16 @@ no_nego_needed:
|
|||
static GstCaps *
|
||||
gst_v4l2src_get_caps (GstBaseSrc * src, GstCaps * filter)
|
||||
{
|
||||
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
|
||||
GstV4l2Src *v4l2src;
|
||||
GstV4l2Object *obj;
|
||||
GstCaps *ret;
|
||||
GSList *walk;
|
||||
GSList *formats;
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
|
||||
v4l2src = GST_V4L2SRC (src);
|
||||
obj = v4l2src->v4l2object;
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (obj)) {
|
||||
/* FIXME: copy? */
|
||||
return
|
||||
gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD
|
||||
|
@ -473,7 +475,7 @@ gst_v4l2src_get_caps (GstBaseSrc * src, GstCaps * filter)
|
|||
if (v4l2src->probed_caps)
|
||||
return gst_caps_ref (v4l2src->probed_caps);
|
||||
|
||||
formats = gst_v4l2_object_get_format_list (v4l2src->v4l2object);
|
||||
formats = gst_v4l2_object_get_format_list (obj);
|
||||
|
||||
ret = gst_caps_new_empty ();
|
||||
|
||||
|
@ -489,7 +491,7 @@ gst_v4l2src_get_caps (GstBaseSrc * src, GstCaps * filter)
|
|||
GstCaps *tmp;
|
||||
|
||||
tmp =
|
||||
gst_v4l2_object_probe_caps_for_format (v4l2src->v4l2object,
|
||||
gst_v4l2_object_probe_caps_for_format (obj,
|
||||
format->pixelformat, template);
|
||||
if (tmp)
|
||||
gst_caps_append (ret, tmp);
|
||||
|
@ -511,40 +513,30 @@ static gboolean
|
|||
gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
|
||||
{
|
||||
GstV4l2Src *v4l2src;
|
||||
GstV4l2Object *obj;
|
||||
|
||||
v4l2src = GST_V4L2SRC (src);
|
||||
|
||||
/* if we're not open, punt -- we'll get setcaps'd later via negotiate */
|
||||
if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object))
|
||||
return FALSE;
|
||||
obj = v4l2src->v4l2object;
|
||||
|
||||
/* make sure we stop capturing and dealloc buffers */
|
||||
if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
|
||||
/* both will throw an element-error on failure */
|
||||
if (!gst_v4l2src_capture_stop (v4l2src))
|
||||
if (!gst_v4l2_object_stop (obj))
|
||||
return FALSE;
|
||||
if (!gst_v4l2src_capture_deinit (v4l2src))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!gst_v4l2_object_set_format (v4l2src->v4l2object, caps))
|
||||
if (!gst_v4l2_object_set_format (obj, caps))
|
||||
/* error already posted */
|
||||
return FALSE;
|
||||
|
||||
if (!gst_v4l2src_capture_init (v4l2src))
|
||||
return FALSE;
|
||||
|
||||
if (v4l2src->use_mmap) {
|
||||
if (obj->use_mmap) {
|
||||
v4l2src->get_frame = gst_v4l2src_get_mmap;
|
||||
} else {
|
||||
v4l2src->get_frame = gst_v4l2src_get_read;
|
||||
}
|
||||
|
||||
if (!gst_v4l2src_capture_start (v4l2src))
|
||||
if (!gst_v4l2_object_start (obj))
|
||||
return FALSE;
|
||||
|
||||
/* now store the expected output size */
|
||||
v4l2src->frame_byte_size = v4l2src->v4l2object->size;
|
||||
v4l2src->frame_byte_size = obj->size;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -584,7 +576,7 @@ gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query)
|
|||
min_latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
|
||||
|
||||
/* max latency is total duration of the frame buffer */
|
||||
max_latency = src->num_buffers * min_latency;
|
||||
max_latency = src->v4l2object->num_buffers * min_latency;
|
||||
|
||||
GST_DEBUG_OBJECT (bsrc,
|
||||
"report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
|
||||
|
@ -651,11 +643,10 @@ static gboolean
|
|||
gst_v4l2src_stop (GstBaseSrc * src)
|
||||
{
|
||||
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
|
||||
GstV4l2Object *obj = v4l2src->v4l2object;
|
||||
|
||||
if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
|
||||
if (!gst_v4l2src_capture_stop (v4l2src))
|
||||
return FALSE;
|
||||
if (!gst_v4l2src_capture_deinit (v4l2src))
|
||||
if (GST_V4L2_IS_ACTIVE (obj)) {
|
||||
if (!gst_v4l2_object_stop (obj))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
|
@ -666,11 +657,12 @@ gst_v4l2src_change_state (GstElement * element, GstStateChange transition)
|
|||
{
|
||||
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
||||
GstV4l2Src *v4l2src = GST_V4L2SRC (element);
|
||||
GstV4l2Object *obj = v4l2src->v4l2object;
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||
/* open the device */
|
||||
if (!gst_v4l2_object_start (v4l2src->v4l2object))
|
||||
if (!gst_v4l2_object_open (obj))
|
||||
return GST_STATE_CHANGE_FAILURE;
|
||||
break;
|
||||
default:
|
||||
|
@ -682,7 +674,7 @@ gst_v4l2src_change_state (GstElement * element, GstStateChange transition)
|
|||
switch (transition) {
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
/* close the device */
|
||||
if (!gst_v4l2_object_stop (v4l2src->v4l2object))
|
||||
if (!gst_v4l2_object_close (obj))
|
||||
return GST_STATE_CHANGE_FAILURE;
|
||||
|
||||
if (v4l2src->probed_caps) {
|
||||
|
|
|
@ -62,11 +62,6 @@ struct _GstV4l2Src
|
|||
/* pads */
|
||||
GstCaps *probed_caps;
|
||||
|
||||
/* buffer handling */
|
||||
GstV4l2BufferPool *pool;
|
||||
|
||||
guint32 num_buffers;
|
||||
gboolean use_mmap;
|
||||
guint32 frame_byte_size;
|
||||
|
||||
/* if the buffer will be or not used from directly mmap */
|
||||
|
@ -74,10 +69,6 @@ struct _GstV4l2Src
|
|||
|
||||
int decimate;
|
||||
|
||||
/* True if we want to stop */
|
||||
gboolean quit;
|
||||
gboolean is_capturing;
|
||||
|
||||
guint64 offset;
|
||||
|
||||
GstClockTime ctrl_time;
|
||||
|
|
|
@ -50,32 +50,6 @@
|
|||
#define GST_CAT_DEFAULT v4l2src_debug
|
||||
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
|
||||
|
||||
/* Local functions */
|
||||
|
||||
static gboolean
|
||||
gst_v4l2src_buffer_pool_activate (GstV4l2BufferPool * pool,
|
||||
GstV4l2Src * v4l2src)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
|
||||
while ((buf = gst_v4l2_buffer_pool_get (pool, FALSE)) != NULL)
|
||||
if (!gst_v4l2_buffer_pool_qbuf (pool, buf))
|
||||
goto queue_failed;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
queue_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
|
||||
(_("Could not enqueue buffers in device '%s'."),
|
||||
v4l2src->v4l2object->videodev),
|
||||
("enqueing buffer %d/%d failed: %s",
|
||||
GST_META_V4L2_GET (buf)->vbuffer.index, v4l2src->num_buffers,
|
||||
g_strerror (errno)));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_grab_frame ():
|
||||
|
@ -94,7 +68,7 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
|
|||
gint ret;
|
||||
|
||||
v4l2object = v4l2src->v4l2object;
|
||||
pool = v4l2src->pool;
|
||||
pool = v4l2object->pool;
|
||||
if (!pool)
|
||||
goto no_buffer_pool;
|
||||
|
||||
|
@ -191,152 +165,3 @@ too_many_trials:
|
|||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_capture_init():
|
||||
* initialize the capture system
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
gboolean
|
||||
gst_v4l2src_capture_init (GstV4l2Src * v4l2src)
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2src, "initializing the capture system");
|
||||
|
||||
GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
|
||||
GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
|
||||
|
||||
if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
|
||||
|
||||
/* Map the buffers */
|
||||
GST_LOG_OBJECT (v4l2src, "initiating buffer pool");
|
||||
|
||||
if (!(v4l2src->pool = gst_v4l2_buffer_pool_new (v4l2src->v4l2object,
|
||||
v4l2src->num_buffers, TRUE)))
|
||||
goto buffer_pool_new_failed;
|
||||
|
||||
GST_INFO_OBJECT (v4l2src, "capturing buffers via mmap()");
|
||||
v4l2src->use_mmap = TRUE;
|
||||
|
||||
if (v4l2src->num_buffers != v4l2src->pool->buffer_count) {
|
||||
v4l2src->num_buffers = v4l2src->pool->buffer_count;
|
||||
g_object_notify (G_OBJECT (v4l2src), "queue-size");
|
||||
}
|
||||
|
||||
} else if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) {
|
||||
GST_INFO_OBJECT (v4l2src, "capturing buffers via read()");
|
||||
v4l2src->use_mmap = FALSE;
|
||||
v4l2src->pool = NULL;
|
||||
} else {
|
||||
goto no_supported_capture_method;
|
||||
}
|
||||
|
||||
GST_V4L2_SET_ACTIVE (v4l2src->v4l2object);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
buffer_pool_new_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
|
||||
(_("Could not map buffers from device '%s'"),
|
||||
v4l2src->v4l2object->videodev),
|
||||
("Failed to create buffer pool: %s", g_strerror (errno)));
|
||||
return FALSE;
|
||||
}
|
||||
no_supported_capture_method:
|
||||
{
|
||||
GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
|
||||
(_("The driver of device '%s' does not support any known capture "
|
||||
"method."), v4l2src->v4l2object->videodev), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_capture_start():
|
||||
* start streaming capture
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
gboolean
|
||||
gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
|
||||
//GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
|
||||
GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
|
||||
|
||||
v4l2src->quit = FALSE;
|
||||
|
||||
if (v4l2src->use_mmap) {
|
||||
if (!gst_v4l2src_buffer_pool_activate (v4l2src->pool, v4l2src)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!gst_v4l2_object_start_streaming (v4l2src->v4l2object)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
v4l2src->is_capturing = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_capture_stop():
|
||||
* stop streaming capture
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
gboolean
|
||||
gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object))
|
||||
goto done;
|
||||
if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object))
|
||||
goto done;
|
||||
|
||||
if (v4l2src->use_mmap) {
|
||||
/* we actually need to sync on all queued buffers but not
|
||||
* on the non-queued ones */
|
||||
if (!gst_v4l2_object_stop_streaming (v4l2src->v4l2object)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
/* make an optional pending wait stop */
|
||||
v4l2src->quit = TRUE;
|
||||
v4l2src->is_capturing = FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************
|
||||
* gst_v4l2src_capture_deinit():
|
||||
* deinitialize the capture system
|
||||
* return value: TRUE on success, FALSE on error
|
||||
******************************************************/
|
||||
gboolean
|
||||
gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
|
||||
{
|
||||
GST_DEBUG_OBJECT (v4l2src, "deinitting capture system");
|
||||
|
||||
if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
|
||||
return TRUE;
|
||||
}
|
||||
if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (v4l2src->pool) {
|
||||
gst_v4l2_buffer_pool_destroy (v4l2src->pool);
|
||||
v4l2src->pool = NULL;
|
||||
}
|
||||
|
||||
GST_V4L2_SET_INACTIVE (v4l2src->v4l2object);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -27,13 +27,6 @@
|
|||
#include "gstv4l2src.h"
|
||||
#include "v4l2_calls.h"
|
||||
|
||||
gboolean gst_v4l2src_capture_init (GstV4l2Src * v4l2src);
|
||||
gboolean gst_v4l2src_capture_start (GstV4l2Src * v4l2src);
|
||||
|
||||
GstFlowReturn gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer **buf);
|
||||
|
||||
gboolean gst_v4l2src_capture_stop (GstV4l2Src * v4l2src);
|
||||
gboolean gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src);
|
||||
|
||||
|
||||
#endif /* __V4L2SRC_CALLS_H__ */
|
||||
|
|
Loading…
Reference in a new issue