diff options
Diffstat (limited to 'sys/v4l2/v4l2src_calls.c')
-rw-r--r-- | sys/v4l2/v4l2src_calls.c | 508 |
1 files changed, 500 insertions, 8 deletions
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; +} |