Correct all relevant warnings found by the sparse semantic code analyzer. This includ...
[platform/upstream/gstreamer.git] / sys / v4l / gstv4ljpegsrc.c
1 /* GStreamer
2  *
3  * gstv4ljpegsrc.c: V4L source element for JPEG cameras
4  *
5  * Copyright (C) 2004-2005 Jan Schmidt <thaytan@mad.scientist.com>
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  e 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 "gstv4ljpegsrc.h"
30 #include "v4lsrc_calls.h"
31
32 /* elementfactory information */
33 static const GstElementDetails gst_v4ljpegsrc_details =
34 GST_ELEMENT_DETAILS ("Video (video4linux/raw) Jpeg Source",
35     "Source/Video",
36     "Reads jpeg frames from a video4linux (eg ov519) device",
37     "Jan Schmidt <thaytan@mad.scientist.com>");
38
39 GST_DEBUG_CATEGORY_STATIC (v4ljpegsrc_debug);
40 #define GST_CAT_DEFAULT v4ljpegsrc_debug
41
42 /* init functions */
43 static void gst_v4ljpegsrc_base_init (gpointer g_class);
44 static void gst_v4ljpegsrc_class_init (GstV4lJpegSrcClass * klass);
45 static void gst_v4ljpegsrc_init (GstV4lJpegSrc * v4ljpegsrc);
46
47 /* buffer functions */
48 static GstPadLinkReturn gst_v4ljpegsrc_src_link (GstPad * pad,
49     const GstCaps * caps);
50 static GstCaps *gst_v4ljpegsrc_getcaps (GstPad * pad);
51 static GstData *gst_v4ljpegsrc_get (GstPad * pad);
52
53 static GstElementClass *parent_class = NULL;
54
55 GType
56 gst_v4ljpegsrc_get_type (void)
57 {
58   static GType v4ljpegsrc_type = 0;
59
60   if (!v4ljpegsrc_type) {
61     static const GTypeInfo v4ljpegsrc_info = {
62       sizeof (GstV4lJpegSrcClass),
63       gst_v4ljpegsrc_base_init,
64       NULL,
65       (GClassInitFunc) gst_v4ljpegsrc_class_init,
66       NULL,
67       NULL,
68       sizeof (GstV4lJpegSrc),
69       0,
70       (GInstanceInitFunc) gst_v4ljpegsrc_init,
71       NULL
72     };
73
74     v4ljpegsrc_type =
75         g_type_register_static (GST_TYPE_V4LSRC, "GstV4lJpegSrc",
76         &v4ljpegsrc_info, 0);
77     GST_DEBUG_CATEGORY_INIT (v4ljpegsrc_debug, "v4ljpegsrc", 0,
78         "V4L JPEG source element");
79   }
80   return v4ljpegsrc_type;
81 }
82
83 static void
84 gst_v4ljpegsrc_base_init (gpointer g_class)
85 {
86   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
87
88   gst_element_class_set_details (gstelement_class, &gst_v4ljpegsrc_details);
89 }
90
91 static void
92 gst_v4ljpegsrc_class_init (GstV4lJpegSrcClass * klass)
93 {
94   parent_class = g_type_class_peek_parent (klass);
95 }
96
97 static void
98 gst_v4ljpegsrc_init (GstV4lJpegSrc * v4ljpegsrc)
99 {
100   GstV4lSrc *v4lsrc = GST_V4LSRC (v4ljpegsrc);
101   GstPad *pad = v4lsrc->srcpad;
102
103   /*
104    * Stash away and then replace the getcaps and get functions on the src pad
105    */
106   v4ljpegsrc->getfn = GST_RPAD_GETFUNC (pad);
107   v4ljpegsrc->getcapsfn = GST_RPAD_GETCAPSFUNC (pad);
108
109   gst_pad_set_get_function (v4lsrc->srcpad, gst_v4ljpegsrc_get);
110   gst_pad_set_getcaps_function (v4lsrc->srcpad, gst_v4ljpegsrc_getcaps);
111   gst_pad_set_link_function (v4lsrc->srcpad, gst_v4ljpegsrc_src_link);
112 }
113
114 static GstPadLinkReturn
115 gst_v4ljpegsrc_src_link (GstPad * pad, const GstCaps * vscapslist)
116 {
117   GstV4lJpegSrc *v4ljpegsrc;
118   GstV4lSrc *v4lsrc;
119   gint w, h, palette = -1;
120   const GValue *fps;
121   GstStructure *structure;
122   gboolean was_capturing;
123   struct video_window *vwin;
124
125   v4ljpegsrc = GST_V4LJPEGSRC (gst_pad_get_parent (pad));
126   v4lsrc = GST_V4LSRC (v4ljpegsrc);
127   vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
128   was_capturing = v4lsrc->is_capturing;
129
130   /* in case the buffers are active (which means that we already
131    * did capsnego before and didn't clean up), clean up anyways */
132   if (GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc))) {
133     if (was_capturing) {
134       if (!gst_v4lsrc_capture_stop (v4lsrc))
135         return GST_PAD_LINK_REFUSED;
136     }
137     if (!gst_v4lsrc_capture_deinit (v4lsrc))
138       return GST_PAD_LINK_REFUSED;
139   } else if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
140     return GST_PAD_LINK_DELAYED;
141   }
142
143   structure = gst_caps_get_structure (vscapslist, 0);
144
145   gst_structure_get_int (structure, "width", &w);
146   gst_structure_get_int (structure, "height", &h);
147   fps = gst_structure_get_value (structure, "framerate");
148
149   GST_DEBUG_OBJECT (v4ljpegsrc, "linking with %dx%d at %d/%d fps", w, h,
150       gst_value_get_fraction_numerator (fps),
151       gst_value_get_fraction_denominator (fps));
152
153   /* set framerate if it's not already correct */
154   if (fps != gst_v4lsrc_get_fps (v4lsrc)) {
155     int fps_index = fps / 15.0 * 16;
156
157     GST_DEBUG_OBJECT (v4ljpegsrc, "Trying to set fps index %d", fps_index);
158     /* set bits 16 to 21 to 0 */
159     vwin->flags &= (0x3F00 - 1);
160     /* set bits 16 to 21 to the index */
161     vwin->flags |= fps_index << 16;
162     if (!gst_v4l_set_window_properties (GST_V4LELEMENT (v4lsrc))) {
163       return GST_PAD_LINK_DELAYED;
164     }
165   }
166
167   /*
168    * Try to set the camera to capture RGB24 
169    */
170   palette = VIDEO_PALETTE_RGB24;
171   v4lsrc->buffer_size = w * h * 3;
172
173   GST_DEBUG_OBJECT (v4ljpegsrc, "trying to set_capture %dx%d, palette %d",
174       w, h, palette);
175   /* this only fills in v4lsrc->mmap values */
176   if (!gst_v4lsrc_set_capture (v4lsrc, w, h, palette)) {
177     GST_WARNING_OBJECT (v4ljpegsrc, "could not set_capture %dx%d, palette %d",
178         w, h, palette);
179     return GST_PAD_LINK_REFUSED;
180   }
181
182   /* first try the negotiated settings using try_capture */
183   if (!gst_v4lsrc_try_capture (v4lsrc, w, h, palette)) {
184     GST_DEBUG_OBJECT (v4ljpegsrc, "failed trying palette %d for %dx%d", palette,
185         w, h);
186     return GST_PAD_LINK_REFUSED;
187   }
188
189   if (!gst_v4lsrc_capture_init (v4lsrc))
190     return GST_PAD_LINK_REFUSED;
191
192   if (was_capturing || GST_STATE (v4lsrc) == GST_STATE_PLAYING) {
193     if (!gst_v4lsrc_capture_start (v4lsrc))
194       return GST_PAD_LINK_REFUSED;
195   }
196
197   return GST_PAD_LINK_OK;
198 }
199
200 static GstCaps *
201 gst_v4ljpegsrc_getcaps (GstPad * pad)
202 {
203   GstCaps *list;
204   GstV4lJpegSrc *v4ljpegsrc = GST_V4LJPEGSRC (gst_pad_get_parent (pad));
205   GstV4lSrc *v4lsrc = GST_V4LSRC (v4ljpegsrc);
206   struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap;
207   gfloat fps = 0.0;
208
209   if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
210     return gst_caps_new_any ();
211   }
212   if (!v4lsrc->autoprobe) {
213     /* FIXME: query current caps and return those, with _any appended */
214     return gst_caps_new_any ();
215   }
216
217   list = gst_caps_new_simple ("image/jpeg", NULL);
218   GST_DEBUG_OBJECT (v4ljpegsrc,
219       "Device reports w: %d-%d, h: %d-%d, fps: %f",
220       vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight, fps);
221
222   if (vcap->minwidth < vcap->maxwidth) {
223     gst_caps_set_simple (list, "width", GST_TYPE_INT_RANGE, vcap->minwidth,
224         vcap->maxwidth, NULL);
225   } else {
226     gst_caps_set_simple (list, "width", G_TYPE_INT, vcap->minwidth, NULL);
227   }
228   if (vcap->minheight < vcap->maxheight) {
229     gst_caps_set_simple (list, "height", GST_TYPE_INT_RANGE, vcap->minheight,
230         vcap->maxheight, NULL);
231   } else {
232     gst_caps_set_simple (list, "height", G_TYPE_INT, vcap->minheight, NULL);
233   }
234
235   if (v4lsrc->fps_list) {
236     GstStructure *structure = gst_caps_get_structure (list, 0);
237
238     gst_structure_set_value (structure, "framerate", v4lsrc->fps_list);
239   }
240   GST_DEBUG_OBJECT (v4ljpegsrc, "caps: %" GST_PTR_FORMAT, list);
241
242   return list;
243 }
244
245 static GstData *
246 gst_v4ljpegsrc_get (GstPad * pad)
247 {
248   GstV4lJpegSrc *v4ljpegsrc;
249   GstV4lSrc *v4lsrc;
250   GstData *data;
251   GstBuffer *buf;
252   GstBuffer *outbuf;
253   int jpeg_size;
254
255   g_return_val_if_fail (pad != NULL, NULL);
256   v4ljpegsrc = GST_V4LJPEGSRC (gst_pad_get_parent (pad));
257   v4lsrc = GST_V4LSRC (v4ljpegsrc);
258
259   /* Fetch from the v4lsrc class get fn.  */
260   data = v4ljpegsrc->getfn (pad);
261
262   /* If not a buffer, return it unchanged */
263   if (!data || (!GST_IS_BUFFER (data)))
264     return data;
265
266   buf = GST_BUFFER (data);
267
268   /* Confirm that the buffer contains jpeg data */
269
270   /* 
271    * Create a new subbuffer from the jpeg data 
272    * The first 2 bytes in the buffer are the size of the jpeg data
273    */
274   if (GST_BUFFER_SIZE (buf) > 2) {
275     jpeg_size = (int) (GST_READ_UINT16_LE (GST_BUFFER_DATA (buf))) * 8;
276   } else
277     jpeg_size = 0;
278
279   /* Check that the size is sensible */
280   if ((jpeg_size <= 0) || (jpeg_size > GST_BUFFER_SIZE (buf) - 2)) {
281     GST_ELEMENT_ERROR (v4ljpegsrc, STREAM, FORMAT, (NULL),
282         ("Invalid non-jpeg frame from camera"));
283     return NULL;
284   }
285
286   GST_DEBUG_OBJECT (v4ljpegsrc, "Creating JPEG subbuffer of size %d",
287       jpeg_size);
288   outbuf = gst_buffer_create_sub (buf, 2, jpeg_size);
289
290   /* Copy timestamps onto the subbuffer */
291   gst_buffer_stamp (outbuf, buf);
292
293   /* Release the main buffer */
294   gst_buffer_unref (buf);
295
296   return GST_DATA (outbuf);
297 }