Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / sys / v4l / v4lmjpegsrc_calls.c
1 /* GStreamer
2  *
3  * v4lmjpegsrc_calls.c: functions for hardware MJPEG video source
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 <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <sys/ioctl.h>
31 #include <sys/mman.h>
32 #include <string.h>
33 #include <errno.h>
34 #include "v4lmjpegsrc_calls.h"
35
36 /* On some systems MAP_FAILED seems to be missing */
37 #ifndef MAP_FAILED
38 #define MAP_FAILED ( (caddr_t) -1 )
39 #endif
40
41 #define MIN_BUFFERS_QUEUED 2
42
43 GST_DEBUG_CATEGORY_EXTERN (v4lmjpegsrc_debug);
44 #define GST_CAT_DEFAULT v4lmjpegsrc_debug
45
46 enum
47 {
48   QUEUE_STATE_ERROR = -1,
49   QUEUE_STATE_READY_FOR_QUEUE,
50   QUEUE_STATE_QUEUED,
51   QUEUE_STATE_SYNCED,
52 };
53
54 /******************************************************
55  * gst_v4lmjpegsrc_queue_frame():
56  *   queue a frame for capturing
57  * return value: TRUE on success, FALSE on error
58  ******************************************************/
59
60 static gboolean
61 gst_v4lmjpegsrc_queue_frame (GstV4lMjpegSrc * v4lmjpegsrc, gint num)
62 {
63   GST_DEBUG_OBJECT (v4lmjpegsrc, "queueing frame %d", num);
64
65   if (v4lmjpegsrc->frame_queue_state[num] != QUEUE_STATE_READY_FOR_QUEUE) {
66     return FALSE;
67   }
68
69   if (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd, MJPIOC_QBUF_CAPT,
70           &num) < 0) {
71     GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, READ, (NULL),
72         ("Error queueing a buffer (%d): %s", num, g_strerror (errno)));
73     return FALSE;
74   }
75
76   v4lmjpegsrc->frame_queue_state[num] = QUEUE_STATE_QUEUED;
77   v4lmjpegsrc->num_queued++;
78
79   return TRUE;
80 }
81
82
83 /******************************************************
84  * gst_v4lmjpegsrc_sync_next_frame():
85  *   sync on the next frame for capturing
86  * return value: TRUE on success, FALSE on error
87  ******************************************************/
88
89 static gboolean
90 gst_v4lmjpegsrc_sync_next_frame (GstV4lMjpegSrc * v4lmjpegsrc, gint * num)
91 {
92   GST_DEBUG_OBJECT (v4lmjpegsrc, "syncing on next frame");
93
94   if (v4lmjpegsrc->num_queued <= 0) {
95     return FALSE;
96   }
97
98   while (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd,
99           MJPIOC_SYNC, &(v4lmjpegsrc->bsync)) < 0) {
100     if (errno != EINTR) {
101       GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, SYNC, (NULL), GST_ERROR_SYSTEM);
102       return FALSE;
103     }
104     GST_DEBUG_OBJECT (v4lmjpegsrc, "Sync got interrupted");
105   }
106
107   *num = v4lmjpegsrc->bsync.frame;
108
109   v4lmjpegsrc->frame_queue_state[*num] = QUEUE_STATE_SYNCED;
110   v4lmjpegsrc->num_queued--;
111
112   return TRUE;
113 }
114
115
116 /******************************************************
117  * gst_v4lmjpegsrc_set_buffer():
118  *   set buffer parameters (size/count)
119  * return value: TRUE on success, FALSE on error
120  ******************************************************/
121
122 gboolean
123 gst_v4lmjpegsrc_set_buffer (GstV4lMjpegSrc * v4lmjpegsrc,
124     gint numbufs, gint bufsize)
125 {
126   GST_DEBUG_OBJECT (v4lmjpegsrc,
127       "setting buffer info to numbufs = %d, bufsize = %d KB", numbufs, bufsize);
128   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc));
129   GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc));
130
131   v4lmjpegsrc->breq.size = bufsize * 1024;
132   v4lmjpegsrc->breq.count = numbufs;
133
134   return TRUE;
135 }
136
137
138 /******************************************************
139  * gst_v4lmjpegsrc_set_capture():
140  *   set capture parameters (simple)
141  * return value: TRUE on success, FALSE on error
142  ******************************************************/
143
144 gboolean
145 gst_v4lmjpegsrc_set_capture (GstV4lMjpegSrc * v4lmjpegsrc,
146     gint decimation, gint quality)
147 {
148   int norm, input, mw;
149   struct mjpeg_params bparm;
150
151   GST_DEBUG_OBJECT (v4lmjpegsrc, "setting decimation = %d, quality = %d",
152       decimation, quality);
153   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc));
154   GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc));
155
156   gst_v4l_get_chan_norm (GST_V4LELEMENT (v4lmjpegsrc), &input, &norm);
157
158   /* Query params for capture */
159   if (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd, MJPIOC_G_PARAMS,
160           &bparm) < 0) {
161     GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, SETTINGS, (NULL),
162         GST_ERROR_SYSTEM);
163     return FALSE;
164   }
165
166   bparm.decimation = decimation;
167   bparm.quality = quality;
168   bparm.norm = norm;
169   bparm.input = input;
170   bparm.APP_len = 0;            /* no JPEG markers - TODO: this is definately not right for decimation==1 */
171
172   mw = GST_V4LELEMENT (v4lmjpegsrc)->vcap.maxwidth;
173   if (mw != 768 && mw != 640) {
174     if (decimation == 1)
175       mw = 720;
176     else
177       mw = 704;
178   }
179   v4lmjpegsrc->end_width = mw / decimation;
180   v4lmjpegsrc->end_height = (norm == VIDEO_MODE_NTSC ? 480 : 576) / decimation;
181
182   /* TODO: interlacing */
183
184   /* Set params for capture */
185   if (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd, MJPIOC_S_PARAMS,
186           &bparm) < 0) {
187     GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, SETTINGS, (NULL),
188         GST_ERROR_SYSTEM);
189     return FALSE;
190   }
191
192   return TRUE;
193 }
194
195
196 /******************************************************
197  * gst_v4lmjpegsrc_set_capture_m():
198  *   set capture parameters (advanced)
199  * return value: TRUE on success, FALSE on error
200  ******************************************************/
201
202 gboolean
203 gst_v4lmjpegsrc_set_capture_m (GstV4lMjpegSrc * v4lmjpegsrc,
204     gint x_offset,
205     gint y_offset,
206     gint width, gint height, gint h_decimation, gint v_decimation, gint quality)
207 {
208   gint norm, input;
209   gint maxwidth;
210   struct mjpeg_params bparm;
211
212   GST_DEBUG_OBJECT (v4lmjpegsrc, "setting x_offset = %d, y_offset = %d, "
213       "width = %d, height = %d, h_decimation = %d, v_decimation = %d, quality = %d\n",
214       x_offset, y_offset, width, height, h_decimation, v_decimation, quality);
215   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc));
216   GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc));
217
218   gst_v4l_get_chan_norm (GST_V4LELEMENT (v4lmjpegsrc), &input, &norm);
219
220   if (GST_V4LELEMENT (v4lmjpegsrc)->vcap.maxwidth != 768 &&
221       GST_V4LELEMENT (v4lmjpegsrc)->vcap.maxwidth != 640)
222     maxwidth = 720;
223   else
224     maxwidth = GST_V4LELEMENT (v4lmjpegsrc)->vcap.maxwidth;
225
226   /* Query params for capture */
227   if (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd, MJPIOC_G_PARAMS,
228           &bparm) < 0) {
229     GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, SETTINGS, (NULL),
230         GST_ERROR_SYSTEM);
231     return FALSE;
232   }
233
234   bparm.decimation = 0;
235   bparm.quality = quality;
236   bparm.norm = norm;
237   bparm.input = input;
238   bparm.APP_len = 0;            /* no JPEG markers - TODO: this is definately
239                                  * not right for decimation==1 */
240
241   if (width <= 0) {
242     if (x_offset < 0)
243       x_offset = 0;
244     width = (maxwidth == 720
245         && h_decimation != 1) ? 704 : maxwidth - 2 * x_offset;
246   } else {
247     if (x_offset < 0)
248       x_offset = (maxwidth - width) / 2;
249   }
250
251   if (height <= 0) {
252     if (y_offset < 0)
253       y_offset = 0;
254     height = (norm == VIDEO_MODE_NTSC) ? 480 : 576 - 2 * y_offset;
255   } else {
256     if (y_offset < 0)
257       y_offset = ((norm == VIDEO_MODE_NTSC) ? 480 : 576 - height) / 2;
258   }
259
260   if (width + x_offset > maxwidth) {
261     GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, TOO_LAZY, (NULL),
262         ("Image width+offset (%d) bigger than maximum (%d)",
263             width + x_offset, maxwidth));
264     return FALSE;
265   }
266   if ((width % (bparm.HorDcm * 16)) != 0) {
267     GST_ELEMENT_ERROR (v4lmjpegsrc, STREAM, FORMAT, (NULL),
268         ("Image width (%d) not multiple of %d (required for JPEG)",
269             width, bparm.HorDcm * 16));
270     return FALSE;
271   }
272   if (height + y_offset > (norm == VIDEO_MODE_NTSC ? 480 : 576)) {
273     GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, TOO_LAZY, (NULL),
274         ("Image height+offset (%d) bigger than maximum (%d)",
275             height + y_offset, (norm == VIDEO_MODE_NTSC ? 480 : 576)));
276     return FALSE;
277   }
278   /* RJ: Image height must only be a multiple of 8, but geom_height
279    * is double the field height
280    */
281   if ((height % (bparm.VerDcm * 16)) != 0) {
282     GST_ELEMENT_ERROR (v4lmjpegsrc, STREAM, FORMAT, (NULL),
283         ("Image height (%d) not multiple of %d (required for JPEG)",
284             height, bparm.VerDcm * 16));
285     return FALSE;
286   }
287
288   bparm.img_x = x_offset;
289   bparm.img_width = width;
290   bparm.img_y = y_offset;
291   bparm.img_height = height;
292   bparm.HorDcm = h_decimation;
293   bparm.VerDcm = (v_decimation == 4) ? 2 : 1;
294   bparm.TmpDcm = (v_decimation == 1) ? 1 : 2;
295   bparm.field_per_buff = (v_decimation == 1) ? 2 : 1;
296
297   v4lmjpegsrc->end_width = width / h_decimation;
298   v4lmjpegsrc->end_width = height / v_decimation;
299
300   /* TODO: interlacing */
301
302   /* Set params for capture */
303   if (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd, MJPIOC_S_PARAMS,
304           &bparm) < 0) {
305     GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, SETTINGS, (NULL),
306         GST_ERROR_SYSTEM);
307     return FALSE;
308   }
309
310   return TRUE;
311 }
312
313
314 /******************************************************
315  * gst_v4lmjpegsrc_capture_init():
316  *   initialize the capture system
317  * return value: TRUE on success, FALSE on error
318  ******************************************************/
319
320 gboolean
321 gst_v4lmjpegsrc_capture_init (GstV4lMjpegSrc * v4lmjpegsrc)
322 {
323   GST_DEBUG_OBJECT (v4lmjpegsrc, "initting capture subsystem");
324   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc));
325   GST_V4L_CHECK_NOT_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc));
326
327   /* Request buffers */
328   if (ioctl (GST_V4LELEMENT (v4lmjpegsrc)->video_fd,
329           MJPIOC_REQBUFS, &(v4lmjpegsrc->breq)) < 0) {
330     GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
331     return FALSE;
332   }
333
334   if (v4lmjpegsrc->breq.count < MIN_BUFFERS_QUEUED) {
335     GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, READ, (NULL),
336         ("Too little buffers. We got %ld, we want at least %d",
337             v4lmjpegsrc->breq.count, MIN_BUFFERS_QUEUED));
338     return FALSE;
339   }
340
341   GST_INFO_OBJECT (v4lmjpegsrc, "Got %ld buffers of size %ld KB",
342       v4lmjpegsrc->breq.count, v4lmjpegsrc->breq.size / 1024);
343
344   /* keep track of queued buffers */
345   v4lmjpegsrc->frame_queue_state = (gint8 *)
346       g_malloc (sizeof (gint8) * v4lmjpegsrc->breq.count);
347
348   /* track how often to use each frame */
349   v4lmjpegsrc->use_num_times = (gint *)
350       g_malloc (sizeof (gint) * v4lmjpegsrc->breq.count);
351
352   /* lock for the frame_state */
353   v4lmjpegsrc->mutex_queue_state = g_mutex_new ();
354   v4lmjpegsrc->cond_queue_state = g_cond_new ();
355
356   /* Map the buffers */
357   GST_V4LELEMENT (v4lmjpegsrc)->buffer = mmap (0,
358       v4lmjpegsrc->breq.count * v4lmjpegsrc->breq.size,
359       PROT_READ | PROT_WRITE, MAP_SHARED,
360       GST_V4LELEMENT (v4lmjpegsrc)->video_fd, 0);
361   if (GST_V4LELEMENT (v4lmjpegsrc)->buffer == MAP_FAILED) {
362     GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, TOO_LAZY, (NULL),
363         ("Error mapping video buffers: %s", g_strerror (errno)));
364     GST_V4LELEMENT (v4lmjpegsrc)->buffer = NULL;
365     return FALSE;
366   }
367
368   return TRUE;
369 }
370
371
372 /******************************************************
373  * gst_v4lmjpegsrc_capture_start():
374  *   start streaming capture
375  * return value: TRUE on success, FALSE on error
376  ******************************************************/
377
378 gboolean
379 gst_v4lmjpegsrc_capture_start (GstV4lMjpegSrc * v4lmjpegsrc)
380 {
381   int n;
382
383   GST_DEBUG_OBJECT (v4lmjpegsrc, "starting capture");
384   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc));
385   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc));
386
387   g_mutex_lock (v4lmjpegsrc->mutex_queue_state);
388
389   v4lmjpegsrc->quit = FALSE;
390   v4lmjpegsrc->num_queued = 0;
391   v4lmjpegsrc->queue_frame = 0;
392
393   /* set all buffers ready to queue , this starts streaming capture */
394   for (n = 0; n < v4lmjpegsrc->breq.count; n++) {
395     v4lmjpegsrc->frame_queue_state[n] = QUEUE_STATE_READY_FOR_QUEUE;
396     if (!gst_v4lmjpegsrc_queue_frame (v4lmjpegsrc, n)) {
397       g_mutex_unlock (v4lmjpegsrc->mutex_queue_state);
398       gst_v4lmjpegsrc_capture_stop (v4lmjpegsrc);
399       return FALSE;
400     }
401   }
402
403   v4lmjpegsrc->is_capturing = TRUE;
404   g_mutex_unlock (v4lmjpegsrc->mutex_queue_state);
405
406   return TRUE;
407 }
408
409
410 /******************************************************
411  * gst_v4lmjpegsrc_grab_frame():
412  *   grab one frame during streaming capture
413  * return value: TRUE on success, FALSE on error
414  ******************************************************/
415
416 gboolean
417 gst_v4lmjpegsrc_grab_frame (GstV4lMjpegSrc * v4lmjpegsrc,
418     gint * num, gint * size)
419 {
420   GST_DEBUG_OBJECT (v4lmjpegsrc, "grabbing frame");
421   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc));
422   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc));
423
424   g_mutex_lock (v4lmjpegsrc->mutex_queue_state);
425
426   /* do we have enough frames? */
427   while (v4lmjpegsrc->num_queued < MIN_BUFFERS_QUEUED ||
428       v4lmjpegsrc->frame_queue_state[v4lmjpegsrc->queue_frame] ==
429       QUEUE_STATE_READY_FOR_QUEUE) {
430     while (v4lmjpegsrc->frame_queue_state[v4lmjpegsrc->queue_frame] !=
431         QUEUE_STATE_READY_FOR_QUEUE && !v4lmjpegsrc->quit) {
432       GST_DEBUG_OBJECT (v4lmjpegsrc,
433           "Waiting for frames to become available (%d < %d)",
434           v4lmjpegsrc->num_queued, MIN_BUFFERS_QUEUED);
435       g_cond_wait (v4lmjpegsrc->cond_queue_state,
436           v4lmjpegsrc->mutex_queue_state);
437     }
438     if (v4lmjpegsrc->quit) {
439       g_mutex_unlock (v4lmjpegsrc->mutex_queue_state);
440       return TRUE;              /* it won't get through anyway */
441     }
442     if (!gst_v4lmjpegsrc_queue_frame (v4lmjpegsrc, v4lmjpegsrc->queue_frame)) {
443       g_mutex_unlock (v4lmjpegsrc->mutex_queue_state);
444       return FALSE;
445     }
446     v4lmjpegsrc->queue_frame =
447         (v4lmjpegsrc->queue_frame + 1) % v4lmjpegsrc->breq.count;
448   }
449
450   /* syncing on the buffer grabs it */
451   if (!gst_v4lmjpegsrc_sync_next_frame (v4lmjpegsrc, num)) {
452     return FALSE;
453   }
454
455   *size = v4lmjpegsrc->bsync.length;
456
457   g_mutex_unlock (v4lmjpegsrc->mutex_queue_state);
458
459   return TRUE;
460 }
461
462
463 /******************************************************
464  * gst_v4lmjpegsrc_get_buffer():
465  *   get the memory address of a single buffer
466  * return value: TRUE on success, FALSE on error
467  ******************************************************/
468
469 guint8 *
470 gst_v4lmjpegsrc_get_buffer (GstV4lMjpegSrc * v4lmjpegsrc, gint num)
471 {
472   /*DEBUG("gst_v4lmjpegsrc_get_buffer(), num = %d", num); */
473
474   if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc)) ||
475       !GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lmjpegsrc)))
476     return NULL;
477
478   if (num < 0 || num >= v4lmjpegsrc->breq.count)
479     return NULL;
480
481   return GST_V4LELEMENT (v4lmjpegsrc)->buffer + (v4lmjpegsrc->breq.size * num);
482 }
483
484
485 /******************************************************
486  * gst_v4lmjpegsrc_requeue_frame():
487  *   requeue a frame for capturing
488  * return value: TRUE on success, FALSE on error
489  ******************************************************/
490
491 gboolean
492 gst_v4lmjpegsrc_requeue_frame (GstV4lMjpegSrc * v4lmjpegsrc, gint num)
493 {
494   GST_DEBUG_OBJECT (v4lmjpegsrc, "requeueing frame %d", num);
495   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc));
496   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc));
497
498   /* mark frame as 'ready to requeue' */
499   g_mutex_lock (v4lmjpegsrc->mutex_queue_state);
500
501   if (v4lmjpegsrc->frame_queue_state[num] != QUEUE_STATE_SYNCED) {
502     GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, TOO_LAZY, (NULL),
503         ("Invalid state %d (expected %d), can't requeue",
504             v4lmjpegsrc->frame_queue_state[num], QUEUE_STATE_SYNCED));
505     return FALSE;
506   }
507
508   v4lmjpegsrc->frame_queue_state[num] = QUEUE_STATE_READY_FOR_QUEUE;
509
510   /* let an optional wait know */
511   g_cond_broadcast (v4lmjpegsrc->cond_queue_state);
512
513   g_mutex_unlock (v4lmjpegsrc->mutex_queue_state);
514
515   return TRUE;
516 }
517
518
519 /******************************************************
520  * gst_v4lmjpegsrc_capture_stop():
521  *   stop streaming capture
522  * return value: TRUE on success, FALSE on error
523  ******************************************************/
524
525 gboolean
526 gst_v4lmjpegsrc_capture_stop (GstV4lMjpegSrc * v4lmjpegsrc)
527 {
528   int n;
529
530   GST_DEBUG_OBJECT (v4lmjpegsrc, "stopping capture");
531   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc));
532   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc));
533
534   g_mutex_lock (v4lmjpegsrc->mutex_queue_state);
535
536   /* make an optional pending wait stop */
537   v4lmjpegsrc->quit = TRUE;
538   g_cond_broadcast (v4lmjpegsrc->cond_queue_state);
539
540   /* sync on remaining frames */
541   while (v4lmjpegsrc->num_queued > 0) {
542     gst_v4lmjpegsrc_sync_next_frame (v4lmjpegsrc, &n);
543   }
544
545   v4lmjpegsrc->is_capturing = FALSE;
546   g_mutex_unlock (v4lmjpegsrc->mutex_queue_state);
547
548   return TRUE;
549 }
550
551
552 /******************************************************
553  * gst_v4lmjpegsrc_capture_deinit():
554  *   deinitialize the capture system
555  * return value: TRUE on success, FALSE on error
556  ******************************************************/
557
558 gboolean
559 gst_v4lmjpegsrc_capture_deinit (GstV4lMjpegSrc * v4lmjpegsrc)
560 {
561   GST_DEBUG_OBJECT (v4lmjpegsrc, "quitting capture subsystem");
562   GST_V4L_CHECK_OPEN (GST_V4LELEMENT (v4lmjpegsrc));
563   GST_V4L_CHECK_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc));
564
565   /* unmap the buffer */
566   munmap (GST_V4LELEMENT (v4lmjpegsrc)->buffer,
567       v4lmjpegsrc->breq.size * v4lmjpegsrc->breq.count);
568   GST_V4LELEMENT (v4lmjpegsrc)->buffer = NULL;
569
570   /* free buffer tracker */
571   g_mutex_free (v4lmjpegsrc->mutex_queue_state);
572   g_cond_free (v4lmjpegsrc->cond_queue_state);
573   g_free (v4lmjpegsrc->frame_queue_state);
574   g_free (v4lmjpegsrc->use_num_times);
575
576   return TRUE;
577 }