diff options
author | Wim Taymans <wim.taymans@collabora.co.uk> | 2009-10-14 17:58:45 +0200 |
---|---|---|
committer | Wim Taymans <wim.taymans@collabora.co.uk> | 2009-10-14 17:59:29 +0200 |
commit | 804a6aab4ff4ecee28bb962bcda2f5a16fd24c5f (patch) | |
tree | 734a1ab4d60a969ead4710b4f8562e45f1ba180c | |
parent | ad87141865d28ab74514f6da1ce244755a890022 (diff) |
v4l2src: various changesste-good-0.10.16
Use custom buffers for output.
Add properties for color balance and other effects.
-rw-r--r-- | sys/v4l2/gstv4l2bufferpool.c | 63 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2bufferpool.h | 3 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2object.c | 8 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2src.c | 311 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2src.h | 18 | ||||
-rw-r--r-- | sys/v4l2/gstv4l2xoverlay.h | 19 | ||||
-rw-r--r-- | sys/v4l2/v4l2src_calls.c | 508 | ||||
-rw-r--r-- | sys/v4l2/v4l2src_calls.h | 13 |
8 files changed, 918 insertions, 25 deletions
diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c index 494f46d73..7c2094ce7 100644 --- a/sys/v4l2/gstv4l2bufferpool.c +++ b/sys/v4l2/gstv4l2bufferpool.c @@ -35,7 +35,7 @@ #include "gstv4l2sink.h" #include "v4l2_calls.h" #include "gst/gst-i18n-plugin.h" - +#include "gsticbvideo.h" GST_DEBUG_CATEGORY_EXTERN (v4l2_debug); #define GST_CAT_DEFAULT v4l2_debug @@ -53,6 +53,7 @@ gst_v4l2_buffer_finalize (GstV4l2Buffer * buffer) GstV4l2BufferPool *pool; gboolean resuscitated = FALSE; gint index; + gboolean need_copy = FALSE; pool = buffer->pool; @@ -82,8 +83,10 @@ gst_v4l2_buffer_finalize (GstV4l2Buffer * buffer) if (resuscitated) { /* FIXME: check that the caps didn't change */ - GST_LOG_OBJECT (pool->v4l2elem, "reviving buffer %p, %d", buffer, index); - gst_buffer_ref (GST_BUFFER (buffer)); + GST_LOG ("reviving buffer %p, %d", buffer, index); + if (G_UNLIKELY (need_copy)) + gst_buffer_ref (GST_BUFFER (buffer)); + GST_BUFFER_SIZE (buffer) = 0; pool->buffers[index] = buffer; } @@ -94,13 +97,20 @@ gst_v4l2_buffer_finalize (GstV4l2Buffer * buffer) GST_LOG_OBJECT (pool->v4l2elem, "buffer %p not recovered, unmapping", buffer); gst_mini_object_unref (GST_MINI_OBJECT (pool)); - v4l2_munmap ((void *) GST_BUFFER_DATA (buffer), buffer->vbuffer.length); GST_MINI_OBJECT_CLASS (v4l2buffer_parent_class)->finalize (GST_MINI_OBJECT (buffer)); } } + +static void +gst_icb_v4l2_buffer_finalize (GstICBVideoBuffer * buffer) +{ + gst_v4l2_buffer_finalize ((GstV4l2Buffer *) buffer->ctx); +} + + static void gst_v4l2_buffer_class_init (gpointer g_class, gpointer class_data) { @@ -169,12 +179,14 @@ gst_v4l2_buffer_new (GstV4l2BufferPool * pool, guint index, GstCaps * caps) GST_LOG_OBJECT (pool->v4l2elem, " length: %u", ret->vbuffer.length); GST_LOG_OBJECT (pool->v4l2elem, " input: %u", ret->vbuffer.input); - data = (guint8 *) v4l2_mmap (0, ret->vbuffer.length, - PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd, - ret->vbuffer.m.offset); - if (data == MAP_FAILED) - goto mmap_failed; + /* get data from memory pool (this pool was previously reserved & mmap at gst_v4l2src_capture_init execution */ + if (pool->memory == NULL) + + if (data == MAP_FAILED) + goto mmap_failed; + + data = (guint8 *) pool->memory + ret->vbuffer.index * ret->vbuffer.length; GST_BUFFER_DATA (ret) = data; GST_BUFFER_SIZE (ret) = ret->vbuffer.length; @@ -316,6 +328,7 @@ gst_v4l2_buffer_pool_new (GstElement * v4l2elem, gint fd, gint num_buffers, { GstV4l2BufferPool *pool; gint n; + gint pmem_fd = 0; struct v4l2_requestbuffers breq; pool = (GstV4l2BufferPool *) gst_mini_object_new (GST_TYPE_V4L2_BUFFER_POOL); @@ -344,6 +357,16 @@ gst_v4l2_buffer_pool_new (GstElement * v4l2elem, gint fd, gint num_buffers, if (breq.count < GST_V4L2_MIN_BUFFERS) goto no_buffers; + /* the memory pool is reserved by pmem allocator */ + pmem_fd = (int) breq.reserved[0]; /* pmem file descriptor */ + pool->memorySize = (int) breq.reserved[1]; /* pmem memory size */ + pool->memory = + (guint8 *) v4l2_mmap (0, pool->memorySize, PROT_READ | PROT_WRITE, + MAP_SHARED, pmem_fd, (off_t) 0); + + if (pool->memory == NULL) + goto buffer_new_failed; + if (num_buffers != breq.count) { GST_WARNING_OBJECT (v4l2elem, "using %u buffers instead", breq.count); num_buffers = breq.count; @@ -359,6 +382,7 @@ gst_v4l2_buffer_pool_new (GstElement * v4l2elem, gint fd, gint num_buffers, /* now, map the buffers: */ for (n = 0; n < num_buffers; n++) { pool->buffers[n] = gst_v4l2_buffer_new (pool, n, caps); + if (!pool->buffers[n]) goto buffer_new_failed; pool->num_live_buffers++; @@ -421,6 +445,10 @@ gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool) GST_DEBUG_OBJECT (pool->v4l2elem, "destroy pool"); + v4l2_munmap ((void *) pool->memory, pool->memorySize); + pool->memorySize = 0; + pool->memory = NULL; + /* after this point, no more buffers will be queued or dequeued; no buffer * from pool->buffers that is NULL will be set to a buffer, and no buffer that * is not NULL will be pushed out. */ @@ -495,10 +523,13 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool) GstV4l2Object *v4l2object = get_v4l2_object (pool->v4l2elem); GstV4l2Buffer *pool_buffer; struct v4l2_buffer buffer; + video_frame_t frame = VIDEO_FRAME_INIT; + gint index; memset (&buffer, 0x00, sizeof (buffer)); buffer.type = pool->type; buffer.memory = V4L2_MEMORY_MMAP; + buffer.m.userptr = (unsigned long) &frame; if (v4l2_ioctl (pool->video_fd, VIDIOC_DQBUF, &buffer) >= 0) { @@ -508,7 +539,15 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool) /* get our GstBuffer with that index from the pool, if the buffer was * outstanding we have a serious problem. */ - pool_buffer = pool->buffers[buffer.index]; + index = buffer.index; + frame.image.semiplanar.a.vbase_address = + GST_BUFFER_DATA (pool->buffers[index]); + pool_buffer = + gst_icbvideo_buffer_new (&frame, gst_icb_v4l2_buffer_finalize, + pool->buffers[index]); + + gst_buffer_set_caps (GST_BUFFER (pool_buffer), + GST_BUFFER_CAPS (pool->buffers[index])); if (pool_buffer == NULL) { GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED, @@ -520,9 +559,9 @@ gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool) } GST_LOG_OBJECT (pool->v4l2elem, - "grabbed frame %d (ix=%d), flags %08x, pool-ct=%d, buffer=%p", + "grabbed frame %d (ix=%d), flags %08x, pool-ct=%d, buffer=%p, data=%p", buffer.sequence, buffer.index, buffer.flags, pool->num_live_buffers, - pool_buffer); + pool_buffer, GST_BUFFER_DATA (pool_buffer)); pool->num_live_buffers++; GST_DEBUG_OBJECT (pool->v4l2elem, "num_live_buffers++: %d", diff --git a/sys/v4l2/gstv4l2bufferpool.h b/sys/v4l2/gstv4l2bufferpool.h index 36a42208c..3966b5856 100644 --- a/sys/v4l2/gstv4l2bufferpool.h +++ b/sys/v4l2/gstv4l2bufferpool.h @@ -64,6 +64,9 @@ struct _GstV4l2BufferPool gint video_fd; /* a dup(2) of the v4l2object's video_fd */ guint buffer_count; GstV4l2Buffer **buffers; + + guint8* memory; + gint memorySize; }; struct _GstV4l2Buffer { diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index f73ce2183..9aa2336d3 100644 --- a/sys/v4l2/gstv4l2object.c +++ b/sys/v4l2/gstv4l2object.c @@ -1200,13 +1200,13 @@ gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps, break; case GST_MAKE_FOURCC ('N', 'V', '1', '2'): fourcc = V4L2_PIX_FMT_NV12; - outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h); - outsize += (GST_ROUND_UP_4 (*w) * *h) / 2; + outsize = GST_ROUND_UP_16 (*w) * GST_ROUND_UP_16 (*h); + outsize += (GST_ROUND_UP_16 (*w) * *h) / 2; break; case GST_MAKE_FOURCC ('N', 'V', '2', '1'): fourcc = V4L2_PIX_FMT_NV21; - outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h); - outsize += (GST_ROUND_UP_4 (*w) * *h) / 2; + outsize = GST_ROUND_UP_16 (*w) * GST_ROUND_UP_16 (*h); + outsize += (GST_ROUND_UP_16 (*w) * *h) / 2; break; #ifdef V4L2_PIX_FMT_YVYU case GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U'): diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index 463bef3a6..5b7fade38 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -79,7 +79,23 @@ enum PROP_0, V4L2_STD_OBJECT_PROPS, PROP_QUEUE_SIZE, - PROP_ALWAYS_COPY + PROP_ALWAYS_COPY, + + /* additionnal properties for Stericsson sensors */ + PROP_EFFECT, + PROP_HFLIP, + PROP_VFLIP, + PROP_BRIGHTNESS, + PROP_CONTRAST, + PROP_SATURATION, + PROP_ZOOM, + PROP_WB_MODE, + PROP_SCENE, + PROP_SENSITIVITY, + PROP_MET_EXP, + PROP_FOCUS_CTRL, + PROP_FOCUS_STATE, + PROP_FLICKER_MOD, }; GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SrcClass, gst_v4l2src); @@ -221,6 +237,32 @@ gst_v4l2src_base_init (gpointer g_class) gst_v4l2_object_get_all_caps ())); } +GType gst_v4l2src_effect_type = 0; +const GEnumValue gst_icbvideo_v4l_effects[] = GST_ICB_EFFECT_LIST; +#define DEFAULT_EFFECT 0 /* NO_FX */ +GType gst_v4l2src_wb_mode = 0; +const GEnumValue gst_icbvideo_v4l_wb_mode[] = GST_ICB_WB_MODE_LIST; +#define DEFAULT_WB_MODE 0 /* AUTO */ +GType gst_v4l2src_scene = 0; +const GEnumValue gst_icbvideo_v4l_scene[] = GST_ICB_SCENE_LIST; +#define DEFAULT_SCENE V4L2_CTRL_SCENE_AUTO +GType gst_v4l2src_sensitivity = 0; +const GEnumValue gst_icbvideo_v4l_sensitivity[] = GST_ICB_SENSITIVITY_LIST; +#define DEFAULT_SENSITIVITY V4L2_CTRL_ISO_AUTO +GType gst_v4l2src_metering_exposure = 0; +const GEnumValue gst_icbvideo_v4l_metering_exposure[] = GST_ICB_MET_EXP_LIST; +#define DEFAULT_MET_EXP V4L2_CTRL_MET_EXP_MATRIX +GType gst_v4l2src_focus_ctrl = 0; +const GEnumValue gst_icbvideo_v4l_focus_ctrl[] = GST_ICB_FOCUS_CTRL_LIST; +#define DEFAULT_FOCUS_CTRL GST_ICB_FOCUS_CTRL_OFF +GType gst_v4l2src_focus_state = 0; +const GEnumValue gst_icbvideo_v4l_focus_state[] = GST_ICB_FOCUS_STATE_LIST; +#define DEFAULT_FOCUS_STATE GST_ICB_FOCUS_STATE_NOT_FOCUSED +GType gst_v4l2src_flicker_mod = 0; +const GEnumValue gst_icbvideo_v4l_flicker_mod[] = GST_ICB_FLICKER_MOD_LIST; +#define DEFAULT_FLICKER_MOD V4L2_CID_POWER_LINE_FREQUENCY_DISABLED + + static void gst_v4l2src_class_init (GstV4l2SrcClass * klass) { @@ -264,6 +306,126 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass) basesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_v4l2src_negotiate); pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_v4l2src_create); + + /* additionnal properties for Stericsson sensors */ + if (!gst_v4l2src_effect_type) { + gst_v4l2src_effect_type = + g_enum_register_static ("GstV4l2SrcEffects", gst_icbvideo_v4l_effects); + } + + if (!gst_v4l2src_wb_mode) { + + gst_v4l2src_wb_mode = + g_enum_register_static ("GstV4l2SrcWhiteBalanceMode", + gst_icbvideo_v4l_wb_mode); + } + + if (!gst_v4l2src_scene) { + + gst_v4l2src_scene = + g_enum_register_static ("GstV4l2SrcScene", gst_icbvideo_v4l_scene); + } + + if (!gst_v4l2src_sensitivity) { + + gst_v4l2src_sensitivity = + g_enum_register_static ("GstV4l2SrcSensitivity", + gst_icbvideo_v4l_sensitivity); + } + + if (!gst_v4l2src_metering_exposure) { + + gst_v4l2src_metering_exposure = + g_enum_register_static ("GstV4l2SrcMeteringExposure", + gst_icbvideo_v4l_metering_exposure); + } + + if (!gst_v4l2src_focus_ctrl) { + + gst_v4l2src_focus_ctrl = + g_enum_register_static ("GstV4l2SrcFocusCtrl", + gst_icbvideo_v4l_focus_ctrl); + } + + if (!gst_v4l2src_focus_state) { + + gst_v4l2src_focus_state = + g_enum_register_static ("GstV4l2SrcFocusState", + gst_icbvideo_v4l_focus_state); + } + + + if (!gst_v4l2src_flicker_mod) { + + gst_v4l2src_flicker_mod = + g_enum_register_static ("GstV4l2SrcFlickerMod", + gst_icbvideo_v4l_flicker_mod); + } + + g_object_class_install_property (gobject_class, PROP_EFFECT, + g_param_spec_enum ("effect", "Effect", "Effect of the source", + gst_v4l2src_effect_type, DEFAULT_EFFECT, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_WB_MODE, + g_param_spec_enum ("wb", "White_balance_mode", + "White balancemode of the source", gst_v4l2src_wb_mode, + DEFAULT_WB_MODE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_HFLIP, + g_param_spec_boolean ("hflip", "Horizontal Flip", + "Horizontal Flip : camera configuration", 0, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_VFLIP, + g_param_spec_boolean ("vflip", "Vertical Flip", + "Vertical Flip : camera configuration", 0, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_BRIGHTNESS, + g_param_spec_int ("brightness", "Brightness", + "Brightness : camera configuration", GST_ICB_BRIGHTNESS_MIN, + GST_ICB_BRIGHTNESS_MAX, GST_ICB_BRIGHTNESS_DEFAULT, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_CONTRAST, + g_param_spec_int ("contrast", "Contrast", + "Contrast : camera configuration", GST_ICB_CONTRAST_MIN, + GST_ICB_CONTRAST_MAX, GST_ICB_CONTRAST_DEFAULT, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_SATURATION, + g_param_spec_int ("saturation", "Saturation", + "Saturation : camera configuration", GST_ICB_SATURATION_MIN, + GST_ICB_SATURATION_MAX, GST_ICB_SATURATION_DEFAULT, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_ZOOM, + g_param_spec_double ("zoom", "Zoom", + "Zoom : camera configuration", 1.0, 4.0, 1.0, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_SCENE, + g_param_spec_enum ("scene", "Scene", "Scene of the source", + gst_v4l2src_scene, DEFAULT_SCENE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_SENSITIVITY, + g_param_spec_enum ("sensitivity", "Sensitivity", + "Sensitivity of the source", gst_v4l2src_sensitivity, + DEFAULT_SENSITIVITY, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_MET_EXP, + g_param_spec_enum ("metering_exposure", "Metering exposure", + "metering exposure mode", gst_v4l2src_metering_exposure, + DEFAULT_MET_EXP, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_FOCUS_CTRL, + g_param_spec_enum ("focus control", "Focus control", "Lens focus control", + gst_v4l2src_focus_ctrl, DEFAULT_FOCUS_CTRL, G_PARAM_WRITABLE)); + + g_object_class_install_property (gobject_class, PROP_FOCUS_STATE, + g_param_spec_enum ("focus state", "Focus state", "Lens focus state", + gst_v4l2src_focus_state, DEFAULT_FOCUS_STATE, G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, PROP_FLICKER_MOD, + g_param_spec_enum ("flicker mode", "Flicker mode", "Flicker mode", + gst_v4l2src_flicker_mod, DEFAULT_FLICKER_MOD, G_PARAM_READWRITE)); + } static void @@ -286,6 +448,18 @@ gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass) v4l2src->fps_d = 0; v4l2src->fps_n = 0; + v4l2src->hflip = FALSE; + v4l2src->hflip = FALSE; + v4l2src->brightness = GST_ICB_BRIGHTNESS_DEFAULT; + v4l2src->contrast = GST_ICB_CONTRAST_DEFAULT; + v4l2src->saturation = GST_ICB_SATURATION_DEFAULT; + v4l2src->zoom = 1.0; + v4l2src->effect = DEFAULT_EFFECT; + v4l2src->wb_mode = DEFAULT_WB_MODE; + v4l2src->scene = DEFAULT_SCENE; + v4l2src->sensitivity = DEFAULT_SENSITIVITY; + v4l2src->metering_exposure = DEFAULT_MET_EXP; + } @@ -308,6 +482,20 @@ gst_v4l2src_finalize (GstV4l2Src * v4l2src) gst_v4l2_object_destroy (v4l2src->v4l2object); G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (v4l2src)); + +} + + +/* looks for the nick name from value ; return NULL if not found */ +char * +gst_v4l2src_get_enum_nick_from_value (GEnumValue * table, gint value) +{ + while (table->value_nick != NULL) { + if (table->value == value) + return (char *) table->value_nick; + table++; + } + return NULL; } @@ -326,6 +514,62 @@ gst_v4l2src_set_property (GObject * object, case PROP_ALWAYS_COPY: v4l2src->always_copy = g_value_get_boolean (value); break; + case PROP_EFFECT: + v4l2src->effect = g_value_get_enum (value); + gst_v4l2src_capture_set_effect (v4l2src, + gst_v4l2src_get_enum_nick_from_value ((GEnumValue *) + gst_icbvideo_v4l_effects, v4l2src->effect)); + break; + case PROP_WB_MODE: + v4l2src->wb_mode = g_value_get_enum (value); + gst_v4l2src_capture_set_white_balance_mode (v4l2src, + gst_v4l2src_get_enum_nick_from_value ((GEnumValue *) + gst_icbvideo_v4l_wb_mode, v4l2src->wb_mode)); + break; + case PROP_HFLIP: + v4l2src->hflip = g_value_get_boolean (value); + gst_v4l2src_capture_set_control (v4l2src, PROP_HFLIP); + break; + case PROP_VFLIP: + v4l2src->vflip = g_value_get_boolean (value); + gst_v4l2src_capture_set_control (v4l2src, PROP_VFLIP); + break; + case PROP_BRIGHTNESS: + v4l2src->brightness = g_value_get_int (value); + gst_v4l2src_capture_set_control (v4l2src, PROP_BRIGHTNESS); + break; + case PROP_CONTRAST: + v4l2src->contrast = g_value_get_int (value); + gst_v4l2src_capture_set_control (v4l2src, PROP_CONTRAST); + break; + case PROP_SATURATION: + v4l2src->saturation = g_value_get_int (value); + gst_v4l2src_capture_set_control (v4l2src, PROP_SATURATION); + break; + case PROP_ZOOM: + v4l2src->zoom = g_value_get_double (value); + gst_v4l2src_capture_set_zoom (v4l2src); + break; + case PROP_SCENE: + v4l2src->scene = g_value_get_enum (value); + gst_v4l2src_capture_set_control (v4l2src, PROP_SCENE); + break; + case PROP_SENSITIVITY: + v4l2src->sensitivity = g_value_get_enum (value); + gst_v4l2src_capture_set_control (v4l2src, PROP_SENSITIVITY); + break; + case PROP_MET_EXP: + v4l2src->metering_exposure = g_value_get_enum (value); + gst_v4l2src_capture_set_control (v4l2src, PROP_MET_EXP); + break; + case PROP_FOCUS_CTRL: + v4l2src->focus_ctrl = g_value_get_enum (value); + gst_v4l2src_capture_set_control (v4l2src, PROP_FOCUS_CTRL); + break; + case PROP_FLICKER_MOD: + v4l2src->flicker_mod = g_value_get_enum (value); + gst_v4l2src_capture_set_control (v4l2src, PROP_FLICKER_MOD); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -349,6 +593,55 @@ gst_v4l2src_get_property (GObject * object, case PROP_ALWAYS_COPY: g_value_set_boolean (value, v4l2src->always_copy); break; + case PROP_EFFECT: + g_value_set_enum (value, v4l2src->effect); + break; + case PROP_WB_MODE: + g_value_set_enum (value, v4l2src->wb_mode); + break; + case PROP_HFLIP: + gst_v4l2src_capture_get_control (v4l2src, PROP_HFLIP); + g_value_set_boolean (value, v4l2src->hflip); + break; + case PROP_VFLIP: + gst_v4l2src_capture_get_control (v4l2src, PROP_VFLIP); + g_value_set_boolean (value, v4l2src->vflip); + break; + case PROP_BRIGHTNESS: + gst_v4l2src_capture_get_control (v4l2src, PROP_BRIGHTNESS); + g_value_set_int (value, v4l2src->brightness); + break; + case PROP_CONTRAST: + gst_v4l2src_capture_get_control (v4l2src, PROP_CONTRAST); + g_value_set_int (value, v4l2src->contrast); + break; + case PROP_SATURATION: + gst_v4l2src_capture_get_control (v4l2src, PROP_SATURATION); + g_value_set_int (value, v4l2src->saturation); + break; + case PROP_ZOOM: + g_value_set_double (value, v4l2src->zoom); + break; + case PROP_SCENE: + gst_v4l2src_capture_get_control (v4l2src, PROP_SCENE); + g_value_set_enum (value, v4l2src->scene); + break; + case PROP_SENSITIVITY: + gst_v4l2src_capture_get_control (v4l2src, PROP_SENSITIVITY); + g_value_set_enum (value, v4l2src->sensitivity); + break; + case PROP_MET_EXP: + gst_v4l2src_capture_get_control (v4l2src, PROP_MET_EXP); + g_value_set_enum (value, v4l2src->metering_exposure); + break; + case PROP_FOCUS_STATE: + gst_v4l2src_capture_get_control (v4l2src, PROP_FOCUS_STATE); + g_value_set_enum (value, v4l2src->focus_state); + break; + case PROP_FLICKER_MOD: + gst_v4l2src_capture_get_control (v4l2src, PROP_FLICKER_MOD); + g_value_set_enum (value, v4l2src->flicker_mod); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -617,6 +910,22 @@ gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps) if (!gst_v4l2src_capture_init (v4l2src, caps)) return FALSE; + if (!gst_v4l2src_capture_set_all_controls (v4l2src)) + return FALSE; + + if (!gst_v4l2src_capture_set_effect (v4l2src, + gst_v4l2src_get_enum_nick_from_value ((GEnumValue *) + gst_icbvideo_v4l_effects, v4l2src->effect))) + return FALSE; + + if (!gst_v4l2src_capture_set_white_balance_mode (v4l2src, + gst_v4l2src_get_enum_nick_from_value ((GEnumValue *) + gst_icbvideo_v4l_wb_mode, v4l2src->wb_mode))) + return FALSE; + + if (!gst_v4l2src_capture_set_zoom (v4l2src)) + return FALSE; + if (!gst_v4l2src_capture_start (v4l2src)) return FALSE; diff --git a/sys/v4l2/gstv4l2src.h b/sys/v4l2/gstv4l2src.h index fef3f108c..4e52dc3c3 100644 --- a/sys/v4l2/gstv4l2src.h +++ b/sys/v4l2/gstv4l2src.h @@ -26,6 +26,7 @@ #include <gstv4l2object.h> #include <gstv4l2bufferpool.h> +#include "gsticbvideo.h" GST_DEBUG_CATEGORY_EXTERN (v4l2src_debug); @@ -80,6 +81,23 @@ struct _GstV4l2Src guint64 offset; gint fps_d, fps_n; /* framerate if device is open */ + /* additionnal properties */ + gboolean hflip; /* horizontal flip */ + gboolean vflip; /* vertical flip */ + gint brightness; + gint contrast; + gint saturation; + gdouble zoom; + + GstIcbEffect effect; /* prop effect */ + GstIcbWbMode wb_mode; /* prop white balance mode */ + gint scene; + gint sensitivity; + gint metering_exposure; + gint flicker_mod; + gint focus_ctrl; + gint focus_state; + gint focus_step; }; struct _GstV4l2SrcClass diff --git a/sys/v4l2/gstv4l2xoverlay.h b/sys/v4l2/gstv4l2xoverlay.h index 3d15ce90a..0185ebf2a 100644 --- a/sys/v4l2/gstv4l2xoverlay.h +++ b/sys/v4l2/gstv4l2xoverlay.h @@ -24,7 +24,11 @@ #ifndef __GST_V4L2_X_OVERLAY_H__ #define __GST_V4L2_X_OVERLAY_H__ +#define NO_X11 /* PLA hack */ + +#ifndef NO_X11 #include <X11/X.h> +#endif #include <gst/gst.h> #include <gst/interfaces/xoverlay.h> @@ -37,6 +41,7 @@ void gst_v4l2_xoverlay_start (GstV4l2Object *v4l2object); void gst_v4l2_xoverlay_stop (GstV4l2Object *v4l2object); void gst_v4l2_xoverlay_interface_init (GstXOverlayClass * klass); +#ifndef NO_X11 void gst_v4l2_xoverlay_set_xwindow_id (GstV4l2Object * v4l2object, XID xwindow_id); @@ -60,5 +65,19 @@ interface_as_function ## _xoverlay_interface_init (GstXOverlayClass * klass) \ gst_v4l2_xoverlay_interface_init(klass); \ } \ +#else + +#define GST_IMPLEMENT_V4L2_XOVERLAY_METHODS(Type, interface_as_function) \ + \ +static void \ +interface_as_function ## _xoverlay_interface_init (GstXOverlayClass * klass) \ +{ \ + /* default virtual functions */ \ + klass->set_xwindow_id = interface_as_function ## _xoverlay_set_xwindow_id; \ + \ + gst_v4l2_xoverlay_interface_init(klass); \ +} \ + +#endif /* NO_X11 */ #endif /* __GST_V4L2_X_OVERLAY_H__ */ diff --git a/sys/v4l2/v4l2src_calls.c b/sys/v4l2/v4l2src_calls.c index d8e365f9a..d87bdf4f1 100644 --- a/sys/v4l2/v4l2src_calls.c +++ b/sys/v4l2/v4l2src_calls.c @@ -44,12 +44,38 @@ #include "gstv4l2tuner.h" #include "gstv4l2bufferpool.h" +#include "gsticbvideo.h" #include "gst/gst-i18n-plugin.h" GST_DEBUG_CATEGORY_EXTERN (v4l2src_debug); #define GST_CAT_DEFAULT v4l2src_debug +enum +{ + PROP_0, + V4L2_STD_OBJECT_PROPS, + PROP_QUEUE_SIZE, + PROP_ALWAYS_COPY, + + /* additionnal properties for PNX sensors */ + PROP_EFFECT, + PROP_HFLIP, + PROP_VFLIP, + PROP_BRIGHTNESS, + PROP_CONTRAST, + PROP_SATURATION, + PROP_ZOOM, + PROP_WB_MODE, + PROP_SCENE, + PROP_SENSITIVITY, + PROP_MET_EXP, + PROP_FOCUS_CTRL, + PROP_FOCUS_STATE, + PROP_FLICKER_MOD, +}; + + /* lalala... */ #define GST_V4L2_SET_ACTIVE(element) (element)->buffer = GINT_TO_POINTER (-1) #define GST_V4L2_SET_INACTIVE(element) (element)->buffer = NULL @@ -125,6 +151,7 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf) } pool_buffer = GST_BUFFER (gst_v4l2_buffer_pool_dqbuf (pool)); + if (pool_buffer) break; @@ -156,6 +183,8 @@ gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf) need_copy = v4l2src->always_copy || !gst_v4l2_buffer_pool_available_buffers (pool); + need_copy = FALSE; + if (G_UNLIKELY (need_copy)) { *buf = gst_buffer_copy (pool_buffer); GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY); @@ -226,14 +255,9 @@ gst_v4l2src_set_capture (GstV4l2Src * v4l2src, guint32 pixelformat, goto done; } - /* Note: V4L2 provides the frame interval, we have the frame rate */ - if (fractions_are_equal (stream.parm.capture.timeperframe.numerator, - stream.parm.capture.timeperframe.denominator, fps_d, fps_n)) { - GST_LOG_OBJECT (v4l2src, "Desired framerate already set"); - v4l2src->fps_n = fps_n; - v4l2src->fps_d = fps_d; - goto done; - } + /* initialize default values */ + v4l2src->fps_n = stream.parm.capture.timeperframe.numerator; + v4l2src->fps_d = stream.parm.capture.timeperframe.denominator; /* We want to change the frame rate, so check whether we can. Some cheap USB * cameras don't have the capability */ @@ -416,3 +440,471 @@ gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src) return TRUE; } + +/****************************************************** + * gst_v4l2src_capture_set_all_controls(): + * set control on capture device + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2src_capture_set_all_controls (GstV4l2Src * v4l2src) +{ + struct v4l2_control control; + + GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); + GST_DEBUG_OBJECT (v4l2src, "set controls on capture device"); + + memset (&control, 0, sizeof (struct v4l2_control)); + control.id = V4L2_CID_HFLIP; + control.value = v4l2src->hflip; + + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_HFLIP"); + } + + memset (&control, 0, sizeof (struct v4l2_control)); + control.id = V4L2_CID_VFLIP; + control.value = v4l2src->vflip; + + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_VFLIP"); + } + + memset (&control, 0, sizeof (struct v4l2_control)); + control.id = V4L2_CID_SCENE; + control.value = v4l2src->scene; + + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_SCENE"); + } + + memset (&control, 0, sizeof (struct v4l2_control)); + control.id = V4L2_CID_SENSITIVITY; + control.value = v4l2src->sensitivity; + + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_SENSITIVITY"); + } + + memset (&control, 0, sizeof (struct v4l2_control)); + control.id = V4L2_CID_MET_EXP; + control.value = v4l2src->metering_exposure; + + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_MET_EXP"); + } + + memset (&control, 0, sizeof (struct v4l2_control)); + control.id = V4L2_CID_BRIGHTNESS; + control.value = v4l2src->brightness; + + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_BRIGHTNESS"); + } + + memset (&control, 0, sizeof (struct v4l2_control)); + control.id = V4L2_CID_CONTRAST; + control.value = v4l2src->contrast; + + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_CONTRAST"); + } + + memset (&control, 0, sizeof (struct v4l2_control)); + control.id = V4L2_CID_SATURATION; + control.value = v4l2src->saturation; + + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_SATURATION"); + } + + memset (&control, 0, sizeof (struct v4l2_control)); + control.id = V4L2_CID_FOCUS_AUTO; + control.value = v4l2src->focus_ctrl; + + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_FOCUS_AUTO"); + } + + memset (&control, 0, sizeof (struct v4l2_control)); + control.id = V4L2_CID_POWER_LINE_FREQUENCY; + control.value = v4l2src->flicker_mod; + + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_POWER_LINE_FREQUENCY"); + } + + return TRUE; +} + +/****************************************************** + * gst_v4l2src_capture_set_control(): + * set a specific control on capture device + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2src_capture_set_control (GstV4l2Src * v4l2src, guint prop_id) +{ + struct v4l2_control control; + + GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); + GST_DEBUG_OBJECT (v4l2src, "set control on capture device"); + + memset (&control, 0, sizeof (struct v4l2_control)); + + switch (prop_id) { + case PROP_HFLIP: + control.id = V4L2_CID_HFLIP; + control.value = v4l2src->hflip; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_HFLIP"); + } + break; + case PROP_VFLIP: + control.id = V4L2_CID_VFLIP; + control.value = v4l2src->vflip; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_VFLIP"); + } + break; + case PROP_BRIGHTNESS: + control.id = V4L2_CID_BRIGHTNESS; + control.value = v4l2src->brightness; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_BRIGHTNESS"); + } + break; + case PROP_CONTRAST: + control.id = V4L2_CID_CONTRAST; + control.value = v4l2src->contrast; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_CONTRAST"); + } + break; + case PROP_SATURATION: + control.id = V4L2_CID_SATURATION; + control.value = v4l2src->saturation; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_SATURATION"); + } + break; + case PROP_SCENE: + control.id = V4L2_CID_SCENE; + control.value = v4l2src->scene; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_SCENE"); + } + break; + case PROP_SENSITIVITY: + control.id = V4L2_CID_SENSITIVITY; + control.value = v4l2src->sensitivity; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_SENSITIVITY"); + } + break; + case PROP_MET_EXP: + control.id = V4L2_CID_MET_EXP; + control.value = v4l2src->metering_exposure; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_MET_EXP"); + } + break; + case PROP_FOCUS_CTRL: + control.id = V4L2_CID_FOCUS_AUTO; + control.value = v4l2src->focus_ctrl; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_FOCUS_AUTO"); + } + break; + case PROP_FLICKER_MOD: + control.id = V4L2_CID_POWER_LINE_FREQUENCY; + control.value = v4l2src->flicker_mod; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, + "failed to set V4L2_CID_POWER_LINE_FREQUENCY"); + } + break; + default: + break; + } + + return TRUE; +} + +/****************************************************** + * gst_v4l2src_capture_get_control(): + * get a specific control on capture device + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2src_capture_get_control (GstV4l2Src * v4l2src, guint prop_id) +{ + struct v4l2_control control; + + GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); + GST_DEBUG_OBJECT (v4l2src, "set control on capture device"); + + memset (&control, 0, sizeof (struct v4l2_control)); + + switch (prop_id) { + case PROP_HFLIP: + control.id = V4L2_CID_HFLIP; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_HFLIP"); + } + v4l2src->hflip = control.value; + break; + case PROP_VFLIP: + control.id = V4L2_CID_VFLIP; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_VFLIP"); + } + v4l2src->vflip = control.value; + break; + case PROP_BRIGHTNESS: + control.id = V4L2_CID_BRIGHTNESS; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_BRIGHTNESS"); + } + v4l2src->brightness = control.value; + break; + case PROP_CONTRAST: + control.id = V4L2_CID_CONTRAST; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_CONTRAST"); + } + v4l2src->contrast = control.value; + break; + case PROP_SATURATION: + control.id = V4L2_CID_SATURATION; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_SATURATION"); + } + v4l2src->saturation = control.value; + break; + case PROP_SCENE: + control.id = V4L2_CID_SCENE; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_SCENE"); + } + v4l2src->scene = control.value; + break; + case PROP_SENSITIVITY: + control.id = V4L2_CID_SENSITIVITY; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_SENSITIVITY"); + } + v4l2src->sensitivity = control.value; + break; + case PROP_MET_EXP: + control.id = V4L2_CID_MET_EXP; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_MET_EXP"); + } + v4l2src->metering_exposure = control.value; + break; + case PROP_FOCUS_STATE: + control.id = V4L2_CID_FOCUS_AUTO; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set V4L2_CID_FOCUS_AUTO"); + } + v4l2src->focus_ctrl = control.value; + break; + case PROP_FLICKER_MOD: + control.id = V4L2_CID_POWER_LINE_FREQUENCY; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_G_CTRL, &control) < 0) { + GST_WARNING_OBJECT (v4l2src, + "failed to set V4L2_CID_POWER_LINE_FREQUENCY"); + } + v4l2src->flicker_mod = control.value; + break; + default: + break; + } + + return TRUE; +} + + +/****************************************************** + * gst_v4l2src_capture_set_effect(): + * set effect on capture device + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2src_capture_set_effect (GstV4l2Src * v4l2src, gchar * effect_name) +{ + struct v4l2_efx v4l2_effect; + + GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); + GST_DEBUG_OBJECT (v4l2src, "set effect on capture device"); + + memset (&v4l2_effect, 0, sizeof (struct v4l2_efx)); + sprintf (v4l2_effect.efx_name, "%s", effect_name); + GST_DEBUG_OBJECT (v4l2src, "set effect: %s", effect_name); + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_EFX, &v4l2_effect) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set effect"); + } + + return TRUE; +} + +/****************************************************** + * gst_v4l2src_capture_set_white_balance_mode(): + * set white_balance mode on capture device + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2src_capture_set_white_balance_mode (GstV4l2Src * v4l2src, + gchar * wb_mode_name) +{ + struct v4l2_wb_mode wb_mode; + + GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); + GST_DEBUG_OBJECT (v4l2src, "set white balance on capture device"); + + memset (&wb_mode, 0, sizeof (struct v4l2_efx)); + sprintf (wb_mode.wb_mode_name, "%s", wb_mode_name); + GST_DEBUG_OBJECT (v4l2src, "set white balance mode: %s", wb_mode_name); + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_WBMODE, &wb_mode) < 0) { + GST_WARNING_OBJECT (v4l2src, "failed to set white balance"); + } + + return TRUE; +} + +/****************************************************** + * gst_v4l2src_capture_set_zoom(): + * set zoom value mode on capture device + * return value: TRUE on success, FALSE on error + ******************************************************/ +gboolean +gst_v4l2src_capture_set_zoom (GstV4l2Src * v4l2src) +{ + double zoom_max = 1.0; + struct v4l2_crop crop; + struct v4l2_cropcap cropcap; + +#define min(a,b) ((a) > (b) ? (b) : (a)) + + GST_V4L2_CHECK_OPEN (v4l2src->v4l2object); + GST_DEBUG_OBJECT (v4l2src, "set ZOOM on capture device"); + + + /* get crop cap */ + memset (&cropcap, 0, sizeof (struct v4l2_cropcap)); + cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_CROPCAP, &cropcap) < 0) { + GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL), + ("failed to get crop caps")); + return FALSE; + } + GST_DEBUG_OBJECT (v4l2src, "defrect: w:%d h:%d l:%d t:%d", + cropcap.defrect.width, cropcap.defrect.height, + cropcap.defrect.left, cropcap.defrect.top); + GST_DEBUG_OBJECT (v4l2src, "bounds: w:%d h:%d l:%d t:%d", + cropcap.bounds.width, cropcap.bounds.height, + cropcap.bounds.left, cropcap.bounds.top); + + /* limit zoom to zoomax */ + zoom_max = cropcap.defrect.width / cropcap.bounds.width; + v4l2src->zoom = min (v4l2src->zoom, zoom_max); + GST_DEBUG_OBJECT (v4l2src, "set zoom: %f (zoom max:%f)", v4l2src->zoom, + zoom_max); + + /* set croppping zone */ + memset (&crop, 0, sizeof (struct v4l2_crop)); + crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + crop.c.width = cropcap.defrect.width / v4l2src->zoom; + crop.c.height = cropcap.defrect.height / v4l2src->zoom; + /* center crop */ + crop.c.left = + (cropcap.defrect.width + cropcap.defrect.left * 2 - crop.c.width) / 2; + crop.c.top = + (cropcap.defrect.height + cropcap.defrect.top * 2 - crop.c.height) / 2; + GST_DEBUG_OBJECT (v4l2src, "=> CROP: w:%d h:%d l:%d t:%d", crop.c.width, + crop.c.height, crop.c.left, crop.c.top); + + if (ioctl (v4l2src->v4l2object->video_fd, VIDIOC_S_CROP, &crop) < 0) { + GST_WARNING_OBJECT (v4l2src, "Crop setting failed"); + } + + return TRUE; +} + +/* + */ +static gboolean +gst_v4l2src_get_nearest_size (GstV4l2Src * v4l2src, guint32 pixelformat, + gint * width, gint * height) +{ + struct v4l2_format fmt; + int fd; + int r; + + g_return_val_if_fail (width != NULL, FALSE); + g_return_val_if_fail (height != NULL, FALSE); + + GST_LOG_OBJECT (v4l2src, + "getting nearest size to %dx%d with format %" GST_FOURCC_FORMAT, + *width, *height, GST_FOURCC_ARGS (pixelformat)); + + fd = v4l2src->v4l2object->video_fd; + + /* get size delimiters */ + memset (&fmt, 0, sizeof (fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = *width; + fmt.fmt.pix.height = *height; + fmt.fmt.pix.pixelformat = pixelformat; + fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; + + r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt); + if (r < 0 && errno == EINVAL) { + /* try again with progressive video */ + fmt.fmt.pix.width = *width; + fmt.fmt.pix.height = *height; + fmt.fmt.pix.pixelformat = pixelformat; + fmt.fmt.pix.field = V4L2_FIELD_NONE; + r = v4l2_ioctl (fd, VIDIOC_TRY_FMT, &fmt); + } + + if (r < 0) { + /* The driver might not implement TRY_FMT, in which case we will try + S_FMT to probe */ + if (errno != ENOTTY) + return FALSE; + + /* Only try S_FMT if we're not actively capturing yet, which we shouldn't + be, because we're still probing */ + if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) + return FALSE; + + GST_LOG_OBJECT (v4l2src, + "Failed to probe size limit with VIDIOC_TRY_FMT, trying VIDIOC_S_FMT"); + + fmt.fmt.pix.width = *width; + fmt.fmt.pix.height = *height; + + r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt); + if (r < 0 && errno == EINVAL) { + /* try again with progressive video */ + fmt.fmt.pix.width = *width; + fmt.fmt.pix.height = *height; + fmt.fmt.pix.pixelformat = pixelformat; + fmt.fmt.pix.field = V4L2_FIELD_NONE; + r = v4l2_ioctl (fd, VIDIOC_S_FMT, &fmt); + } + + if (r < 0) + return FALSE; + } + + GST_LOG_OBJECT (v4l2src, + "got nearest size %dx%d", fmt.fmt.pix.width, fmt.fmt.pix.height); + + *width = fmt.fmt.pix.width; + *height = fmt.fmt.pix.height; + + return TRUE; +} diff --git a/sys/v4l2/v4l2src_calls.h b/sys/v4l2/v4l2src_calls.h index 1fc7411fa..aee775417 100644 --- a/sys/v4l2/v4l2src_calls.h +++ b/sys/v4l2/v4l2src_calls.h @@ -41,5 +41,18 @@ GstFlowReturn gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer **buf) gboolean gst_v4l2src_capture_stop (GstV4l2Src * v4l2src); gboolean gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src); +gboolean gst_v4l2src_capture_set_effect (GstV4l2Src * v4l2src, gchar* effect_name); +gboolean gst_v4l2src_capture_set_white_balance_mode (GstV4l2Src * v4l2src, gchar* wb_mode_name); +gboolean gst_v4l2src_capture_set_all_controls (GstV4l2Src * v4l2src); +gboolean gst_v4l2src_capture_set_control (GstV4l2Src * v4l2src, guint prop_id); +gboolean gst_v4l2src_capture_get_control (GstV4l2Src * v4l2src, guint prop_id); + +gboolean gst_v4l2src_capture_set_zoom (GstV4l2Src * v4l2src); + +gboolean gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src); +gboolean gst_v4l2src_clear_format_list (GstV4l2Src * v4l2src); + +GstCaps* gst_v4l2src_probe_caps_for_format (GstV4l2Src * v4l2src, guint32 pixelformat, + const GstStructure *template); #endif /* __V4L2SRC_CALLS_H__ */ |