mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-20 04:56:24 +00:00
sys/v4l2/gstv4l2src.c: Provide a custom negotiation function to make sure to pick the highest possible framerate and ...
Original commit message from CVS: Patch by: Sjoerd Simons <sjoerd at luon dot net> * sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init), (gst_v4l2src_fixate), (gst_v4l2src_negotiate): Provide a custom negotiation function to make sure to pick the highest possible framerate and resolution. Fixes bug #536646.
This commit is contained in:
parent
f1c5dc21b4
commit
22940c0010
2 changed files with 138 additions and 2 deletions
|
@ -1,3 +1,12 @@
|
||||||
|
2008-06-04 Sebastian Dröge <slomo@circular-chaos.org>
|
||||||
|
|
||||||
|
Patch by: Sjoerd Simons <sjoerd at luon dot net>
|
||||||
|
|
||||||
|
* sys/v4l2/gstv4l2src.c: (gst_v4l2src_class_init),
|
||||||
|
(gst_v4l2src_fixate), (gst_v4l2src_negotiate):
|
||||||
|
Provide a custom negotiation function to make sure to pick the highest
|
||||||
|
possible framerate and resolution. Fixes bug #536646.
|
||||||
|
|
||||||
2008-06-04 Thijs Vermeir <thijsvermeir@gmail.com>
|
2008-06-04 Thijs Vermeir <thijsvermeir@gmail.com>
|
||||||
|
|
||||||
* gst/avi/gstavidemux.c:
|
* gst/avi/gstavidemux.c:
|
||||||
|
|
|
@ -235,18 +235,26 @@ GST_BOILERPLATE_FULL (GstV4l2Src, gst_v4l2src, GstPushSrc, GST_TYPE_PUSH_SRC,
|
||||||
gst_v4l2src_init_interfaces);
|
gst_v4l2src_init_interfaces);
|
||||||
|
|
||||||
static void gst_v4l2src_dispose (GObject * object);
|
static void gst_v4l2src_dispose (GObject * object);
|
||||||
|
|
||||||
static void gst_v4l2src_finalize (GstV4l2Src * v4l2src);
|
static void gst_v4l2src_finalize (GstV4l2Src * v4l2src);
|
||||||
|
|
||||||
/* basesrc methods */
|
/* basesrc methods */
|
||||||
static gboolean gst_v4l2src_start (GstBaseSrc * src);
|
static gboolean gst_v4l2src_start (GstBaseSrc * src);
|
||||||
|
|
||||||
static gboolean gst_v4l2src_stop (GstBaseSrc * src);
|
static gboolean gst_v4l2src_stop (GstBaseSrc * src);
|
||||||
|
|
||||||
static gboolean gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps);
|
static gboolean gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps);
|
||||||
|
|
||||||
static GstCaps *gst_v4l2src_get_caps (GstBaseSrc * src);
|
static GstCaps *gst_v4l2src_get_caps (GstBaseSrc * src);
|
||||||
|
|
||||||
static gboolean gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query);
|
static gboolean gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query);
|
||||||
|
|
||||||
static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** out);
|
static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** out);
|
||||||
|
|
||||||
static void gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps);
|
static void gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps);
|
||||||
|
|
||||||
|
static gboolean gst_v4l2src_negotiate (GstBaseSrc * basesrc);
|
||||||
|
|
||||||
static void gst_v4l2src_set_property (GObject * object, guint prop_id,
|
static void gst_v4l2src_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec);
|
const GValue * value, GParamSpec * pspec);
|
||||||
static void gst_v4l2src_get_property (GObject * object, guint prop_id,
|
static void gst_v4l2src_get_property (GObject * object, guint prop_id,
|
||||||
|
@ -258,6 +266,7 @@ static void
|
||||||
gst_v4l2src_base_init (gpointer g_class)
|
gst_v4l2src_base_init (gpointer g_class)
|
||||||
{
|
{
|
||||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
|
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
|
||||||
|
|
||||||
GstV4l2SrcClass *gstv4l2src_class = GST_V4L2SRC_CLASS (g_class);
|
GstV4l2SrcClass *gstv4l2src_class = GST_V4L2SRC_CLASS (g_class);
|
||||||
|
|
||||||
gstv4l2src_class->v4l2_class_devices = NULL;
|
gstv4l2src_class->v4l2_class_devices = NULL;
|
||||||
|
@ -276,7 +285,9 @@ static void
|
||||||
gst_v4l2src_class_init (GstV4l2SrcClass * klass)
|
gst_v4l2src_class_init (GstV4l2SrcClass * klass)
|
||||||
{
|
{
|
||||||
GObjectClass *gobject_class;
|
GObjectClass *gobject_class;
|
||||||
|
|
||||||
GstBaseSrcClass *basesrc_class;
|
GstBaseSrcClass *basesrc_class;
|
||||||
|
|
||||||
GstPushSrcClass *pushsrc_class;
|
GstPushSrcClass *pushsrc_class;
|
||||||
|
|
||||||
gobject_class = G_OBJECT_CLASS (klass);
|
gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
@ -305,6 +316,7 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass)
|
||||||
basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2src_stop);
|
basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2src_stop);
|
||||||
basesrc_class->query = GST_DEBUG_FUNCPTR (gst_v4l2src_query);
|
basesrc_class->query = GST_DEBUG_FUNCPTR (gst_v4l2src_query);
|
||||||
basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_v4l2src_fixate);
|
basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_v4l2src_fixate);
|
||||||
|
basesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_v4l2src_negotiate);
|
||||||
|
|
||||||
pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_v4l2src_create);
|
pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_v4l2src_create);
|
||||||
}
|
}
|
||||||
|
@ -406,6 +418,7 @@ static void
|
||||||
gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps)
|
gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstStructure *structure;
|
GstStructure *structure;
|
||||||
|
|
||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps);
|
GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps);
|
||||||
|
@ -417,12 +430,13 @@ gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps)
|
||||||
/* FIXME such sizes? we usually fixate to something in the 320x200
|
/* FIXME such sizes? we usually fixate to something in the 320x200
|
||||||
* range... */
|
* range... */
|
||||||
/* We are fixating to greater possble size (limited to GST_V4L2_MAX_SIZE)
|
/* We are fixating to greater possble size (limited to GST_V4L2_MAX_SIZE)
|
||||||
and framerate closer to 15/2 that is common in web-cams */
|
and the maximum framerate resolution for that size */
|
||||||
gst_structure_fixate_field_nearest_int (structure, "width",
|
gst_structure_fixate_field_nearest_int (structure, "width",
|
||||||
GST_V4L2_MAX_SIZE);
|
GST_V4L2_MAX_SIZE);
|
||||||
gst_structure_fixate_field_nearest_int (structure, "height",
|
gst_structure_fixate_field_nearest_int (structure, "height",
|
||||||
GST_V4L2_MAX_SIZE);
|
GST_V4L2_MAX_SIZE);
|
||||||
gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2);
|
gst_structure_fixate_field_nearest_fraction (structure, "framerate",
|
||||||
|
G_MAXINT, 1);
|
||||||
|
|
||||||
v = gst_structure_get_value (structure, "format");
|
v = gst_structure_get_value (structure, "format");
|
||||||
if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) {
|
if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) {
|
||||||
|
@ -434,8 +448,99 @@ gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps)
|
||||||
gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL);
|
gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (basesrc, "fixated caps %" GST_PTR_FORMAT, caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_v4l2src_negotiate (GstBaseSrc * basesrc)
|
||||||
|
{
|
||||||
|
GstCaps *thiscaps;
|
||||||
|
|
||||||
|
GstCaps *caps = NULL;
|
||||||
|
|
||||||
|
GstCaps *peercaps = NULL;
|
||||||
|
|
||||||
|
gboolean result = FALSE;
|
||||||
|
|
||||||
|
/* first see what is possible on our source pad */
|
||||||
|
thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc));
|
||||||
|
GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps);
|
||||||
|
/* nothing or anything is allowed, we're done */
|
||||||
|
if (thiscaps == NULL || gst_caps_is_any (thiscaps))
|
||||||
|
goto no_nego_needed;
|
||||||
|
|
||||||
|
/* get the peer caps */
|
||||||
|
peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
|
||||||
|
GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps);
|
||||||
|
if (peercaps && !gst_caps_is_any (peercaps)) {
|
||||||
|
GstCaps *icaps;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Prefer the first caps we are compatible with that the peer proposed */
|
||||||
|
for (i = 0; i < gst_caps_get_size (peercaps); i++) {
|
||||||
|
/* get intersection */
|
||||||
|
GstCaps *ipcaps = gst_caps_copy_nth (peercaps, i);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (basesrc, "peer: %" GST_PTR_FORMAT, ipcaps);
|
||||||
|
|
||||||
|
icaps = gst_caps_intersect (thiscaps, ipcaps);
|
||||||
|
gst_caps_unref (ipcaps);
|
||||||
|
|
||||||
|
if (!gst_caps_is_empty (icaps))
|
||||||
|
break;
|
||||||
|
|
||||||
|
gst_caps_unref (icaps);
|
||||||
|
icaps = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, icaps);
|
||||||
|
gst_caps_unref (thiscaps);
|
||||||
|
gst_caps_unref (peercaps);
|
||||||
|
if (icaps) {
|
||||||
|
/* take first (and best, since they are sorted) possibility */
|
||||||
|
caps = gst_caps_copy_nth (icaps, 0);
|
||||||
|
gst_caps_unref (icaps);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* no peer or peer have ANY caps, work with our own caps then */
|
||||||
|
caps = thiscaps;
|
||||||
|
}
|
||||||
|
if (caps) {
|
||||||
|
caps = gst_caps_make_writable (caps);
|
||||||
|
gst_caps_truncate (caps);
|
||||||
|
|
||||||
|
/* now fixate */
|
||||||
|
if (!gst_caps_is_empty (caps)) {
|
||||||
|
gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
|
||||||
|
GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps);
|
||||||
|
|
||||||
|
if (gst_caps_is_any (caps)) {
|
||||||
|
/* hmm, still anything, so element can do anything and
|
||||||
|
* nego is not needed */
|
||||||
|
result = TRUE;
|
||||||
|
} else if (gst_caps_is_fixed (caps)) {
|
||||||
|
/* yay, fixed caps, use those then */
|
||||||
|
gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gst_caps_unref (caps);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
no_nego_needed:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (basesrc, "no negotiation needed");
|
||||||
|
if (thiscaps)
|
||||||
|
gst_caps_unref (thiscaps);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static GstStructure *
|
static GstStructure *
|
||||||
gst_v4l2src_v4l2fourcc_to_structure (guint32 fourcc)
|
gst_v4l2src_v4l2fourcc_to_structure (guint32 fourcc)
|
||||||
{
|
{
|
||||||
|
@ -465,7 +570,9 @@ gst_v4l2src_v4l2fourcc_to_structure (guint32 fourcc)
|
||||||
case V4L2_PIX_FMT_RGB32:
|
case V4L2_PIX_FMT_RGB32:
|
||||||
case V4L2_PIX_FMT_BGR32:{
|
case V4L2_PIX_FMT_BGR32:{
|
||||||
guint depth = 0, bpp = 0;
|
guint depth = 0, bpp = 0;
|
||||||
|
|
||||||
gint endianness = 0;
|
gint endianness = 0;
|
||||||
|
|
||||||
guint32 r_mask = 0, b_mask = 0, g_mask = 0;
|
guint32 r_mask = 0, b_mask = 0, g_mask = 0;
|
||||||
|
|
||||||
switch (fourcc) {
|
switch (fourcc) {
|
||||||
|
@ -622,6 +729,7 @@ static struct v4l2_fmtdesc *
|
||||||
gst_v4l2src_get_format_from_fourcc (GstV4l2Src * v4l2src, guint32 fourcc)
|
gst_v4l2src_get_format_from_fourcc (GstV4l2Src * v4l2src, guint32 fourcc)
|
||||||
{
|
{
|
||||||
struct v4l2_fmtdesc *fmt;
|
struct v4l2_fmtdesc *fmt;
|
||||||
|
|
||||||
GSList *walk;
|
GSList *walk;
|
||||||
|
|
||||||
if (fourcc == 0)
|
if (fourcc == 0)
|
||||||
|
@ -651,6 +759,7 @@ gst_v4l2src_get_all_caps (void)
|
||||||
|
|
||||||
if (caps == NULL) {
|
if (caps == NULL) {
|
||||||
GstStructure *structure;
|
GstStructure *structure;
|
||||||
|
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
caps = gst_caps_new_empty ();
|
caps = gst_caps_new_empty ();
|
||||||
|
@ -673,7 +782,9 @@ static GstCaps *
|
||||||
gst_v4l2src_get_caps (GstBaseSrc * src)
|
gst_v4l2src_get_caps (GstBaseSrc * src)
|
||||||
{
|
{
|
||||||
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
|
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
|
||||||
|
|
||||||
GstCaps *ret;
|
GstCaps *ret;
|
||||||
|
|
||||||
GSList *walk;
|
GSList *walk;
|
||||||
|
|
||||||
if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
|
if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
|
||||||
|
@ -693,6 +804,7 @@ gst_v4l2src_get_caps (GstBaseSrc * src)
|
||||||
|
|
||||||
for (walk = v4l2src->formats; walk; walk = walk->next) {
|
for (walk = v4l2src->formats; walk; walk = walk->next) {
|
||||||
struct v4l2_fmtdesc *format;
|
struct v4l2_fmtdesc *format;
|
||||||
|
|
||||||
GstStructure *template;
|
GstStructure *template;
|
||||||
|
|
||||||
format = (struct v4l2_fmtdesc *) walk->data;
|
format = (struct v4l2_fmtdesc *) walk->data;
|
||||||
|
@ -733,9 +845,13 @@ gst_v4l2_get_caps_info (GstV4l2Src * v4l2src, GstCaps * caps,
|
||||||
guint * fps_d, guint * size)
|
guint * fps_d, guint * size)
|
||||||
{
|
{
|
||||||
GstStructure *structure;
|
GstStructure *structure;
|
||||||
|
|
||||||
const GValue *framerate;
|
const GValue *framerate;
|
||||||
|
|
||||||
guint32 fourcc;
|
guint32 fourcc;
|
||||||
|
|
||||||
const gchar *mimetype;
|
const gchar *mimetype;
|
||||||
|
|
||||||
guint outsize;
|
guint outsize;
|
||||||
|
|
||||||
/* default unknown values */
|
/* default unknown values */
|
||||||
|
@ -854,9 +970,13 @@ static gboolean
|
||||||
gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
|
gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstV4l2Src *v4l2src;
|
GstV4l2Src *v4l2src;
|
||||||
|
|
||||||
gint w = 0, h = 0;
|
gint w = 0, h = 0;
|
||||||
|
|
||||||
struct v4l2_fmtdesc *format;
|
struct v4l2_fmtdesc *format;
|
||||||
|
|
||||||
guint fps_n, fps_d;
|
guint fps_n, fps_d;
|
||||||
|
|
||||||
guint size;
|
guint size;
|
||||||
|
|
||||||
v4l2src = GST_V4L2SRC (src);
|
v4l2src = GST_V4L2SRC (src);
|
||||||
|
@ -906,6 +1026,7 @@ static gboolean
|
||||||
gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query)
|
gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query)
|
||||||
{
|
{
|
||||||
GstV4l2Src *src;
|
GstV4l2Src *src;
|
||||||
|
|
||||||
gboolean res = FALSE;
|
gboolean res = FALSE;
|
||||||
|
|
||||||
src = GST_V4L2SRC (bsrc);
|
src = GST_V4L2SRC (bsrc);
|
||||||
|
@ -997,6 +1118,7 @@ static GstFlowReturn
|
||||||
gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
|
gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
|
||||||
{
|
{
|
||||||
gint amount;
|
gint amount;
|
||||||
|
|
||||||
gint buffersize;
|
gint buffersize;
|
||||||
|
|
||||||
buffersize = v4l2src->frame_byte_size;
|
buffersize = v4l2src->frame_byte_size;
|
||||||
|
@ -1025,6 +1147,7 @@ gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
|
||||||
/* timestamps, LOCK to get clock and base time. */
|
/* timestamps, LOCK to get clock and base time. */
|
||||||
{
|
{
|
||||||
GstClock *clock;
|
GstClock *clock;
|
||||||
|
|
||||||
GstClockTime timestamp;
|
GstClockTime timestamp;
|
||||||
|
|
||||||
GST_OBJECT_LOCK (v4l2src);
|
GST_OBJECT_LOCK (v4l2src);
|
||||||
|
@ -1076,8 +1199,11 @@ static GstFlowReturn
|
||||||
gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf)
|
gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf)
|
||||||
{
|
{
|
||||||
GstBuffer *temp;
|
GstBuffer *temp;
|
||||||
|
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
|
||||||
guint size;
|
guint size;
|
||||||
|
|
||||||
guint count;
|
guint count;
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
|
@ -1121,6 +1247,7 @@ static GstFlowReturn
|
||||||
gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
|
gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
|
||||||
{
|
{
|
||||||
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
|
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
|
||||||
|
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
|
||||||
if (v4l2src->use_mmap) {
|
if (v4l2src->use_mmap) {
|
||||||
|
|
Loading…
Reference in a new issue