gst_plugins_base/sys/v4l/v4lsrc_calls.c
branchRCL_3
changeset 30 7e817e7e631c
parent 0 0e761a78d257
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
       
     1 /* GStreamer
       
     2  *
       
     3  * v4lsrc_calls.c: generic V4L source functions
       
     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 <stdlib.h>
       
    28 #include <sys/types.h>
       
    29 #include <sys/stat.h>
       
    30 #include <fcntl.h>
       
    31 #include <sys/ioctl.h>
       
    32 #include <sys/mman.h>
       
    33 #include <string.h>
       
    34 #include <errno.h>
       
    35 #include "v4lsrc_calls.h"
       
    36 #include <sys/time.h>
       
    37 
       
    38 /* number of buffers to be queued *at least* before syncing */
       
    39 #define MIN_BUFFERS_QUEUED 2
       
    40 
       
    41 /* On some systems MAP_FAILED seems to be missing */
       
    42 #ifndef MAP_FAILED
       
    43 #define MAP_FAILED ( (caddr_t) -1 )
       
    44 #endif
       
    45 
       
    46 GST_DEBUG_CATEGORY_EXTERN (v4l_debug);
       
    47 
       
    48 #define GST_CAT_DEFAULT v4l_debug
       
    49 
       
    50 #ifndef GST_DISABLE_GST_DEBUG
       
    51 /* palette names */
       
    52 static const char *v4l_palette_name[] = {
       
    53   "",                           /* 0 */
       
    54   "grayscale",                  /* VIDEO_PALETTE_GREY */
       
    55   "Hi-420",                     /* VIDEO_PALETTE_HI420 */
       
    56   "16-bit RGB (RGB-565)",       /* VIDEO_PALETTE_RB565 */
       
    57   "24-bit RGB",                 /* VIDEO_PALETTE_RGB24 */
       
    58   "32-bit RGB",                 /* VIDEO_PALETTE_RGB32 */
       
    59   "15-bit RGB (RGB-555)",       /* VIDEO_PALETTE_RGB555 */
       
    60   "YUV-4:2:2 (packed)",         /* VIDEO_PALETTE_YUV422 */
       
    61   "YUYV",                       /* VIDEO_PALETTE_YUYV */
       
    62   "UYVY",                       /* VIDEO_PALETTE_UYVY */
       
    63   "YUV-4:2:0 (packed)",         /* VIDEO_PALETTE_YUV420 */
       
    64   "YUV-4:1:1 (packed)",         /* VIDEO_PALETTE_YUV411 */
       
    65   "Raw",                        /* VIDEO_PALETTE_RAW */
       
    66   "YUV-4:2:2 (planar)",         /* VIDEO_PALETTE_YUV422P */
       
    67   "YUV-4:1:1 (planar)",         /* VIDEO_PALETTE_YUV411P */
       
    68   "YUV-4:2:0 (planar)/I420",    /* VIDEO_PALETTE_YUV420P */
       
    69   "YUV-4:1:0 (planar)"          /* VIDEO_PALETTE_YUV410P */
       
    70 };
       
    71 #endif
       
    72 
       
    73 /******************************************************
       
    74  * gst_v4lsrc_queue_frame():
       
    75  *   queue a frame for capturing
       
    76  *   (ie. instruct the hardware to start capture)
       
    77  *   Requires queue_state lock to be held!
       
    78  * return value: TRUE on success, FALSE on error
       
    79  ******************************************************/
       
    80 
       
    81 static gboolean
       
    82 gst_v4lsrc_queue_frame (GstV4lSrc * v4lsrc, gint num)
       
    83 {
       
    84   GST_LOG_OBJECT (v4lsrc, "queueing frame %d", num);
       
    85 
       
    86   if (v4lsrc->frame_queue_state[num] != QUEUE_STATE_READY_FOR_QUEUE) {
       
    87     return FALSE;
       
    88   }
       
    89 
       
    90   /* instruct the driver to prepare capture using buffer frame num */
       
    91   v4lsrc->mmap.frame = num;
       
    92   if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd,
       
    93           VIDIOCMCAPTURE, &(v4lsrc->mmap)) < 0) {
       
    94     GST_ELEMENT_ERROR (v4lsrc, RESOURCE, WRITE, (NULL),
       
    95         ("Error queueing a buffer (%d): %s", num, g_strerror (errno)));
       
    96     return FALSE;
       
    97   }
       
    98 
       
    99   v4lsrc->frame_queue_state[num] = QUEUE_STATE_QUEUED;
       
   100   v4lsrc->num_queued++;
       
   101 
       
   102   return TRUE;
       
   103 }
       
   104 
       
   105 /******************************************************
       
   106  * gst_v4lsrc_hard_sync_frame(GstV4lSrc *v4lsrc,gint num)
       
   107  *   sync a frame and set the timestamp correctly
       
   108  *   Requires queue_state lock to be held
       
   109  *****************************************************/
       
   110 
       
   111 static gboolean
       
   112 gst_v4lsrc_sync_frame (GstV4lSrc * v4lsrc, gint num)
       
   113 {
       
   114   GST_LOG_OBJECT (v4lsrc, "VIOIOCSYNC on frame %d", num);
       
   115 
       
   116   if (v4lsrc->frame_queue_state[num] != QUEUE_STATE_QUEUED) {
       
   117     return FALSE;
       
   118   }
       
   119 
       
   120   while (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCSYNC, &num) < 0) {
       
   121     /* if the sync() got interrupted, we can retry */
       
   122     if (errno != EINTR) {
       
   123       v4lsrc->frame_queue_state[num] = QUEUE_STATE_ERROR;
       
   124       GST_ELEMENT_ERROR (v4lsrc, RESOURCE, SYNC, (NULL), GST_ERROR_SYSTEM);
       
   125       return FALSE;
       
   126     }
       
   127     GST_DEBUG_OBJECT (v4lsrc, "Sync got interrupted");
       
   128   }
       
   129   GST_LOG_OBJECT (v4lsrc, "VIOIOCSYNC on frame %d done", num);
       
   130 
       
   131   v4lsrc->frame_queue_state[num] = QUEUE_STATE_SYNCED;
       
   132   v4lsrc->num_queued--;
       
   133 
       
   134   return TRUE;
       
   135 }
       
   136 
       
   137 /******************************************************
       
   138  * gst_v4lsrc_set_capture():
       
   139  *   set capture parameters, palette = VIDEO_PALETTE_*
       
   140  * return value: TRUE on success, FALSE on error
       
   141  ******************************************************/
       
   142 
       
   143 gboolean
       
   144 gst_v4lsrc_set_capture (GstV4lSrc * v4lsrc,
       
   145     gint width, gint height, gint palette)
       
   146 {
       
   147   GST_DEBUG_OBJECT (v4lsrc,
       
   148       "capture properties set to %dx%d, palette %d", width, height, palette);
       
   149 
       
   150   v4lsrc->mmap.width = width;
       
   151   v4lsrc->mmap.height = height;
       
   152   v4lsrc->mmap.format = palette;
       
   153 
       
   154   return TRUE;
       
   155 }
       
   156 
       
   157 
       
   158 /******************************************************
       
   159  * gst_v4lsrc_capture_init():
       
   160  *   initialize the capture system
       
   161  * return value: TRUE on success, FALSE on error
       
   162  ******************************************************/
       
   163 
       
   164 gboolean
       
   165 gst_v4lsrc_capture_init (GstV4lSrc * v4lsrc)
       
   166 {
       
   167   GST_DEBUG_OBJECT (v4lsrc, "initting capture subsystem");
       
   168   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc));
       
   169   GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lsrc));
       
   170 
       
   171   /* request the mmap buffer info:
       
   172    * total size of mmap buffer, number of frames, offsets of frames */
       
   173   if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCGMBUF,
       
   174           &(v4lsrc->mbuf)) < 0) {
       
   175     GST_ELEMENT_ERROR (v4lsrc, RESOURCE, READ, (NULL),
       
   176         ("Error getting buffer information: %s", g_strerror (errno)));
       
   177     return FALSE;
       
   178   }
       
   179 
       
   180   if (v4lsrc->mbuf.frames < MIN_BUFFERS_QUEUED) {
       
   181     GST_ELEMENT_ERROR (v4lsrc, RESOURCE, READ, (NULL),
       
   182         ("Not enough buffers. We got %d, we want at least %d",
       
   183             v4lsrc->mbuf.frames, MIN_BUFFERS_QUEUED));
       
   184     return FALSE;
       
   185   }
       
   186 
       
   187   GST_INFO_OBJECT (v4lsrc, "Got %d buffers (\'%s\') with total size %d KB",
       
   188       v4lsrc->mbuf.frames, v4l_palette_name[v4lsrc->mmap.format],
       
   189       v4lsrc->mbuf.size / (v4lsrc->mbuf.frames * 1024));
       
   190 
       
   191   /* keep track of queued buffers */
       
   192   v4lsrc->frame_queue_state = (gint8 *)
       
   193       g_malloc (sizeof (gint8) * v4lsrc->mbuf.frames);
       
   194 
       
   195   /* lock for the frame_state */
       
   196   v4lsrc->mutex_queue_state = g_mutex_new ();
       
   197   v4lsrc->cond_queue_state = g_cond_new ();
       
   198 
       
   199   /* Map the buffers */
       
   200   GST_V4LELEMENT (v4lsrc)->buffer = mmap (NULL, v4lsrc->mbuf.size,
       
   201       PROT_READ | PROT_WRITE, MAP_SHARED, GST_V4LELEMENT (v4lsrc)->video_fd, 0);
       
   202   if (GST_V4LELEMENT (v4lsrc)->buffer == MAP_FAILED) {
       
   203     GST_ELEMENT_ERROR (v4lsrc, RESOURCE, OPEN_READ_WRITE, (NULL),
       
   204         ("Error mapping video buffers: %s", g_strerror (errno)));
       
   205     GST_V4LELEMENT (v4lsrc)->buffer = NULL;
       
   206     return FALSE;
       
   207   }
       
   208 
       
   209   return TRUE;
       
   210 }
       
   211 
       
   212 
       
   213 /******************************************************
       
   214  * gst_v4lsrc_capture_start():
       
   215  *   start streaming capture
       
   216  * return value: TRUE on success, FALSE on error
       
   217  ******************************************************/
       
   218 
       
   219 gboolean
       
   220 gst_v4lsrc_capture_start (GstV4lSrc * v4lsrc)
       
   221 {
       
   222   int n;
       
   223 
       
   224   GST_DEBUG_OBJECT (v4lsrc, "starting capture");
       
   225   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc));
       
   226   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc));
       
   227 
       
   228   g_mutex_lock (v4lsrc->mutex_queue_state);
       
   229 
       
   230   v4lsrc->quit = FALSE;
       
   231   v4lsrc->num_queued = 0;
       
   232   v4lsrc->sync_frame = 0;
       
   233   v4lsrc->queue_frame = 0;
       
   234 
       
   235   /* set all buffers ready to queue, and queue captures to the device.
       
   236    * This starts streaming capture */
       
   237   for (n = 0; n < v4lsrc->mbuf.frames; n++) {
       
   238     v4lsrc->frame_queue_state[n] = QUEUE_STATE_READY_FOR_QUEUE;
       
   239     if (!gst_v4lsrc_queue_frame (v4lsrc, n)) {
       
   240       g_mutex_unlock (v4lsrc->mutex_queue_state);
       
   241       gst_v4lsrc_capture_stop (v4lsrc);
       
   242       return FALSE;
       
   243     }
       
   244   }
       
   245 
       
   246   v4lsrc->is_capturing = TRUE;
       
   247   g_mutex_unlock (v4lsrc->mutex_queue_state);
       
   248 
       
   249   return TRUE;
       
   250 }
       
   251 
       
   252 
       
   253 /******************************************************
       
   254  * gst_v4lsrc_grab_frame():
       
   255  *   capture one frame during streaming capture
       
   256  * return value: TRUE on success, FALSE on error
       
   257  ******************************************************/
       
   258 
       
   259 gboolean
       
   260 gst_v4lsrc_grab_frame (GstV4lSrc * v4lsrc, gint * num)
       
   261 {
       
   262   GST_LOG_OBJECT (v4lsrc, "grabbing frame %d", *num);
       
   263   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc));
       
   264   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc));
       
   265 
       
   266   g_mutex_lock (v4lsrc->mutex_queue_state);
       
   267 
       
   268   /* do we have enough frames? */
       
   269   while (v4lsrc->num_queued < MIN_BUFFERS_QUEUED ||
       
   270       v4lsrc->frame_queue_state[v4lsrc->queue_frame] ==
       
   271       QUEUE_STATE_READY_FOR_QUEUE) {
       
   272     while (v4lsrc->frame_queue_state[v4lsrc->queue_frame] !=
       
   273         QUEUE_STATE_READY_FOR_QUEUE && !v4lsrc->quit) {
       
   274       GST_DEBUG_OBJECT (v4lsrc,
       
   275           "Waiting for frames to become available (queued %d < minimum %d)",
       
   276           v4lsrc->num_queued, MIN_BUFFERS_QUEUED);
       
   277       g_cond_wait (v4lsrc->cond_queue_state, v4lsrc->mutex_queue_state);
       
   278     }
       
   279     if (v4lsrc->quit) {
       
   280       g_mutex_unlock (v4lsrc->mutex_queue_state);
       
   281       return FALSE;
       
   282     }
       
   283     if (!gst_v4lsrc_queue_frame (v4lsrc, v4lsrc->queue_frame)) {
       
   284       g_mutex_unlock (v4lsrc->mutex_queue_state);
       
   285       return FALSE;
       
   286     }
       
   287     v4lsrc->queue_frame = (v4lsrc->queue_frame + 1) % v4lsrc->mbuf.frames;
       
   288   }
       
   289 
       
   290   /* syncing on the buffer grabs it */
       
   291   *num = v4lsrc->sync_frame;
       
   292   if (!gst_v4lsrc_sync_frame (v4lsrc, *num)) {
       
   293     g_mutex_unlock (v4lsrc->mutex_queue_state);
       
   294     return FALSE;
       
   295   }
       
   296   v4lsrc->sync_frame = (v4lsrc->sync_frame + 1) % v4lsrc->mbuf.frames;
       
   297 
       
   298   g_mutex_unlock (v4lsrc->mutex_queue_state);
       
   299 
       
   300   return TRUE;
       
   301 }
       
   302 
       
   303 
       
   304 /******************************************************
       
   305  * gst_v4lsrc_get_buffer():
       
   306  *   get the address of the given frame number in the mmap'd buffer
       
   307  * return value: the buffer's address or NULL
       
   308  ******************************************************/
       
   309 
       
   310 guint8 *
       
   311 gst_v4lsrc_get_buffer (GstV4lSrc * v4lsrc, gint num)
       
   312 {
       
   313   if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc)) ||
       
   314       !GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc)))
       
   315     return NULL;
       
   316 
       
   317   if (num < 0 || num >= v4lsrc->mbuf.frames)
       
   318     return NULL;
       
   319 
       
   320   return GST_V4LELEMENT (v4lsrc)->buffer + v4lsrc->mbuf.offsets[num];
       
   321 }
       
   322 
       
   323 
       
   324 /******************************************************
       
   325  * gst_v4lsrc_requeue_frame():
       
   326  *   re-queue a frame after we're done with the buffer
       
   327  * return value: TRUE on success, FALSE on error
       
   328  ******************************************************/
       
   329 
       
   330 gboolean
       
   331 gst_v4lsrc_requeue_frame (GstV4lSrc * v4lsrc, gint num)
       
   332 {
       
   333   GST_LOG_OBJECT (v4lsrc, "requeueing frame %d", num);
       
   334   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc));
       
   335   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc));
       
   336 
       
   337   /* mark frame as 'ready to requeue' */
       
   338   g_mutex_lock (v4lsrc->mutex_queue_state);
       
   339 
       
   340   if (v4lsrc->frame_queue_state[num] != QUEUE_STATE_SYNCED) {
       
   341     GST_ELEMENT_ERROR (v4lsrc, RESOURCE, TOO_LAZY, (NULL),
       
   342         ("Invalid state %d (expected %d), can't requeue",
       
   343             v4lsrc->frame_queue_state[num], QUEUE_STATE_SYNCED));
       
   344     return FALSE;
       
   345   }
       
   346 
       
   347   v4lsrc->frame_queue_state[num] = QUEUE_STATE_READY_FOR_QUEUE;
       
   348 
       
   349   /* let an optional wait know */
       
   350   g_cond_broadcast (v4lsrc->cond_queue_state);
       
   351 
       
   352   g_mutex_unlock (v4lsrc->mutex_queue_state);
       
   353 
       
   354   return TRUE;
       
   355 }
       
   356 
       
   357 
       
   358 /******************************************************
       
   359  * gst_v4lsrc_capture_stop():
       
   360  *   stop streaming capture
       
   361  * return value: TRUE on success, FALSE on error
       
   362  ******************************************************/
       
   363 
       
   364 gboolean
       
   365 gst_v4lsrc_capture_stop (GstV4lSrc * v4lsrc)
       
   366 {
       
   367   GST_DEBUG_OBJECT (v4lsrc, "stopping capture");
       
   368   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc));
       
   369   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc));
       
   370 
       
   371   g_mutex_lock (v4lsrc->mutex_queue_state);
       
   372   v4lsrc->is_capturing = FALSE;
       
   373 
       
   374   /* make an optional pending wait stop */
       
   375   v4lsrc->quit = TRUE;
       
   376   g_cond_broadcast (v4lsrc->cond_queue_state);
       
   377 
       
   378   /* sync on remaining frames */
       
   379   while (1) {
       
   380     if (v4lsrc->frame_queue_state[v4lsrc->sync_frame] == QUEUE_STATE_QUEUED) {
       
   381       gst_v4lsrc_sync_frame (v4lsrc, v4lsrc->sync_frame);
       
   382       v4lsrc->sync_frame = (v4lsrc->sync_frame + 1) % v4lsrc->mbuf.frames;
       
   383     } else {
       
   384       break;
       
   385     }
       
   386   }
       
   387 
       
   388   g_mutex_unlock (v4lsrc->mutex_queue_state);
       
   389 
       
   390   return TRUE;
       
   391 }
       
   392 
       
   393 
       
   394 /******************************************************
       
   395  * gst_v4lsrc_capture_deinit():
       
   396  *   deinitialize the capture system
       
   397  * return value: TRUE on success, FALSE on error
       
   398  ******************************************************/
       
   399 
       
   400 gboolean
       
   401 gst_v4lsrc_capture_deinit (GstV4lSrc * v4lsrc)
       
   402 {
       
   403   GST_DEBUG_OBJECT (v4lsrc, "quitting capture subsystem");
       
   404   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc));
       
   405   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lsrc));
       
   406 
       
   407   /* free buffer tracker */
       
   408   g_mutex_free (v4lsrc->mutex_queue_state);
       
   409   v4lsrc->mutex_queue_state = NULL;
       
   410   g_cond_free (v4lsrc->cond_queue_state);
       
   411   v4lsrc->cond_queue_state = NULL;
       
   412   g_free (v4lsrc->frame_queue_state);
       
   413   v4lsrc->frame_queue_state = NULL;
       
   414 
       
   415   /* unmap the buffer */
       
   416   if (munmap (GST_V4LELEMENT (v4lsrc)->buffer, v4lsrc->mbuf.size) == -1) {
       
   417     GST_ELEMENT_ERROR (v4lsrc, RESOURCE, CLOSE, (NULL),
       
   418         ("error munmap'ing capture buffer: %s", g_strerror (errno)));
       
   419     return FALSE;
       
   420   }
       
   421   GST_V4LELEMENT (v4lsrc)->buffer = NULL;
       
   422 
       
   423   return TRUE;
       
   424 }
       
   425 
       
   426 /******************************************************
       
   427  * gst_v4lsrc_try_capture():
       
   428  *   try out a capture on the device
       
   429  *   This has to be done before initializing the
       
   430  *   actual capture system, to make sure we don't
       
   431  *   mess up anything. So we need to mini-mmap()
       
   432  *   a buffer here, queue and sync on one buffer,
       
   433  *   and unmap it.
       
   434  *   This is ugly, yes, I know - but it's a major
       
   435  *   design flaw of v4l1 that you don't know in
       
   436  *   advance which formats will be supported...
       
   437  *   This is better than "just assuming that it'll
       
   438  *   work"...
       
   439  * return value: TRUE on success, FALSE on error
       
   440  ******************************************************/
       
   441 
       
   442 gboolean
       
   443 gst_v4lsrc_try_capture (GstV4lSrc * v4lsrc, gint width, gint height,
       
   444     gint palette)
       
   445 {
       
   446   /* so, we need a buffer and some more stuff */
       
   447   int frame = 0;
       
   448   guint8 *buffer;
       
   449   struct video_mbuf vmbuf;
       
   450   struct video_mmap vmmap;
       
   451 
       
   452   GST_DEBUG_OBJECT (v4lsrc, "try out %dx%d, palette format %d (%s)",
       
   453       width, height, palette, v4l_palette_name[palette]);
       
   454   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lsrc));
       
   455   GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lsrc));
       
   456 
       
   457   /* let's start by requesting a buffer and mmap()'ing it */
       
   458   if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCGMBUF, &vmbuf) < 0) {
       
   459     GST_ELEMENT_ERROR (v4lsrc, RESOURCE, READ, (NULL),
       
   460         ("Error getting buffer information: %s", g_strerror (errno)));
       
   461     return FALSE;
       
   462   }
       
   463   /* Map the buffers */
       
   464   buffer = mmap (NULL, vmbuf.size, PROT_READ | PROT_WRITE,
       
   465       MAP_SHARED, GST_V4LELEMENT (v4lsrc)->video_fd, 0);
       
   466   if (buffer == MAP_FAILED) {
       
   467     GST_ELEMENT_ERROR (v4lsrc, RESOURCE, OPEN_READ_WRITE, (NULL),
       
   468         ("Error mapping our try-out buffer: %s", g_strerror (errno)));
       
   469     return FALSE;
       
   470   }
       
   471 
       
   472   /* now that we have a buffer, let's try out our format */
       
   473   vmmap.width = width;
       
   474   vmmap.height = height;
       
   475   vmmap.format = palette;
       
   476   vmmap.frame = frame;
       
   477   if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCMCAPTURE, &vmmap) < 0) {
       
   478     if (errno != EINVAL)        /* our format failed! */
       
   479       GST_ERROR_OBJECT (v4lsrc,
       
   480           "Error queueing our try-out buffer: %s", g_strerror (errno));
       
   481     munmap (buffer, vmbuf.size);
       
   482     return FALSE;
       
   483   }
       
   484 
       
   485   if (ioctl (GST_V4LELEMENT (v4lsrc)->video_fd, VIDIOCSYNC, &frame) < 0) {
       
   486     GST_ELEMENT_ERROR (v4lsrc, RESOURCE, SYNC, (NULL), GST_ERROR_SYSTEM);
       
   487     munmap (buffer, vmbuf.size);
       
   488     return FALSE;
       
   489   }
       
   490 
       
   491   munmap (buffer, vmbuf.size);
       
   492 
       
   493   /* if we got here, it worked! woohoo, the format is supported! */
       
   494   return TRUE;
       
   495 }
       
   496 
       
   497 #ifndef GST_DISABLE_GST_DEBUG
       
   498 const char *
       
   499 gst_v4lsrc_palette_name (int i)
       
   500 {
       
   501   return v4l_palette_name[i];
       
   502 }
       
   503 #endif
       
   504 
       
   505 gboolean
       
   506 gst_v4lsrc_get_fps (GstV4lSrc * v4lsrc, gint * fps_n, gint * fps_d)
       
   507 {
       
   508   gint norm;
       
   509   gint fps_index;
       
   510   struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
       
   511 
       
   512   /* check if we have vwin window properties giving a framerate,
       
   513    * as is done for webcams
       
   514    * See http://www.smcc.demon.nl/webcam/api.html
       
   515    * which is used for the Philips and qce-ga drivers */
       
   516   fps_index = (vwin->flags >> 16) & 0x3F;       /* 6 bit index for framerate */
       
   517 
       
   518   /* webcams have a non-zero fps_index */
       
   519   if (fps_index != 0) {
       
   520     /* index of 16 corresponds to 15 fps */
       
   521     GST_DEBUG_OBJECT (v4lsrc, "device reports fps of %d/%d (%.4f)",
       
   522         fps_index * 15, 16, fps_index * 15.0 / 16);
       
   523 
       
   524     if (fps_n)
       
   525       *fps_n = fps_index * 15;
       
   526     if (fps_d)
       
   527       *fps_d = 16;
       
   528 
       
   529     return TRUE;
       
   530   }
       
   531 
       
   532   /* removed fps estimation code here */
       
   533 
       
   534   /* if that failed ... */
       
   535 
       
   536   if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc)))
       
   537     return FALSE;
       
   538 
       
   539   if (!gst_v4l_get_chan_norm (GST_V4LELEMENT (v4lsrc), NULL, &norm))
       
   540     return FALSE;
       
   541 
       
   542   if (norm == VIDEO_MODE_NTSC) {
       
   543     if (fps_n)
       
   544       *fps_n = 30000;
       
   545     if (fps_d)
       
   546       *fps_d = 1001;
       
   547   } else {
       
   548     if (fps_n)
       
   549       *fps_n = 25;
       
   550     if (fps_d)
       
   551       *fps_d = 1;
       
   552   }
       
   553 
       
   554   return TRUE;
       
   555 }
       
   556 
       
   557 /* get a list of possible framerates
       
   558  * this is only done for webcams;
       
   559  * other devices return NULL here.
       
   560  * this function takes a LONG time to execute.
       
   561  */
       
   562 GValue *
       
   563 gst_v4lsrc_get_fps_list (GstV4lSrc * v4lsrc)
       
   564 {
       
   565   gint fps_index;
       
   566   struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
       
   567   GstV4lElement *v4lelement = GST_V4LELEMENT (v4lsrc);
       
   568 
       
   569   /* check if we have vwin window properties giving a framerate,
       
   570    * as is done for webcams
       
   571    * See http://www.smcc.demon.nl/webcam/api.html
       
   572    * which is used for the Philips and qce-ga drivers */
       
   573   fps_index = (vwin->flags >> 16) & 0x3F;       /* 6 bit index for framerate */
       
   574 
       
   575   /* webcams have a non-zero fps_index */
       
   576   if (fps_index == 0) {
       
   577     GST_DEBUG_OBJECT (v4lsrc, "fps_index is 0, no webcam");
       
   578     return NULL;
       
   579   }
       
   580   GST_DEBUG_OBJECT (v4lsrc, "fps_index is %d, so webcam", fps_index);
       
   581 
       
   582   {
       
   583     int i;
       
   584     GValue *list = NULL;
       
   585     GValue value = { 0 };
       
   586 
       
   587     /* webcam detected, so try all framerates and return a list */
       
   588 
       
   589     list = g_new0 (GValue, 1);
       
   590     g_value_init (list, GST_TYPE_LIST);
       
   591 
       
   592     /* index of 16 corresponds to 15 fps */
       
   593     GST_DEBUG_OBJECT (v4lsrc, "device reports fps of %d/%d (%.4f)",
       
   594         fps_index * 15, 16, fps_index * 15.0 / 16);
       
   595     for (i = 0; i < 63; ++i) {
       
   596       /* set bits 16 to 21 to 0 */
       
   597       vwin->flags &= (0x3F00 - 1);
       
   598       /* set bits 16 to 21 to the index */
       
   599       vwin->flags |= i << 16;
       
   600       if (gst_v4l_set_window_properties (v4lelement)) {
       
   601         /* setting it succeeded.  FIXME: get it and check. */
       
   602         g_value_init (&value, GST_TYPE_FRACTION);
       
   603         gst_value_set_fraction (&value, i * 15, 16);
       
   604         gst_value_list_append_value (list, &value);
       
   605         g_value_unset (&value);
       
   606       }
       
   607     }
       
   608     /* FIXME: set back the original fps_index */
       
   609     vwin->flags &= (0x3F00 - 1);
       
   610     vwin->flags |= fps_index << 16;
       
   611     gst_v4l_set_window_properties (v4lelement);
       
   612     return list;
       
   613   }
       
   614   return NULL;
       
   615 }
       
   616 
       
   617 #define GST_TYPE_V4LSRC_BUFFER (gst_v4lsrc_buffer_get_type())
       
   618 #define GST_IS_V4LSRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4LSRC_BUFFER))
       
   619 #define GST_V4LSRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4LSRC_BUFFER, GstV4lSrcBuffer))
       
   620 
       
   621 typedef struct _GstV4lSrcBuffer
       
   622 {
       
   623   GstBuffer buffer;
       
   624 
       
   625   GstV4lSrc *v4lsrc;
       
   626 
       
   627   gint num;
       
   628 } GstV4lSrcBuffer;
       
   629 
       
   630 static void gst_v4lsrc_buffer_class_init (gpointer g_class,
       
   631     gpointer class_data);
       
   632 static void gst_v4lsrc_buffer_init (GTypeInstance * instance, gpointer g_class);
       
   633 static void gst_v4lsrc_buffer_finalize (GstV4lSrcBuffer * v4lsrc_buffer);
       
   634 
       
   635 static GstBufferClass *v4lbuffer_parent_class = NULL;
       
   636 
       
   637 static GType
       
   638 gst_v4lsrc_buffer_get_type (void)
       
   639 {
       
   640   static GType _gst_v4lsrc_buffer_type;
       
   641 
       
   642   if (G_UNLIKELY (_gst_v4lsrc_buffer_type == 0)) {
       
   643     static const GTypeInfo v4lsrc_buffer_info = {
       
   644       sizeof (GstBufferClass),
       
   645       NULL,
       
   646       NULL,
       
   647       gst_v4lsrc_buffer_class_init,
       
   648       NULL,
       
   649       NULL,
       
   650       sizeof (GstV4lSrcBuffer),
       
   651       0,
       
   652       gst_v4lsrc_buffer_init,
       
   653       NULL
       
   654     };
       
   655     _gst_v4lsrc_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
       
   656         "GstV4lSrcBuffer", &v4lsrc_buffer_info, 0);
       
   657   }
       
   658   return _gst_v4lsrc_buffer_type;
       
   659 }
       
   660 
       
   661 static void
       
   662 gst_v4lsrc_buffer_class_init (gpointer g_class, gpointer class_data)
       
   663 {
       
   664   GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
       
   665 
       
   666   v4lbuffer_parent_class = g_type_class_peek_parent (g_class);
       
   667 
       
   668   mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
       
   669       gst_v4lsrc_buffer_finalize;
       
   670 }
       
   671 
       
   672 static void
       
   673 gst_v4lsrc_buffer_init (GTypeInstance * instance, gpointer g_class)
       
   674 {
       
   675 
       
   676 }
       
   677 
       
   678 static void
       
   679 gst_v4lsrc_buffer_finalize (GstV4lSrcBuffer * v4lsrc_buffer)
       
   680 {
       
   681   GstV4lSrc *v4lsrc;
       
   682   gint num;
       
   683 
       
   684   v4lsrc = v4lsrc_buffer->v4lsrc;
       
   685   num = v4lsrc_buffer->num;
       
   686 
       
   687   GST_LOG_OBJECT (v4lsrc, "freeing buffer %p for frame %d", v4lsrc_buffer, num);
       
   688 
       
   689   /* only requeue if we still have an mmap buffer */
       
   690   if (GST_V4LELEMENT (v4lsrc)->buffer) {
       
   691     GST_LOG_OBJECT (v4lsrc, "requeueing frame %d", num);
       
   692     gst_v4lsrc_requeue_frame (v4lsrc, num);
       
   693   }
       
   694 
       
   695   gst_object_unref (v4lsrc);
       
   696 
       
   697   GST_MINI_OBJECT_CLASS (v4lbuffer_parent_class)->
       
   698       finalize (GST_MINI_OBJECT (v4lsrc_buffer));
       
   699 }
       
   700 
       
   701 /* Create a V4lSrc buffer from our mmap'd data area */
       
   702 GstBuffer *
       
   703 gst_v4lsrc_buffer_new (GstV4lSrc * v4lsrc, gint num)
       
   704 {
       
   705   GstBuffer *buf;
       
   706   gint fps_n, fps_d;
       
   707   GstClockTime duration, timestamp, latency;
       
   708 
       
   709   GST_DEBUG_OBJECT (v4lsrc, "creating buffer for frame %d", num);
       
   710 
       
   711   g_return_val_if_fail (gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d), NULL);
       
   712 
       
   713   buf = (GstBuffer *) gst_mini_object_new (GST_TYPE_V4LSRC_BUFFER);
       
   714 
       
   715   GST_V4LSRC_BUFFER (buf)->num = num;
       
   716   GST_V4LSRC_BUFFER (buf)->v4lsrc = gst_object_ref (v4lsrc);
       
   717 
       
   718   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY);
       
   719   GST_BUFFER_DATA (buf) = gst_v4lsrc_get_buffer (v4lsrc, num);
       
   720   GST_BUFFER_SIZE (buf) = v4lsrc->buffer_size;
       
   721   GST_BUFFER_OFFSET (buf) = v4lsrc->offset++;
       
   722 
       
   723   duration = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
       
   724   latency = duration;
       
   725 
       
   726   timestamp = gst_clock_get_time (GST_ELEMENT_CAST (v4lsrc)->clock);
       
   727   timestamp -= gst_element_get_base_time (GST_ELEMENT_CAST (v4lsrc));
       
   728   if (timestamp > latency)
       
   729     timestamp -= latency;
       
   730   else
       
   731     timestamp = 0;
       
   732 
       
   733   GST_BUFFER_TIMESTAMP (buf) = timestamp;
       
   734   GST_BUFFER_DURATION (buf) = duration;
       
   735 
       
   736   /* the negotiate() method already set caps on the source pad */
       
   737   gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (v4lsrc)));
       
   738 
       
   739   return buf;
       
   740 }