gst_plugins_base/sys/v4l/gstv4lsrc.c
branchRCL_3
changeset 30 7e817e7e631c
parent 0 0e761a78d257
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
       
     1 /* GStreamer
       
     2  *
       
     3  * gstv4lsrc.c: BT8x8/V4L source element
       
     4  *
       
     5  * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
       
     6  *
       
     7  * This library is free software; you can redistribute it and/or
       
     8  * modify it under the terms of the GNU Library General Public
       
     9  * License as published by the Free Software Foundation; either
       
    10  * version 2 of the License, or (at your option) any later version.
       
    11  *
       
    12  * This library is distributed in the hope that it will be useful,
       
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    15  * Library General Public License for more details.
       
    16  *
       
    17  * You should have received a copy of the GNU Library General Public
       
    18  * License along with this library; if not, write to the
       
    19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    20  * Boston, MA 02111-1307, USA.
       
    21  */
       
    22 
       
    23 #ifdef HAVE_CONFIG_H
       
    24 #include <config.h>
       
    25 #endif
       
    26 
       
    27 #include <string.h>
       
    28 #include <sys/time.h>
       
    29 #include "v4lsrc_calls.h"
       
    30 #include <sys/ioctl.h>
       
    31 
       
    32 
       
    33 static const GstElementDetails gst_v4lsrc_details =
       
    34 GST_ELEMENT_DETAILS ("Video (video4linux/raw) Source",
       
    35     "Source/Video",
       
    36     "Reads raw frames from a video4linux device",
       
    37     "Ronald Bultje <rbultje@ronald.bitfreak.net>");
       
    38 
       
    39 
       
    40 GST_DEBUG_CATEGORY_STATIC (v4lsrc_debug);
       
    41 #define GST_CAT_DEFAULT v4lsrc_debug
       
    42 
       
    43 
       
    44 enum
       
    45 {
       
    46   PROP_0,
       
    47   PROP_AUTOPROBE,
       
    48   PROP_AUTOPROBE_FPS,
       
    49   PROP_COPY_MODE,
       
    50   PROP_TIMESTAMP_OFFSET
       
    51 };
       
    52 
       
    53 
       
    54 GST_BOILERPLATE (GstV4lSrc, gst_v4lsrc, GstV4lElement, GST_TYPE_V4LELEMENT);
       
    55 
       
    56 
       
    57 /* basesrc methods */
       
    58 static gboolean gst_v4lsrc_start (GstBaseSrc * src);
       
    59 static gboolean gst_v4lsrc_stop (GstBaseSrc * src);
       
    60 static gboolean gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps);
       
    61 static GstCaps *gst_v4lsrc_get_caps (GstBaseSrc * src);
       
    62 static GstFlowReturn gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** out);
       
    63 static gboolean gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query);
       
    64 static void gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps);
       
    65 
       
    66 static void gst_v4lsrc_set_property (GObject * object,
       
    67     guint prop_id, const GValue * value, GParamSpec * pspec);
       
    68 static void gst_v4lsrc_get_property (GObject * object,
       
    69     guint prop_id, GValue * value, GParamSpec * pspec);
       
    70 
       
    71 
       
    72 static void
       
    73 gst_v4lsrc_base_init (gpointer g_class)
       
    74 {
       
    75   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
       
    76 
       
    77   gst_element_class_set_details (gstelement_class, &gst_v4lsrc_details);
       
    78 
       
    79   gst_element_class_add_pad_template (gstelement_class,
       
    80       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
       
    81           gst_caps_new_any ()));
       
    82 }
       
    83 
       
    84 static void
       
    85 gst_v4lsrc_class_init (GstV4lSrcClass * klass)
       
    86 {
       
    87   GObjectClass *gobject_class;
       
    88   GstBaseSrcClass *basesrc_class;
       
    89   GstPushSrcClass *pushsrc_class;
       
    90 
       
    91   gobject_class = (GObjectClass *) klass;
       
    92   basesrc_class = (GstBaseSrcClass *) klass;
       
    93   pushsrc_class = (GstPushSrcClass *) klass;
       
    94 
       
    95   gobject_class->set_property = gst_v4lsrc_set_property;
       
    96   gobject_class->get_property = gst_v4lsrc_get_property;
       
    97 
       
    98   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOPROBE,
       
    99       g_param_spec_boolean ("autoprobe", "Autoprobe",
       
   100           "Whether the device should be probed for all possible features",
       
   101           TRUE, G_PARAM_READWRITE));
       
   102   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOPROBE_FPS,
       
   103       g_param_spec_boolean ("autoprobe-fps", "Autoprobe FPS",
       
   104           "Whether the device should be probed for framerates",
       
   105           TRUE, G_PARAM_READWRITE));
       
   106   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COPY_MODE,
       
   107       g_param_spec_boolean ("copy-mode", "Copy mode",
       
   108           "Whether to send out copies of buffers, or direct pointers to the mmap region",
       
   109           TRUE, G_PARAM_READWRITE));
       
   110   g_object_class_install_property (G_OBJECT_CLASS (klass),
       
   111       PROP_TIMESTAMP_OFFSET, g_param_spec_int64 ("timestamp-offset",
       
   112           "Timestamp offset",
       
   113           "A time offset subtracted from timestamps set on buffers (in ns)",
       
   114           G_MININT64, G_MAXINT64, 0, G_PARAM_READWRITE));
       
   115 
       
   116   GST_DEBUG_CATEGORY_INIT (v4lsrc_debug, "v4lsrc", 0, "V4L source element");
       
   117 
       
   118   basesrc_class->get_caps = gst_v4lsrc_get_caps;
       
   119   basesrc_class->set_caps = gst_v4lsrc_set_caps;
       
   120   basesrc_class->start = gst_v4lsrc_start;
       
   121   basesrc_class->stop = gst_v4lsrc_stop;
       
   122   basesrc_class->fixate = gst_v4lsrc_fixate;
       
   123   basesrc_class->query = gst_v4lsrc_query;
       
   124 
       
   125   pushsrc_class->create = gst_v4lsrc_create;
       
   126 }
       
   127 
       
   128 static void
       
   129 gst_v4lsrc_init (GstV4lSrc * v4lsrc, GstV4lSrcClass * klass)
       
   130 {
       
   131   v4lsrc->buffer_size = 0;
       
   132 
       
   133   /* no colorspaces */
       
   134   v4lsrc->colorspaces = NULL;
       
   135 
       
   136   v4lsrc->is_capturing = FALSE;
       
   137   v4lsrc->autoprobe = TRUE;
       
   138   v4lsrc->autoprobe_fps = TRUE;
       
   139   v4lsrc->copy_mode = TRUE;
       
   140 
       
   141   v4lsrc->timestamp_offset = 0;
       
   142 
       
   143   v4lsrc->fps_list = NULL;
       
   144 
       
   145   gst_base_src_set_format (GST_BASE_SRC (v4lsrc), GST_FORMAT_TIME);
       
   146   gst_base_src_set_live (GST_BASE_SRC (v4lsrc), TRUE);
       
   147 }
       
   148 
       
   149 static void
       
   150 gst_v4lsrc_set_property (GObject * object,
       
   151     guint prop_id, const GValue * value, GParamSpec * pspec)
       
   152 {
       
   153   GstV4lSrc *v4lsrc = GST_V4LSRC (object);
       
   154 
       
   155   switch (prop_id) {
       
   156     case PROP_AUTOPROBE:
       
   157       g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc)));
       
   158       v4lsrc->autoprobe = g_value_get_boolean (value);
       
   159       break;
       
   160     case PROP_AUTOPROBE_FPS:
       
   161       g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc)));
       
   162       v4lsrc->autoprobe_fps = g_value_get_boolean (value);
       
   163       break;
       
   164     case PROP_COPY_MODE:
       
   165       v4lsrc->copy_mode = g_value_get_boolean (value);
       
   166       break;
       
   167     case PROP_TIMESTAMP_OFFSET:
       
   168       v4lsrc->timestamp_offset = g_value_get_int64 (value);
       
   169       break;
       
   170     default:
       
   171       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   172       break;
       
   173   }
       
   174 }
       
   175 
       
   176 
       
   177 static void
       
   178 gst_v4lsrc_get_property (GObject * object,
       
   179     guint prop_id, GValue * value, GParamSpec * pspec)
       
   180 {
       
   181   GstV4lSrc *v4lsrc = GST_V4LSRC (object);
       
   182 
       
   183   switch (prop_id) {
       
   184     case PROP_AUTOPROBE:
       
   185       g_value_set_boolean (value, v4lsrc->autoprobe);
       
   186       break;
       
   187     case PROP_AUTOPROBE_FPS:
       
   188       g_value_set_boolean (value, v4lsrc->autoprobe_fps);
       
   189       break;
       
   190     case PROP_COPY_MODE:
       
   191       g_value_set_boolean (value, v4lsrc->copy_mode);
       
   192       break;
       
   193     case PROP_TIMESTAMP_OFFSET:
       
   194       g_value_set_int64 (value, v4lsrc->timestamp_offset);
       
   195       break;
       
   196     default:
       
   197       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   198       break;
       
   199   }
       
   200 }
       
   201 
       
   202 /* this function is a bit of a last resort */
       
   203 static void
       
   204 gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps)
       
   205 {
       
   206   GstStructure *structure;
       
   207   int i;
       
   208   int targetwidth, targetheight;
       
   209   GstV4lSrc *v4lsrc = GST_V4LSRC (bsrc);
       
   210   struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap;
       
   211   struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
       
   212 
       
   213   if (GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
       
   214     GST_DEBUG_OBJECT (v4lsrc, "device reported w: %d-%d, h: %d-%d",
       
   215         vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight);
       
   216     targetwidth = vcap->minwidth;
       
   217     targetheight = vcap->minheight;
       
   218     /* if we can get the current vwin settings, we use those to fixate */
       
   219     if (!gst_v4l_get_capabilities (GST_V4LELEMENT (v4lsrc)))
       
   220       GST_DEBUG_OBJECT (v4lsrc, "failed getting capabilities");
       
   221     else {
       
   222       targetwidth = vwin->width;
       
   223       targetheight = vwin->height;
       
   224     }
       
   225   } else {
       
   226     GST_DEBUG_OBJECT (v4lsrc, "device closed, guessing");
       
   227     targetwidth = 320;
       
   228     targetheight = 200;
       
   229   }
       
   230 
       
   231   GST_DEBUG_OBJECT (v4lsrc, "targetting %dx%d", targetwidth, targetheight);
       
   232 
       
   233   for (i = 0; i < gst_caps_get_size (caps); ++i) {
       
   234     const GValue *v;
       
   235 
       
   236     structure = gst_caps_get_structure (caps, i);
       
   237     gst_structure_fixate_field_nearest_int (structure, "width", targetwidth);
       
   238     gst_structure_fixate_field_nearest_int (structure, "height", targetheight);
       
   239     gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2);
       
   240 
       
   241     v = gst_structure_get_value (structure, "format");
       
   242     if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) {
       
   243       guint32 fourcc;
       
   244 
       
   245       g_return_if_fail (G_VALUE_TYPE (v) == GST_TYPE_LIST);
       
   246 
       
   247       fourcc = gst_value_get_fourcc (gst_value_list_get_value (v, 0));
       
   248       gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL);
       
   249     }
       
   250   }
       
   251 }
       
   252 
       
   253 static gint all_palettes[] = {
       
   254   VIDEO_PALETTE_YUV422,
       
   255   VIDEO_PALETTE_YUV420P,
       
   256   VIDEO_PALETTE_UYVY,
       
   257   VIDEO_PALETTE_YUV411P,
       
   258   VIDEO_PALETTE_YUV422P,
       
   259   VIDEO_PALETTE_YUV410P,
       
   260   VIDEO_PALETTE_YUV411,
       
   261   VIDEO_PALETTE_RGB555,
       
   262   VIDEO_PALETTE_RGB565,
       
   263   VIDEO_PALETTE_RGB24,
       
   264   VIDEO_PALETTE_RGB32,
       
   265   -1
       
   266 };
       
   267 
       
   268 static GstCaps *
       
   269 gst_v4lsrc_palette_to_caps (int palette)
       
   270 {
       
   271   guint32 fourcc;
       
   272   GstCaps *caps;
       
   273 
       
   274   switch (palette) {
       
   275     case VIDEO_PALETTE_YUV422:
       
   276     case VIDEO_PALETTE_YUYV:
       
   277       fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
       
   278       break;
       
   279     case VIDEO_PALETTE_YUV420P:
       
   280       fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
       
   281       break;
       
   282     case VIDEO_PALETTE_UYVY:
       
   283       fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
       
   284       break;
       
   285     case VIDEO_PALETTE_YUV411P:
       
   286       fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B');
       
   287       break;
       
   288     case VIDEO_PALETTE_YUV411:
       
   289       fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P');
       
   290       break;
       
   291     case VIDEO_PALETTE_YUV422P:
       
   292       fourcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
       
   293       break;
       
   294     case VIDEO_PALETTE_YUV410P:
       
   295       fourcc = GST_MAKE_FOURCC ('Y', 'U', 'V', '9');
       
   296       break;
       
   297     case VIDEO_PALETTE_RGB555:
       
   298     case VIDEO_PALETTE_RGB565:
       
   299     case VIDEO_PALETTE_RGB24:
       
   300     case VIDEO_PALETTE_RGB32:
       
   301       fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', ' ');
       
   302       break;
       
   303     default:
       
   304       return NULL;
       
   305   }
       
   306 
       
   307   if (fourcc == GST_MAKE_FOURCC ('R', 'G', 'B', ' ')) {
       
   308     switch (palette) {
       
   309       case VIDEO_PALETTE_RGB555:
       
   310         caps = gst_caps_from_string ("video/x-raw-rgb, "
       
   311             "bpp = (int) 16, "
       
   312             "depth = (int) 15, "
       
   313             "endianness = (int) BYTE_ORDER, "
       
   314             "red_mask = 0x7c00, " "green_mask = 0x03e0, " "blue_mask = 0x001f");
       
   315         break;
       
   316       case VIDEO_PALETTE_RGB565:
       
   317         caps = gst_caps_from_string ("video/x-raw-rgb, "
       
   318             "bpp = (int) 16, "
       
   319             "depth = (int) 16, "
       
   320             "endianness = (int) BYTE_ORDER, "
       
   321             "red_mask = 0xf800, " "green_mask = 0x07f0, " "blue_mask = 0x001f");
       
   322         break;
       
   323       case VIDEO_PALETTE_RGB24:
       
   324         caps = gst_caps_from_string ("video/x-raw-rgb, "
       
   325             "bpp = (int) 24, "
       
   326             "depth = (int) 24, "
       
   327             "endianness = (int) BIG_ENDIAN, "
       
   328             "red_mask = 0xFF0000, "
       
   329             "green_mask = 0x00FF00, " "blue_mask = 0x0000FF");
       
   330         break;
       
   331       case VIDEO_PALETTE_RGB32:
       
   332         caps = gst_caps_from_string ("video/x-raw-rgb, "
       
   333             "bpp = (int) 32, "
       
   334             "depth = (int) 24, "
       
   335             "endianness = (int) BIG_ENDIAN, "
       
   336             "red_mask = 0xFF000000, "
       
   337             "green_mask = 0x00FF0000, " "blue_mask = 0x0000FF00");
       
   338         break;
       
   339       default:
       
   340         g_assert_not_reached ();
       
   341         return NULL;
       
   342     }
       
   343   } else {
       
   344     caps = gst_caps_new_simple ("video/x-raw-yuv",
       
   345         "format", GST_TYPE_FOURCC, fourcc, NULL);
       
   346   }
       
   347 
       
   348   return caps;
       
   349 }
       
   350 
       
   351 static GstCaps *
       
   352 gst_v4lsrc_get_any_caps (void)
       
   353 {
       
   354   gint i;
       
   355   GstCaps *caps = gst_caps_new_empty (), *one;
       
   356 
       
   357   for (i = 0; all_palettes[i] != -1; i++) {
       
   358     one = gst_v4lsrc_palette_to_caps (all_palettes[i]);
       
   359     gst_caps_append (caps, one);
       
   360   }
       
   361 
       
   362   return caps;
       
   363 }
       
   364 
       
   365 static GstCaps *
       
   366 gst_v4lsrc_get_caps (GstBaseSrc * src)
       
   367 {
       
   368   GstCaps *list;
       
   369   GstV4lSrc *v4lsrc = GST_V4LSRC (src);
       
   370   struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap;
       
   371   gint width = GST_V4LELEMENT (src)->vcap.minwidth;
       
   372   gint height = GST_V4LELEMENT (src)->vcap.minheight;
       
   373   gint i;
       
   374   gint fps_n, fps_d;
       
   375   GList *item;
       
   376 
       
   377   if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
       
   378     return gst_v4lsrc_get_any_caps ();
       
   379   }
       
   380 
       
   381   if (!v4lsrc->autoprobe) {
       
   382     /* FIXME: query current caps and return those, with _any appended */
       
   383     return gst_v4lsrc_get_any_caps ();
       
   384   }
       
   385 
       
   386   if (!v4lsrc->colorspaces) {
       
   387     GST_DEBUG_OBJECT (v4lsrc, "Checking supported palettes");
       
   388     for (i = 0; all_palettes[i] != -1; i++) {
       
   389       /* try palette out */
       
   390       if (!gst_v4lsrc_try_capture (v4lsrc, width, height, all_palettes[i]))
       
   391         continue;
       
   392       GST_DEBUG_OBJECT (v4lsrc, "Added palette %d (%s) to supported list",
       
   393           all_palettes[i], gst_v4lsrc_palette_name (all_palettes[i]));
       
   394       v4lsrc->colorspaces = g_list_append (v4lsrc->colorspaces,
       
   395           GINT_TO_POINTER (all_palettes[i]));
       
   396     }
       
   397     GST_DEBUG_OBJECT (v4lsrc, "%d palette(s) supported",
       
   398         g_list_length (v4lsrc->colorspaces));
       
   399     if (v4lsrc->autoprobe_fps) {
       
   400       GST_DEBUG_OBJECT (v4lsrc, "autoprobing framerates");
       
   401       v4lsrc->fps_list = gst_v4lsrc_get_fps_list (v4lsrc);
       
   402     }
       
   403   }
       
   404 
       
   405 
       
   406   if (!gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d)) {
       
   407     fps_n = 0;
       
   408     fps_d = 1;
       
   409   }
       
   410 
       
   411   list = gst_caps_new_empty ();
       
   412   for (item = v4lsrc->colorspaces; item != NULL; item = item->next) {
       
   413     GstCaps *one;
       
   414 
       
   415     one = gst_v4lsrc_palette_to_caps (GPOINTER_TO_INT (item->data));
       
   416     if (!one) {
       
   417       GST_WARNING_OBJECT (v4lsrc, "Palette %d gave no caps\n",
       
   418           GPOINTER_TO_INT (item->data));
       
   419       continue;
       
   420     }
       
   421 
       
   422     GST_DEBUG_OBJECT (v4lsrc,
       
   423         "Device reports w: %d-%d, h: %d-%d, fps: %d/%d for palette %d",
       
   424         vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight,
       
   425         fps_n, fps_d, GPOINTER_TO_INT (item->data));
       
   426 
       
   427     if (vcap->minwidth < vcap->maxwidth) {
       
   428       gst_caps_set_simple (one, "width", GST_TYPE_INT_RANGE, vcap->minwidth,
       
   429           vcap->maxwidth, NULL);
       
   430     } else {
       
   431       gst_caps_set_simple (one, "width", G_TYPE_INT, vcap->minwidth, NULL);
       
   432     }
       
   433     if (vcap->minheight < vcap->maxheight) {
       
   434       gst_caps_set_simple (one, "height", GST_TYPE_INT_RANGE, vcap->minheight,
       
   435           vcap->maxheight, NULL);
       
   436     } else {
       
   437       gst_caps_set_simple (one, "height", G_TYPE_INT, vcap->minheight, NULL);
       
   438     }
       
   439 
       
   440     if (v4lsrc->autoprobe_fps) {
       
   441       GstStructure *structure = gst_caps_get_structure (one, 0);
       
   442 
       
   443       if (v4lsrc->fps_list) {
       
   444         gst_structure_set_value (structure, "framerate", v4lsrc->fps_list);
       
   445       } else {
       
   446         gst_structure_set (structure, "framerate", GST_TYPE_FRACTION,
       
   447             fps_n, fps_d, NULL);
       
   448       }
       
   449     } else {
       
   450       gst_caps_set_simple (one, "framerate", GST_TYPE_FRACTION_RANGE,
       
   451           1, 1, 100, 1, NULL);
       
   452     }
       
   453 
       
   454     GST_DEBUG_OBJECT (v4lsrc, "caps: %" GST_PTR_FORMAT, one);
       
   455     gst_caps_append (list, one);
       
   456   }
       
   457 
       
   458   return list;
       
   459 }
       
   460 
       
   461 static gboolean
       
   462 gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps)
       
   463 {
       
   464   GstV4lSrc *v4lsrc;
       
   465   guint32 fourcc;
       
   466   gint bpp, depth, w, h, palette = -1;
       
   467   const GValue *new_fps;
       
   468   gint cur_fps_n, cur_fps_d;
       
   469   GstStructure *structure;
       
   470   struct video_window *vwin;
       
   471 
       
   472   v4lsrc = GST_V4LSRC (src);
       
   473   vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
       
   474 
       
   475   /* if we're not open, punt -- we'll get setcaps'd later via negotiate */
       
   476   if (!GST_V4L_IS_OPEN (v4lsrc))
       
   477     return FALSE;
       
   478 
       
   479   /* make sure we stop capturing and dealloc buffers */
       
   480   if (GST_V4L_IS_ACTIVE (v4lsrc)) {
       
   481     if (!gst_v4lsrc_capture_stop (v4lsrc))
       
   482       return FALSE;
       
   483     if (!gst_v4lsrc_capture_deinit (v4lsrc))
       
   484       return FALSE;
       
   485   }
       
   486 
       
   487   /* it's fixed, one struct */
       
   488   structure = gst_caps_get_structure (caps, 0);
       
   489 
       
   490   if (strcmp (gst_structure_get_name (structure), "video/x-raw-yuv") == 0)
       
   491     gst_structure_get_fourcc (structure, "format", &fourcc);
       
   492   else
       
   493     fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', ' ');
       
   494 
       
   495   gst_structure_get_int (structure, "width", &w);
       
   496   gst_structure_get_int (structure, "height", &h);
       
   497   new_fps = gst_structure_get_value (structure, "framerate");
       
   498 
       
   499   /* set framerate if it's not already correct */
       
   500   if (!gst_v4lsrc_get_fps (v4lsrc, &cur_fps_n, &cur_fps_d))
       
   501     return FALSE;
       
   502 
       
   503   if (new_fps) {
       
   504     GST_DEBUG_OBJECT (v4lsrc, "linking with %dx%d at %d/%d fps", w, h,
       
   505         gst_value_get_fraction_numerator (new_fps),
       
   506         gst_value_get_fraction_denominator (new_fps));
       
   507 
       
   508     if (gst_value_get_fraction_numerator (new_fps) != cur_fps_n ||
       
   509         gst_value_get_fraction_denominator (new_fps) != cur_fps_d) {
       
   510       int fps_index = (gst_value_get_fraction_numerator (new_fps) * 16) /
       
   511           (gst_value_get_fraction_denominator (new_fps) * 15);
       
   512 
       
   513       GST_DEBUG_OBJECT (v4lsrc, "Trying to set fps index %d", fps_index);
       
   514       /* set bits 16 to 21 to 0 */
       
   515       vwin->flags &= (0x3F00 - 1);
       
   516       /* set bits 16 to 21 to the index */
       
   517       vwin->flags |= fps_index << 16;
       
   518       if (!gst_v4l_set_window_properties (GST_V4LELEMENT (v4lsrc))) {
       
   519         return FALSE;
       
   520       }
       
   521     }
       
   522   }
       
   523 
       
   524   switch (fourcc) {
       
   525     case GST_MAKE_FOURCC ('I', '4', '2', '0'):
       
   526       palette = VIDEO_PALETTE_YUV420P;
       
   527       v4lsrc->buffer_size = ((w + 1) & ~1) * ((h + 1) & ~1) * 1.5;
       
   528       break;
       
   529     case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
       
   530       palette = VIDEO_PALETTE_YUV422;
       
   531       v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2;
       
   532       break;
       
   533     case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
       
   534       palette = VIDEO_PALETTE_UYVY;
       
   535       v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2;
       
   536       break;
       
   537     case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
       
   538       palette = VIDEO_PALETTE_YUV411P;
       
   539       v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5;
       
   540       break;
       
   541     case GST_MAKE_FOURCC ('Y', '4', '1', 'P'):
       
   542       palette = VIDEO_PALETTE_YUV411;
       
   543       v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5;
       
   544       break;
       
   545     case GST_MAKE_FOURCC ('Y', 'U', 'V', '9'):
       
   546       palette = VIDEO_PALETTE_YUV410P;
       
   547       v4lsrc->buffer_size = ((w + 3) & ~3) * ((h + 3) & ~3) * 1.125;
       
   548       break;
       
   549     case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
       
   550       palette = VIDEO_PALETTE_YUV422P;
       
   551       v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2;
       
   552       break;
       
   553     case GST_MAKE_FOURCC ('R', 'G', 'B', ' '):
       
   554       gst_structure_get_int (structure, "depth", &depth);
       
   555       switch (depth) {
       
   556         case 15:
       
   557           palette = VIDEO_PALETTE_RGB555;
       
   558           v4lsrc->buffer_size = w * h * 2;
       
   559           break;
       
   560         case 16:
       
   561           palette = VIDEO_PALETTE_RGB565;
       
   562           v4lsrc->buffer_size = w * h * 2;
       
   563           break;
       
   564         case 24:
       
   565           gst_structure_get_int (structure, "bpp", &bpp);
       
   566           switch (bpp) {
       
   567             case 24:
       
   568               palette = VIDEO_PALETTE_RGB24;
       
   569               v4lsrc->buffer_size = w * h * 3;
       
   570               break;
       
   571             case 32:
       
   572               palette = VIDEO_PALETTE_RGB32;
       
   573               v4lsrc->buffer_size = w * h * 4;
       
   574               break;
       
   575             default:
       
   576               break;
       
   577           }
       
   578           break;
       
   579         default:
       
   580           break;
       
   581       }
       
   582       break;
       
   583     default:
       
   584       break;
       
   585   }
       
   586 
       
   587   if (palette == -1) {
       
   588     GST_WARNING_OBJECT (v4lsrc, "palette for fourcc %" GST_FOURCC_FORMAT
       
   589         " is -1, refusing link", GST_FOURCC_ARGS (fourcc));
       
   590     return FALSE;
       
   591   }
       
   592 
       
   593   GST_DEBUG_OBJECT (v4lsrc, "trying to set_capture %dx%d, palette %d",
       
   594       w, h, palette);
       
   595   /* this only fills in v4lsrc->mmap values */
       
   596   if (!gst_v4lsrc_set_capture (v4lsrc, w, h, palette)) {
       
   597     GST_WARNING_OBJECT (v4lsrc, "could not set_capture %dx%d, palette %d",
       
   598         w, h, palette);
       
   599     return FALSE;
       
   600   }
       
   601 
       
   602   /* first try the negotiated settings using try_capture */
       
   603   if (!gst_v4lsrc_try_capture (v4lsrc, w, h, palette)) {
       
   604     GST_DEBUG_OBJECT (v4lsrc, "failed trying palette %d for %dx%d", palette,
       
   605         w, h);
       
   606     return FALSE;
       
   607   }
       
   608 
       
   609   if (!gst_v4lsrc_capture_init (v4lsrc))
       
   610     return FALSE;
       
   611 
       
   612   if (!gst_v4lsrc_capture_start (v4lsrc))
       
   613     return FALSE;
       
   614 
       
   615   return TRUE;
       
   616 }
       
   617 
       
   618 static gboolean
       
   619 gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query)
       
   620 {
       
   621   GstV4lSrc *v4lsrc;
       
   622   gboolean res = FALSE;
       
   623 
       
   624   v4lsrc = GST_V4LSRC (bsrc);
       
   625 
       
   626   switch (GST_QUERY_TYPE (query)) {
       
   627     case GST_QUERY_LATENCY:
       
   628     {
       
   629       GstClockTime min_latency, max_latency;
       
   630       gint fps_n, fps_d;
       
   631 
       
   632       /* device must be open */
       
   633       if (!GST_V4L_IS_OPEN (v4lsrc))
       
   634         goto done;
       
   635 
       
   636       /* we must have a framerate */
       
   637       if (!(res = gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d)))
       
   638         goto done;
       
   639 
       
   640       /* min latency is the time to capture one frame */
       
   641       min_latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
       
   642 
       
   643       /* max latency is total duration of the frame buffer */
       
   644       max_latency = v4lsrc->mbuf.frames * min_latency;
       
   645 
       
   646       GST_DEBUG_OBJECT (bsrc,
       
   647           "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
       
   648           GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
       
   649 
       
   650       /* we are always live, the min latency is 1 frame and the max latency is
       
   651        * the complete buffer of frames. */
       
   652       gst_query_set_latency (query, TRUE, min_latency, max_latency);
       
   653 
       
   654       res = TRUE;
       
   655       break;
       
   656     }
       
   657     default:
       
   658       res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
       
   659       break;
       
   660   }
       
   661 done:
       
   662   return res;
       
   663 }
       
   664 
       
   665 /* start and stop are not symmetric -- start will open the device, but not start
       
   666    capture. it's setcaps that will start capture, which is called via basesrc's
       
   667    negotiate method. stop will both stop capture and close the device.
       
   668  */
       
   669 static gboolean
       
   670 gst_v4lsrc_start (GstBaseSrc * src)
       
   671 {
       
   672   GstV4lSrc *v4lsrc = GST_V4LSRC (src);
       
   673 
       
   674   if (!GST_BASE_SRC_CLASS (parent_class)->start (src))
       
   675     return FALSE;
       
   676 
       
   677   v4lsrc->offset = 0;
       
   678 
       
   679   return TRUE;
       
   680 }
       
   681 
       
   682 static gboolean
       
   683 gst_v4lsrc_stop (GstBaseSrc * src)
       
   684 {
       
   685   GstV4lSrc *v4lsrc = GST_V4LSRC (src);
       
   686 
       
   687   if (GST_V4L_IS_ACTIVE (v4lsrc) && !gst_v4lsrc_capture_stop (v4lsrc))
       
   688     return FALSE;
       
   689 
       
   690   if (GST_V4LELEMENT (v4lsrc)->buffer != NULL) {
       
   691     if (!gst_v4lsrc_capture_deinit (v4lsrc))
       
   692       return FALSE;
       
   693   }
       
   694 
       
   695   if (!GST_BASE_SRC_CLASS (parent_class)->stop (src))
       
   696     return FALSE;
       
   697 
       
   698   g_list_free (v4lsrc->colorspaces);
       
   699   v4lsrc->colorspaces = NULL;
       
   700 
       
   701   if (v4lsrc->fps_list) {
       
   702     g_value_unset (v4lsrc->fps_list);
       
   703     g_free (v4lsrc->fps_list);
       
   704     v4lsrc->fps_list = NULL;
       
   705   }
       
   706 
       
   707   return TRUE;
       
   708 }
       
   709 
       
   710 static GstFlowReturn
       
   711 gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** buf)
       
   712 {
       
   713   GstV4lSrc *v4lsrc;
       
   714   gint num;
       
   715 
       
   716   v4lsrc = GST_V4LSRC (src);
       
   717 
       
   718   /* grab a frame from the device */
       
   719   if (!gst_v4lsrc_grab_frame (v4lsrc, &num))
       
   720     return GST_FLOW_ERROR;
       
   721 
       
   722   *buf = gst_v4lsrc_buffer_new (v4lsrc, num);
       
   723 
       
   724   if (v4lsrc->copy_mode) {
       
   725     GstBuffer *copy = gst_buffer_copy (*buf);
       
   726 
       
   727     gst_buffer_unref (*buf);
       
   728     *buf = copy;
       
   729   }
       
   730 
       
   731   return GST_FLOW_OK;
       
   732 }