diff options
| -rw-r--r-- | ChangeLog | 18 | ||||
| -rw-r--r-- | sys/v4l2/gstv4l2src.c | 17 | ||||
| -rw-r--r-- | sys/v4l2/v4l2src_calls.c | 112 | 
3 files changed, 134 insertions, 13 deletions
@@ -1,3 +1,21 @@ +2007-10-13  Tim-Philipp Müller  <tim at centricular dot net> + +	* sys/v4l2/gstv4l2src.c: +	* sys/v4l2/v4l2src_calls.c: +	  When probing the formats and sizes a camera supports, make +	  sure the best ones (highest resolution, prefered format) +	  end up at the beginning of the probed caps and the less +	  desirable ones at the end.  This is important because the +	  order within the caps matters for things like fixation and +	  negotiation, ie. what format is chosen in the end. +	  With recent kernels, the current probing code will end up +	  querying the supported sizes from lowest resolution to +	  highest resolution, adding them to the probed caps in that +	  order, resulting to v4l2src fixating to the lowest possible +	  resolution if downstream does not express a size preference. +	  Also make up a somewhat random ranking of prefered output +	  formats for the same reason. Fixes #485828. +	  2007-10-11  Tim-Philipp Müller  <tim at centricular dot net>  	Based on patch by: Jason Kivlighn  <jkivlighn gmail com> diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index 5a892bda..9fce1846 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -240,7 +240,7 @@ static GstCaps *gst_v4l2src_get_caps (GstBaseSrc * src);  static gboolean gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query);  static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** out); -static void gst_v4l2src_fixate (GstPad * pad, GstCaps * caps); +static void gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps);  static void gst_v4l2src_set_property (GObject * object, guint prop_id,      const GValue * value, GParamSpec * pspec); @@ -295,6 +295,7 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass)    basesrc_class->start = GST_DEBUG_FUNCPTR (gst_v4l2src_start);    basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2src_stop);    basesrc_class->query = GST_DEBUG_FUNCPTR (gst_v4l2src_query); +  basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_v4l2src_fixate);    pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_v4l2src_create);  } @@ -313,9 +314,6 @@ gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass)    v4l2src->is_capturing = FALSE; -  gst_pad_set_fixatecaps_function (GST_BASE_SRC_PAD (v4l2src), -      gst_v4l2src_fixate); -    gst_base_src_set_format (GST_BASE_SRC (v4l2src), GST_FORMAT_TIME);    gst_base_src_set_live (GST_BASE_SRC (v4l2src), TRUE); @@ -388,15 +386,12 @@ gst_v4l2src_get_property (GObject * object,  /* this function is a bit of a last resort */  static void -gst_v4l2src_fixate (GstPad * pad, GstCaps * caps) +gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps)  {    GstStructure *structure;    gint i; -  G_GNUC_UNUSED gchar *caps_str; -  caps_str = gst_caps_to_string (caps); -  GST_DEBUG_OBJECT (GST_PAD_PARENT (pad), "fixating caps %s", caps_str); -  g_free (caps_str); +  GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps);    for (i = 0; i < gst_caps_get_size (caps); ++i) {      structure = gst_caps_get_structure (caps, i); @@ -405,7 +400,7 @@ gst_v4l2src_fixate (GstPad * pad, GstCaps * caps)      /* FIXME such sizes? we usually fixate to something in the 320x200       * range... */      /* We are fixating to greater possble size (limited to GST_V4L2_MAX_SIZE) -       and framarate closer to 15/2 that is common in web-cams */ +       and framerate closer to 15/2 that is common in web-cams */      gst_structure_fixate_field_nearest_int (structure, "width",          GST_V4L2_MAX_SIZE);      gst_structure_fixate_field_nearest_int (structure, "height", @@ -697,6 +692,8 @@ gst_v4l2src_get_caps (GstBaseSrc * src)    v4l2src->probed_caps = gst_caps_ref (ret); +  GST_INFO_OBJECT (v4l2src, "probed caps: %" GST_PTR_FORMAT, ret); +    return ret;  } diff --git a/sys/v4l2/v4l2src_calls.c b/sys/v4l2/v4l2src_calls.c index 0ed28a88..21022c8c 100644 --- a/sys/v4l2/v4l2src_calls.c +++ b/sys/v4l2/v4l2src_calls.c @@ -373,6 +373,97 @@ gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool)    gst_mini_object_unref (GST_MINI_OBJECT (pool));  } +/* complete made up ranking, the values themselves are meaningless */ +#define YUV_BASE_RANK     1000 +#define JPEG_BASE_RANK     500 +#define DV_BASE_RANK       200 +#define RGB_BASE_RANK      100 +#define YUV_ODD_BASE_RANK   50 +#define RGB_ODD_BASE_RANK   25 +#define BAYER_BASE_RANK     15 +#define GREY_BASE_RANK       5 + +static gint +gst_v4l2src_format_get_rank (guint32 fourcc) +{ +  switch (fourcc) { +    case V4L2_PIX_FMT_MJPEG: +      return JPEG_BASE_RANK; +    case V4L2_PIX_FMT_JPEG: +      return JPEG_BASE_RANK + 1; + +    case V4L2_PIX_FMT_RGB332: +    case V4L2_PIX_FMT_RGB555: +    case V4L2_PIX_FMT_RGB555X: +    case V4L2_PIX_FMT_RGB565: +    case V4L2_PIX_FMT_RGB565X: +      return RGB_ODD_BASE_RANK; + +    case V4L2_PIX_FMT_RGB24: +    case V4L2_PIX_FMT_BGR24: +      return RGB_BASE_RANK - 1; + +    case V4L2_PIX_FMT_RGB32: +    case V4L2_PIX_FMT_BGR32: +      return RGB_BASE_RANK; + +    case V4L2_PIX_FMT_GREY:    /*  8  Greyscale     */ +      return GREY_BASE_RANK; + +    case V4L2_PIX_FMT_NV12:    /* 12  Y/CbCr 4:2:0  */ +    case V4L2_PIX_FMT_NV21:    /* 12  Y/CrCb 4:2:0  */ +    case V4L2_PIX_FMT_YYUV:    /* 16  YUV 4:2:2     */ +    case V4L2_PIX_FMT_HI240:   /*  8  8-bit color   */ +      return YUV_ODD_BASE_RANK; + +    case V4L2_PIX_FMT_YVU410:  /* YVU9,  9 bits per pixel */ +      return YUV_BASE_RANK + 3; +    case V4L2_PIX_FMT_YUV410:  /* YUV9,  9 bits per pixel */ +      return YUV_BASE_RANK + 2; +    case V4L2_PIX_FMT_YUV420:  /* I420, 12 bits per pixel */ +      return YUV_BASE_RANK + 7; +    case V4L2_PIX_FMT_YUYV:    /* YUY2, 16 bits per pixel */ +      return YUV_BASE_RANK + 10; +    case V4L2_PIX_FMT_YVU420:  /* YV12, 12 bits per pixel */ +      return YUV_BASE_RANK + 6; +    case V4L2_PIX_FMT_UYVY:    /* UYVY, 16 bits per pixel */ +      return YUV_BASE_RANK + 9; +    case V4L2_PIX_FMT_Y41P:    /* Y41P, 12 bits per pixel */ +      return YUV_BASE_RANK + 5; +    case V4L2_PIX_FMT_YUV411P: /* Y41B, 12 bits per pixel */ +      return YUV_BASE_RANK + 4; +    case V4L2_PIX_FMT_YUV422P: /* Y42B, 16 bits per pixel */ +      return YUV_BASE_RANK + 8; + +    case V4L2_PIX_FMT_DV: +      return DV_BASE_RANK; + +    case V4L2_PIX_FMT_MPEG:    /* MPEG          */ +    case V4L2_PIX_FMT_WNVA:    /* Winnov hw compres */ +      return 0; + +    case V4L2_PIX_FMT_SBGGR8: +      return BAYER_BASE_RANK; + +    default: +      break; +  } + +  return 0; +} + +static gint +gst_v4l2src_format_cmp_func (gconstpointer a, gconstpointer b) +{ +  guint32 pf1 = ((struct v4l2_fmtdesc *) a)->pixelformat; +  guint32 pf2 = ((struct v4l2_fmtdesc *) b)->pixelformat; + +  if (pf1 == pf2) +    return 0; + +  return gst_v4l2src_format_get_rank (pf2) - gst_v4l2src_format_get_rank (pf1); +} +  /******************************************************   * gst_v4l2src_fill_format_list():   *   create list of supported capture formats @@ -407,9 +498,12 @@ gst_v4l2src_fill_format_list (GstV4l2Src * v4l2src)      GST_LOG_OBJECT (v4l2src, "pixelformat: %" GST_FOURCC_FORMAT,          GST_FOURCC_ARGS (format->pixelformat)); -    v4l2src->formats = g_slist_prepend (v4l2src->formats, format); +    /* sort formats according to our preference;  we do this, because caps +     * are probed in the order the formats are in the list, and the order of +     * formats in the final probed caps matters for things like fixation */ +    v4l2src->formats = g_slist_insert_sorted (v4l2src->formats, format, +        (GCompareFunc) gst_v4l2src_format_cmp_func);    } -  v4l2src->formats = g_slist_reverse (v4l2src->formats);    GST_DEBUG_OBJECT (v4l2src, "got %d format(s)", n); @@ -638,6 +732,7 @@ gst_v4l2src_probe_caps_for_format (GstV4l2Src * v4l2src, guint32 pixelformat,  {    GstCaps *ret;    GstStructure *tmp; +  GList *results = NULL;  #ifdef VIDIOC_ENUM_FRAMESIZES    gint fd = v4l2src->v4l2object->video_fd; @@ -661,7 +756,7 @@ gst_v4l2src_probe_caps_for_format (GstV4l2Src * v4l2src, guint32 pixelformat,        tmp = gst_v4l2src_probe_caps_for_format_and_size (v4l2src, pixelformat,            w, h, template);        if (tmp) -        gst_caps_append_structure (ret, tmp); +        results = g_list_prepend (results, tmp);        size.index++;      } while (ioctl (fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0); @@ -697,6 +792,17 @@ gst_v4l2src_probe_caps_for_format (GstV4l2Src * v4l2src, guint32 pixelformat,      goto unknown_type;    } +  /* we use an intermediary list to store the results of the probing because +   * we probe from lowest resolution to highest resolution, but want the caps +   * to contain the results in reverse order starting with the highest +   * resolution, as order in caps matters for things like fixation.  However, +   * there's no gst_caps_prepend_structure(), so we use the list as helper to +   * reverse the order */ +  while (results != NULL) { +    gst_caps_append_structure (ret, GST_STRUCTURE (results->data)); +    results = g_list_delete_link (results, results); +  } +    return ret;    /* ERRORS */  | 
