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:
Wim Taymans 2011-07-13 16:33:58 +02:00
parent 398001f20d
commit d9e61954a1
10 changed files with 213 additions and 327 deletions

View file

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

View file

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

View file

@ -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) \

View file

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

View file

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

View file

@ -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 {

View file

@ -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) {

View file

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

View file

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

View file

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