v4l2rc: Add DV_TIMINGS query and locking

This adds support to DV_TIMINGS query and locking. The timing width and
height is then used as a preference.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/870>
This commit is contained in:
Nicolas Dufresne 2021-02-10 15:52:55 -05:00
parent b750fb2d5b
commit 25696203c3
4 changed files with 95 additions and 2 deletions

View file

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

View file

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

View file

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

View file

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