diff --git a/sys/v4l2/gstv4l2bufferpool.h b/sys/v4l2/gstv4l2bufferpool.h index b61a6ea821..f4fdf92b4e 100644 --- a/sys/v4l2/gstv4l2bufferpool.h +++ b/sys/v4l2/gstv4l2bufferpool.h @@ -41,6 +41,10 @@ G_BEGIN_DECLS #define GST_V4L2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_BUFFER_POOL, GstV4l2BufferPool)) #define GST_V4L2_BUFFER_POOL_CAST(obj) ((GstV4l2BufferPool*)(obj)) +/* Returns true if the pool is streaming. Must be called with stream lock + * held. */ +#define GST_V4L2_BUFFER_POOL_IS_STREAMING(obj) (GST_V4L2_BUFFER_POOL (obj)->streaming) + /* This flow return is used to indicate that the last buffer has been dequeued * during draining. This should normally only occur for mem-2-mem devices. */ #define GST_V4L2_FLOW_LAST_BUFFER GST_FLOW_CUSTOM_SUCCESS diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h index 394f4292ee..e5ed0acaba 100644 --- a/sys/v4l2/gstv4l2object.h +++ b/sys/v4l2/gstv4l2object.h @@ -330,6 +330,10 @@ gboolean gst_v4l2_query_input (GstV4l2Object * v4l2object, struct v4l2_in gboolean gst_v4l2_get_output (GstV4l2Object * v4l2object, guint32 * output); gboolean gst_v4l2_set_output (GstV4l2Object * v4l2object, guint32 output); +/* dv timings */ +gboolean gst_v4l2_set_dv_timings (GstV4l2Object * v4l2object, struct v4l2_dv_timings *timings); +gboolean gst_v4l2_query_dv_timings (GstV4l2Object * v4l2object, struct v4l2_dv_timings *timings); + /* frequency control */ gboolean gst_v4l2_get_frequency (GstV4l2Object * v4l2object, gint tunernum, gulong * frequency); gboolean gst_v4l2_set_frequency (GstV4l2Object * v4l2object, gint tunernum, gulong frequency); diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index 5c3888a709..e2aa918d54 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -491,8 +491,22 @@ static gboolean gst_v4l2src_query_preferred_dv_timings (GstV4l2Src * v4l2src, struct PreferredCapsInfo *pref) { - GST_FIXME_OBJECT (v4l2src, "query dv_timings not implements"); - return NULL; + GstV4l2Object *obj = v4l2src->v4l2object; + struct v4l2_dv_timings dv_timings = { 0, }; + + if (!gst_v4l2_query_dv_timings (obj, &dv_timings)) + return FALSE; + + pref->width = dv_timings.bt.width; + pref->height = dv_timings.bt.height; + /* FIXME calculate frame rate */ + + /* If are are not streaming (e.g. we received source-change event), lock the + * new timing immediatly so that TRY_FMT can properly work */ + if (!obj->pool || !GST_V4L2_BUFFER_POOL_IS_STREAMING (obj->pool)) + gst_v4l2_set_dv_timings (obj, &dv_timings); + + return TRUE; } static gboolean diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c index dce8e33dcc..2dada91151 100644 --- a/sys/v4l2/v4l2_calls.c +++ b/sys/v4l2/v4l2_calls.c @@ -1286,3 +1286,74 @@ gst_v4l2_dequeue_event (GstV4l2Object * v4l2object, struct v4l2_event * event) return TRUE; } + +gboolean +gst_v4l2_set_dv_timings (GstV4l2Object * v4l2object, + struct v4l2_dv_timings * timings) +{ + gint ret; + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + ret = v4l2object->ioctl (v4l2object->video_fd, VIDIOC_S_DV_TIMINGS, timings); + + if (ret < 0) { + GST_ERROR_OBJECT (v4l2object->dbg_obj, "S_DV_TIMINGS failed: %s (%i)", + g_strerror (errno), errno); + return FALSE; + } + + return TRUE; +} + +gboolean +gst_v4l2_query_dv_timings (GstV4l2Object * v4l2object, + struct v4l2_dv_timings * timings) +{ + gint ret; + + if (!GST_V4L2_IS_OPEN (v4l2object)) + return FALSE; + + ret = v4l2object->ioctl (v4l2object->video_fd, VIDIOC_QUERY_DV_TIMINGS, + timings); + + if (ret < 0) { + switch (errno) { + case ENODATA: + GST_DEBUG_OBJECT (v4l2object->dbg_obj, + "QUERY_DV_TIMINGS not supported for this input/output"); + break; + case ENOLINK: + GST_DEBUG_OBJECT (v4l2object->dbg_obj, + "No timings could be detected because no signal was found."); + break; + case ENOLCK: + GST_INFO_OBJECT (v4l2object->dbg_obj, + "The signal was unstable and the hardware could not lock on to it."); + break; + case ERANGE: + GST_INFO_OBJECT (v4l2object->dbg_obj, + "Timings were found, but they are out of range of the hardware capabilities."); + break; + default: + GST_ERROR_OBJECT (v4l2object->dbg_obj, + "QUERY_DV_TIMINGS failed: %s (%i)", g_strerror (errno), errno); + break; + } + + return FALSE; + } + + if (timings->type != V4L2_DV_BT_656_1120) { + GST_FIXME_OBJECT (v4l2object->dbg_obj, "Unsupported DV Timings type (%i)", + timings->type); + return FALSE; + } + + GST_INFO_OBJECT (v4l2object->dbg_obj, "Detected DV Timings (%i x %i)", + timings->bt.width, timings->bt.height); + + return TRUE; +}