f2a993c0bf4a132e2980e0a7d9b5f5b356145869
[platform/upstream/gstreamer.git] / sys / rpicamsrc / gstrpicamsrc.c
1 /*
2  * GStreamer
3  * Copyright (C) 2013-2015 Jan Schmidt <jan@centricular.com>
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Alternatively, the contents of this file may be used under the
24  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
25  * which case the following provisions apply instead of the ones
26  * mentioned above:
27  *
28  * This library is free software; you can redistribute it and/or
29  * modify it under the terms of the GNU Library General Public
30  * License as published by the Free Software Foundation; either
31  * version 2 of the License, or (at your option) any later version.
32  *
33  * This library is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
36  * Library General Public License for more details.
37  *
38  * You should have received a copy of the GNU Library General Public
39  * License along with this library; if not, write to the
40  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
41  * Boston, MA 02111-1307, USA.
42  */
43
44 /**
45  * SECTION:element-rpicamsrc
46  *
47  * Source element for capturing from the Raspberry Pi camera module
48  *
49  * <refsect2>
50  * <title>Example launch line</title>
51  * |[
52  * gst-launch -v -m rpicamsrc ! fakesink
53  * ]|
54  * </refsect2>
55  */
56
57 #ifdef HAVE_CONFIG_H
58 #  include <config.h>
59 #endif
60 #include <gst/video/video.h>
61
62 #include "gstrpicamsrc.h"
63 #include "gstrpicam_types.h"
64 #include "gstrpicam-enum-types.h"
65 #include "gstrpicamsrcdeviceprovider.h"
66 #include "RaspiCapture.h"
67
68 #include "bcm_host.h"
69 #include "interface/vcos/vcos.h"
70
71 #include "interface/mmal/mmal.h"
72 #include "interface/mmal/mmal_logging.h"
73 #include "interface/mmal/mmal_buffer.h"
74 #include "interface/mmal/util/mmal_util.h"
75 #include "interface/mmal/util/mmal_util_params.h"
76 #include "interface/mmal/util/mmal_default_components.h"
77 #include "interface/mmal/util/mmal_connection.h"
78
79 GST_DEBUG_CATEGORY (gst_rpi_cam_src_debug);
80
81 /* comment out to use JPEG codec instead of MJPEG */
82 // #define USE_JPEG_CODEC
83
84 /* Filter signals and args */
85 enum
86 {
87   /* FILL ME */
88   LAST_SIGNAL
89 };
90
91 enum
92 {
93   PROP_0,
94   PROP_CAMERA_NUMBER,
95   PROP_BITRATE,
96   PROP_KEYFRAME_INTERVAL,
97   PROP_PREVIEW,
98   PROP_PREVIEW_ENCODED,
99   PROP_PREVIEW_OPACITY,
100   PROP_PREVIEW_X,
101   PROP_PREVIEW_Y,
102   PROP_PREVIEW_W,
103   PROP_PREVIEW_H,
104   PROP_FULLSCREEN,
105   PROP_SHARPNESS,
106   PROP_CONTRAST,
107   PROP_BRIGHTNESS,
108   PROP_SATURATION,
109   PROP_ISO,
110   PROP_VIDEO_STABILISATION,
111   PROP_EXPOSURE_COMPENSATION,
112   PROP_EXPOSURE_MODE,
113   PROP_EXPOSURE_METERING_MODE,
114   PROP_AWB_MODE,
115   PROP_AWB_GAIN_RED,
116   PROP_AWB_GAIN_BLUE,
117   PROP_IMAGE_EFFECT,
118   PROP_IMAGE_EFFECT_PARAMS,
119   PROP_COLOUR_EFFECTS,
120   PROP_ROTATION,
121   PROP_HFLIP,
122   PROP_VFLIP,
123   PROP_ROI_X,
124   PROP_ROI_Y,
125   PROP_ROI_W,
126   PROP_ROI_H,
127   PROP_QUANTISATION_PARAMETER,
128   PROP_INLINE_HEADERS,
129   PROP_SHUTTER_SPEED,
130   PROP_SENSOR_MODE,
131   PROP_DRC,
132   PROP_ANNOTATION_MODE,
133   PROP_ANNOTATION_TEXT,
134   PROP_ANNOTATION_TEXT_SIZE,
135   PROP_ANNOTATION_TEXT_COLOUR,
136   PROP_ANNOTATION_TEXT_BG_COLOUR,
137   PROP_INTRA_REFRESH_TYPE,
138 #ifdef GST_RPI_CAM_SRC_ENABLE_VIDEO_DIRECTION
139   PROP_VIDEO_DIRECTION,
140 #endif
141   PROP_JPEG_QUALITY
142 };
143
144 #define CAMERA_DEFAULT 0
145
146 #define BITRATE_DEFAULT 17000000        /* 17Mbit/s default for 1080p */
147 #define BITRATE_HIGHEST 25000000
148
149 #define QUANTISATION_DEFAULT 0
150
151 #define SHARPNESS_DEFAULT 0
152 #define CONTRAST_DEFAULT 0
153 #define BRIGHTNESS_DEFAULT 50
154 #define SATURATION_DEFAULT 0
155 #define ISO_DEFAULT 0
156 #define VIDEO_STABILISATION_DEFAULT FALSE
157 #define EXPOSURE_COMPENSATION_DEFAULT 0
158 #define KEYFRAME_INTERVAL_DEFAULT -1
159
160 #define EXPOSURE_MODE_DEFAULT GST_RPI_CAM_SRC_EXPOSURE_MODE_AUTO
161 #define EXPOSURE_METERING_MODE_DEFAULT GST_RPI_CAM_SRC_EXPOSURE_METERING_MODE_AVERAGE
162
163 #define DEFAULT_JPEG_QUALITY 50
164
165 /*
166    params->exposureMode = MMAL_PARAM_EXPOSUREMODE_AUTO;
167    params->exposureMeterMode = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE;
168    params->awbMode = MMAL_PARAM_AWBMODE_AUTO;
169    params->imageEffect = MMAL_PARAM_IMAGEFX_NONE;
170    params->colourEffects.enable = 0;
171    params->colourEffects.u = 128;
172    params->colourEffects.v = 128;
173    params->rotation = 0;
174    params->hflip = params->vflip = 0;
175    params->roi.x = params->roi.y = 0.0;
176    params->roi.w = params->roi.h = 1.0;
177 */
178
179 #define JPEG_CAPS \
180   "image/jpeg,"                                   \
181   "width = " GST_VIDEO_SIZE_RANGE ","             \
182   "height = " GST_VIDEO_SIZE_RANGE ","            \
183   "framerate = " GST_VIDEO_FPS_RANGE
184 #define H264_CAPS               \
185   "video/x-h264, "                              \
186   "width = " GST_VIDEO_SIZE_RANGE ", "          \
187   "height = " GST_VIDEO_SIZE_RANGE ", "         \
188   "framerate = " GST_VIDEO_FPS_RANGE ", "       \
189   "stream-format = (string) byte-stream, "  \
190   "alignment = (string) nal, "               \
191   "profile = (string) { baseline, main, high }"
192 #define RAW_CAPS \
193   GST_VIDEO_CAPS_MAKE ("{ I420, RGB, BGR, RGBA }") /* FIXME: Map more raw formats */
194
195 #ifdef GST_RPI_CAM_SRC_ENABLE_VIDEO_DIRECTION
196 #define gst_rpi_cam_src_reset_custom_orientation(src) { src->orientation = GST_VIDEO_ORIENTATION_CUSTOM; }
197 #else
198 #define gst_rpi_cam_src_reset_custom_orientation(src) { }
199 #endif
200
201 static GstStaticPadTemplate video_src_template = GST_STATIC_PAD_TEMPLATE ("src",
202     GST_PAD_SRC,
203     GST_PAD_ALWAYS,
204     GST_STATIC_CAPS ( H264_CAPS "; " JPEG_CAPS "; " RAW_CAPS)
205     );
206
207
208 static void gst_rpi_cam_src_finalize (GObject *object);
209
210 static void gst_rpi_cam_src_colorbalance_init (GstColorBalanceInterface *
211     iface);
212 static void gst_rpi_cam_src_orientation_init (GstVideoOrientationInterface * iface);
213 #ifdef GST_RPI_CAM_SRC_ENABLE_VIDEO_DIRECTION
214 static void gst_rpi_cam_src_direction_init (GstVideoDirectionInterface * iface);
215 #endif
216
217 static void gst_rpi_cam_src_set_property (GObject * object, guint prop_id,
218     const GValue * value, GParamSpec * pspec);
219 static void gst_rpi_cam_src_get_property (GObject * object, guint prop_id,
220     GValue * value, GParamSpec * pspec);
221 static gboolean gst_rpi_cam_src_start (GstBaseSrc * parent);
222 static gboolean gst_rpi_cam_src_stop (GstBaseSrc * parent);
223 static gboolean gst_rpi_cam_src_decide_allocation (GstBaseSrc * src,
224     GstQuery * query);
225 static GstFlowReturn gst_rpi_cam_src_create (GstPushSrc * parent,
226     GstBuffer ** buf);
227 static GstCaps *gst_rpi_cam_src_get_caps (GstBaseSrc * src, GstCaps * filter);
228 static gboolean gst_rpi_cam_src_set_caps (GstBaseSrc * src, GstCaps * caps);
229 static GstCaps *gst_rpi_cam_src_fixate (GstBaseSrc * basesrc, GstCaps * caps);
230 static gboolean gst_rpi_cam_src_event (GstBaseSrc * src, GstEvent * event);
231 static gboolean gst_rpi_cam_src_send_event (GstElement * element,
232     GstEvent * event);
233
234 #define gst_rpi_cam_src_parent_class parent_class
235 G_DEFINE_TYPE_WITH_CODE (GstRpiCamSrc, gst_rpi_cam_src,
236     GST_TYPE_PUSH_SRC,
237     G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
238         gst_rpi_cam_src_colorbalance_init);
239 #ifdef GST_RPI_CAM_SRC_ENABLE_VIDEO_DIRECTION
240     G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_DIRECTION,
241         gst_rpi_cam_src_direction_init);
242 #endif
243     G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_ORIENTATION,
244         gst_rpi_cam_src_orientation_init));
245
246 #define C_ENUM(v) ((gint) v)
247
248 GType
249 gst_rpi_cam_src_sensor_mode_get_type (void)
250 {
251   static const GEnumValue values[] = {
252     {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_AUTOMATIC), "Automatic", "automatic"},
253     {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_1920x1080), "1920x1080 16:9 1-30fps",
254         "1920x1080"},
255     {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_2592x1944_FAST),
256           "2592x1944 4:3 1-15fps / 3240x2464 15fps w/ v.2 board",
257         "2592x1944-fast"},
258     {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_2592x1944_SLOW),
259         "2592x1944 4:3 0.1666-1fps / 3240x2464 15fps w/ v.2 board", "2592x1944-slow"},
260     {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_1296x972), "1296x972 4:3 1-42fps",
261         "1296x972"},
262     {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_1296x730), "1296x730 16:9 1-49fps",
263         "1296x730"},
264     {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_640x480_SLOW),
265         "640x480 4:3 42.1-60fps", "640x480-slow"},
266     {C_ENUM (GST_RPI_CAM_SRC_SENSOR_MODE_640x480_FAST),
267         "640x480 4:3 60.1-90fps", "640x480-fast"},
268     {0, NULL, NULL}
269   };
270   static volatile GType id = 0;
271   if (g_once_init_enter ((gsize *) & id)) {
272     GType _id;
273     _id = g_enum_register_static ("GstRpiCamSrcSensorMode", values);
274     g_once_init_leave ((gsize *) & id, _id);
275   }
276
277   return id;
278 }
279
280
281 static void
282 gst_rpi_cam_src_class_init (GstRpiCamSrcClass * klass)
283 {
284   GObjectClass *gobject_class;
285   GstElementClass *gstelement_class;
286   GstBaseSrcClass *basesrc_class;
287   GstPushSrcClass *pushsrc_class;
288   gobject_class = (GObjectClass *) klass;
289   gstelement_class = (GstElementClass *) klass;
290   basesrc_class = (GstBaseSrcClass *) klass;
291   pushsrc_class = (GstPushSrcClass *) klass;
292
293   gobject_class->finalize = gst_rpi_cam_src_finalize;
294   gobject_class->set_property = gst_rpi_cam_src_set_property;
295   gobject_class->get_property = gst_rpi_cam_src_get_property;
296   g_object_class_install_property (gobject_class, PROP_CAMERA_NUMBER,
297       g_param_spec_int ("camera-number", "Camera Number",
298           "Which camera to use on a multi-camera system - 0 or 1", 0,
299           1, CAMERA_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
300   g_object_class_install_property (gobject_class, PROP_BITRATE,
301       g_param_spec_int ("bitrate", "Bitrate",
302           "Bitrate for encoding. 0 for VBR using quantisation-parameter", 0,
303           BITRATE_HIGHEST, BITRATE_DEFAULT,
304           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
305 #ifdef USE_JPEG_CODEC
306   g_object_class_install_property (gobject_class, PROP_JPEG_QUALITY,
307       g_param_spec_int ("jpeg-quality", "JPEG Quality",
308           "Quality setting for JPEG encode", 1, 100, DEFAULT_JPEG_QUALITY,
309           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
310 #endif
311   g_object_class_install_property (gobject_class, PROP_KEYFRAME_INTERVAL,
312       g_param_spec_int ("keyframe-interval", "Keyframe Interface",
313           "Interval (in frames) between I frames. -1 = automatic, 0 = single-keyframe",
314           -1, G_MAXINT, KEYFRAME_INTERVAL_DEFAULT,
315           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
316   g_object_class_install_property (gobject_class, PROP_PREVIEW,
317       g_param_spec_boolean ("preview", "Preview Window",
318           "Display preview window overlay", TRUE,
319           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
320   g_object_class_install_property (gobject_class, PROP_FULLSCREEN,
321       g_param_spec_boolean ("fullscreen", "Fullscreen Preview",
322           "Display preview window full screen", TRUE,
323           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
324   g_object_class_install_property (gobject_class, PROP_PREVIEW_ENCODED,
325       g_param_spec_boolean ("preview-encoded", "Preview Encoded",
326           "Display encoder output in the preview", TRUE,
327           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
328   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PREVIEW_OPACITY,
329       g_param_spec_int ("preview-opacity", "Preview Opacity",
330           "Opacity to use for the preview window", 0, 255, 255,
331           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
332   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PREVIEW_X,
333       g_param_spec_int ("preview-x", "Preview window X position",
334           "Start X coordinate of the preview window (in pixels)", 0, 2048, 0,
335           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
336   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PREVIEW_Y,
337       g_param_spec_int ("preview-y", "Preview window Y position",
338           "Start Y coordinate of the preview window (in pixels)", 0, 2048, 0,
339           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
340   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PREVIEW_W,
341       g_param_spec_int ("preview-w", "Preview window width",
342           "Width of the preview window (in pixels)", 0, 2048, 1024,
343           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
344   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PREVIEW_H,
345       g_param_spec_int ("preview-h", "Preview window height",
346           "Height of the preview window (in pixels)", 0, 2048, 768,
347           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
348   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SHARPNESS,
349       g_param_spec_int ("sharpness", "Sharpness", "Image capture sharpness",
350           -100, 100, SHARPNESS_DEFAULT,
351           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
352   g_object_class_install_property (gobject_class, PROP_CONTRAST,
353       g_param_spec_int ("contrast", "Contrast", "Image capture contrast", -100,
354           100, CONTRAST_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
355   g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
356       g_param_spec_int ("brightness", "Brightness", "Image capture brightness",
357           0, 100, BRIGHTNESS_DEFAULT,
358           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
359   g_object_class_install_property (gobject_class, PROP_SATURATION,
360       g_param_spec_int ("saturation", "Saturation", "Image capture saturation",
361           -100, 100, SATURATION_DEFAULT,
362           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
363   g_object_class_install_property (gobject_class, PROP_ISO,
364       g_param_spec_int ("iso", "ISO", "ISO value to use (0 = Auto)", 0, 3200, 0,
365           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
366   g_object_class_install_property (gobject_class, PROP_VIDEO_STABILISATION,
367       g_param_spec_boolean ("video-stabilisation", "Video Stabilisation",
368           "Enable or disable video stabilisation", FALSE,
369           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
370   g_object_class_install_property (gobject_class, PROP_EXPOSURE_COMPENSATION,
371       g_param_spec_int ("exposure-compensation", "EV compensation",
372           "Exposure Value compensation", -10, 10, 0,
373           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
374   g_object_class_install_property (gobject_class, PROP_EXPOSURE_MODE,
375       g_param_spec_enum ("exposure-mode", "Exposure Mode",
376           "Camera exposure mode to use",
377           GST_RPI_CAM_TYPE_RPI_CAM_SRC_EXPOSURE_MODE, EXPOSURE_MODE_DEFAULT,
378           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
379   g_object_class_install_property (gobject_class, PROP_EXPOSURE_METERING_MODE,
380       g_param_spec_enum ("metering-mode", "Exposure Metering Mode",
381           "Camera exposure metering mode to use",
382           GST_RPI_CAM_TYPE_RPI_CAM_SRC_EXPOSURE_METERING_MODE,
383           EXPOSURE_METERING_MODE_DEFAULT,
384           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
385   g_object_class_install_property (gobject_class, PROP_DRC,
386       g_param_spec_enum ("drc", "DRC level", "Dynamic Range Control level",
387           GST_RPI_CAM_TYPE_RPI_CAM_SRC_DRC_LEVEL, GST_RPI_CAM_SRC_DRC_LEVEL_OFF,
388           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
389   g_object_class_install_property (gobject_class, PROP_AWB_MODE,
390       g_param_spec_enum ("awb-mode", "Automatic White Balance Mode",
391           "White Balance mode", GST_RPI_CAM_TYPE_RPI_CAM_SRC_AWB_MODE,
392           GST_RPI_CAM_SRC_AWB_MODE_AUTO,
393           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
394   g_object_class_install_property (gobject_class, PROP_AWB_GAIN_RED,
395       g_param_spec_float ("awb-gain-red", "AWB Red Gain",
396           "Manual AWB Gain for red channel when awb-mode=off", 0, 8.0, 0,
397           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
398   g_object_class_install_property (gobject_class, PROP_AWB_GAIN_BLUE,
399       g_param_spec_float ("awb-gain-blue", "AWB Blue Gain",
400           "Manual AWB Gain for blue channel when awb-mode=off", 0, 8.0, 0,
401           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
402   g_object_class_install_property (gobject_class, PROP_IMAGE_EFFECT,
403       g_param_spec_enum ("image-effect", "Image effect",
404           "Visual FX to apply to the image",
405           GST_RPI_CAM_TYPE_RPI_CAM_SRC_IMAGE_EFFECT,
406           GST_RPI_CAM_SRC_IMAGEFX_NONE,
407           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
408 #if 0
409   PROP_IMAGE_EFFECT_PARAMS, PROP_COLOUR_EFFECTS,
410 #endif
411       g_object_class_install_property (gobject_class, PROP_ROTATION,
412       g_param_spec_int ("rotation", "Rotation",
413           "Rotate captured image (0, 90, 180, 270 degrees)", 0, 270, 0,
414           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
415   g_object_class_install_property (gobject_class, PROP_HFLIP,
416       g_param_spec_boolean ("hflip", "Horizontal Flip",
417           "Flip capture horizontally", FALSE,
418           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
419   g_object_class_install_property (gobject_class, PROP_VFLIP,
420       g_param_spec_boolean ("vflip", "Vertical Flip",
421           "Flip capture vertically", FALSE,
422           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
423   g_object_class_install_property (gobject_class, PROP_ROI_X,
424       g_param_spec_float ("roi-x", "ROI X",
425           "Normalised region-of-interest X coord", 0, 1.0, 0,
426           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
427   g_object_class_install_property (gobject_class, PROP_ROI_Y,
428       g_param_spec_float ("roi-y", "ROI Y",
429           "Normalised region-of-interest Y coord", 0, 1.0, 0,
430           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
431   g_object_class_install_property (gobject_class, PROP_ROI_W,
432       g_param_spec_float ("roi-w", "ROI W",
433           "Normalised region-of-interest W coord", 0, 1.0, 1.0,
434           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
435   g_object_class_install_property (gobject_class, PROP_ROI_H,
436       g_param_spec_float ("roi-h", "ROI H",
437           "Normalised region-of-interest H coord", 0, 1.0, 1.0,
438           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
439   g_object_class_install_property (gobject_class,
440       PROP_QUANTISATION_PARAMETER,
441       g_param_spec_int ("quantisation-parameter",
442           "Quantisation Parameter",
443           "Set a Quantisation Parameter approx 10-40 with bitrate=0 for VBR encoding. 0 = off",
444           0, G_MAXINT, QUANTISATION_DEFAULT,
445           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
446   g_object_class_install_property (gobject_class, PROP_INLINE_HEADERS,
447       g_param_spec_boolean ("inline-headers", "Inline Headers",
448           "Set to TRUE to insert SPS/PPS before each IDR packet", FALSE,
449           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
450   g_object_class_install_property (gobject_class, PROP_SHUTTER_SPEED,
451       g_param_spec_int ("shutter-speed", "Shutter Speed",
452           "Set a fixed shutter speed, in microseconds. (0 = Auto)", 0,
453           6000000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
454   g_object_class_install_property (gobject_class, PROP_SENSOR_MODE,
455       g_param_spec_enum ("sensor-mode", "Camera Sensor Mode",
456           "Manually set the camera sensor mode",
457           gst_rpi_cam_src_sensor_mode_get_type (),
458           GST_RPI_CAM_SRC_SENSOR_MODE_AUTOMATIC,
459           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
460   g_object_class_install_property (gobject_class, PROP_ANNOTATION_MODE,
461       g_param_spec_flags ("annotation-mode", "Annotation Mode",
462           "Flags to control annotation of the output video",
463           GST_RPI_CAM_TYPE_RPI_CAM_SRC_ANNOTATION_MODE, 0,
464           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
465   g_object_class_install_property (gobject_class, PROP_ANNOTATION_TEXT,
466       g_param_spec_string ("annotation-text", "Annotation Text",
467           "Text string to annotate onto video when annotation-mode flags include 'custom-text'",
468           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
469   g_object_class_install_property (gobject_class, PROP_INTRA_REFRESH_TYPE,
470       g_param_spec_enum ("intra-refresh-type", "Intra Refresh Type",
471           "Type of Intra Refresh to use, -1 to disable intra refresh",
472           GST_RPI_CAM_TYPE_RPI_CAM_SRC_INTRA_REFRESH_TYPE,
473           GST_RPI_CAM_SRC_INTRA_REFRESH_TYPE_NONE,
474           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
475   g_object_class_install_property (gobject_class, PROP_ANNOTATION_TEXT_SIZE,
476       g_param_spec_int ("annotation-text-size", "Annotation text size",
477           "Set the size of annotation text (in pixels) (0 = Auto)", 0,
478           G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
479   g_object_class_install_property (gobject_class, PROP_ANNOTATION_TEXT_COLOUR,
480       g_param_spec_int ("annotation-text-colour", "Annotation text colour (VUY)",
481           "Set the annotation text colour, as the integer corresponding to a VUY value eg 0x8080FF = 8421631, -1 for default", -1,
482           G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
483   g_object_class_install_property (gobject_class, PROP_ANNOTATION_TEXT_BG_COLOUR,
484       g_param_spec_int ("annotation-text-bg-colour", "Annotation text background colour (VUY)",
485           "Set the annotation text background colour, as the integer corresponding to a VUY value eg 0x8080FF = 8421631, -1 for default", -1,
486           G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
487 #ifdef GST_RPI_CAM_SRC_ENABLE_VIDEO_DIRECTION
488   g_object_class_override_property (gobject_class, PROP_VIDEO_DIRECTION,
489       "video-direction");
490 #endif
491
492   gst_element_class_set_static_metadata (gstelement_class,
493       "Raspberry Pi Camera Source", "Source/Video",
494       "Raspberry Pi camera module source", "Jan Schmidt <jan@centricular.com>");
495   gst_element_class_add_pad_template (gstelement_class,
496       gst_static_pad_template_get (&video_src_template));
497   basesrc_class->start = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_start);
498   basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_stop);
499   basesrc_class->decide_allocation =
500       GST_DEBUG_FUNCPTR (gst_rpi_cam_src_decide_allocation);
501   basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_get_caps);
502   basesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_set_caps);
503   basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_fixate);
504   basesrc_class->event = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_event);
505   gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_send_event);
506   pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_rpi_cam_src_create);
507   raspicapture_init ();
508 }
509
510 static void
511 gst_rpi_cam_src_init (GstRpiCamSrc * src)
512 {
513   GstColorBalanceChannel *channel;
514
515   gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
516   gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
517   raspicapture_default_config (&src->capture_config);
518   src->capture_config.intraperiod = KEYFRAME_INTERVAL_DEFAULT;
519   src->capture_config.verbose = 1;
520
521   g_mutex_init (&src->config_lock);
522
523   /* Don't let basesrc set timestamps, we'll do it using
524    * buffer PTS and system times */
525   gst_base_src_set_do_timestamp (GST_BASE_SRC (src), FALSE);
526
527   /* Generate the channels list */
528   channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
529   channel->label = g_strdup ("CONTRAST");
530   channel->min_value = -100;
531   channel->max_value = 100;
532   src->channels = g_list_append (src->channels, channel);
533
534   channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
535   channel->label = g_strdup ("BRIGHTNESS");
536   channel->min_value = 0;
537   channel->max_value = 100;
538   src->channels = g_list_append (src->channels, channel);
539
540   channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
541   channel->label = g_strdup ("SATURATION");
542   channel->min_value = -100;
543   channel->max_value = 100;
544   src->channels = g_list_append (src->channels, channel);
545 }
546
547 static void
548 gst_rpi_cam_src_finalize (GObject *object)
549 {
550   GstRpiCamSrc *src = GST_RPICAMSRC (object);
551   GList *channels = NULL;
552   g_mutex_clear (&src->config_lock);
553
554   channels = src->channels;
555   while (channels) {
556     GstColorBalanceChannel *channel = channels->data;
557
558     g_object_unref (channel);
559     channels->data = NULL;
560     channels = g_list_next (channels);
561   }
562
563   if (src->channels)
564     g_list_free (src->channels);
565
566   G_OBJECT_CLASS (gst_rpi_cam_src_parent_class)->finalize (object);
567 }
568
569 static const GList *
570 gst_rpi_cam_src_colorbalance_list_channels (GstColorBalance * balance)
571 {
572   GstRpiCamSrc *src = GST_RPICAMSRC (balance);
573
574   g_return_val_if_fail (src != NULL, NULL);
575   g_return_val_if_fail (GST_IS_RPICAMSRC (src), NULL);
576
577   return src->channels;
578 }
579
580 static void
581 gst_rpi_cam_src_colorbalance_set_value (GstColorBalance * balance,
582     GstColorBalanceChannel * channel, gint value)
583 {
584   GstRpiCamSrc *src = GST_RPICAMSRC (balance);
585   gboolean changed = FALSE;
586
587   g_return_if_fail (src != NULL);
588   g_return_if_fail (GST_IS_RPICAMSRC (src));
589   g_return_if_fail (channel->label != NULL);
590
591   g_mutex_lock (&src->config_lock);
592   if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
593     changed = value != src->capture_config.camera_parameters.saturation;
594     src->capture_config.camera_parameters.saturation = value;
595   } else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
596     changed = value != src->capture_config.camera_parameters.brightness;
597     src->capture_config.camera_parameters.brightness = value;
598   } else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
599     changed = value != src->capture_config.camera_parameters.contrast;
600     src->capture_config.camera_parameters.contrast = value;
601   }
602
603   if (changed)
604     src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE;
605
606   g_mutex_unlock (&src->config_lock);
607
608   if (changed) {
609     gst_color_balance_value_changed (balance, channel,
610         gst_color_balance_get_value (balance, channel));
611   }
612 }
613
614 static gint
615 gst_rpi_cam_src_colorbalance_get_value (GstColorBalance * balance,
616     GstColorBalanceChannel * channel)
617 {
618   GstRpiCamSrc *src = GST_RPICAMSRC (balance);
619   gint value = 0;
620
621   g_return_val_if_fail (src != NULL, 0);
622   g_return_val_if_fail (GST_IS_RPICAMSRC (src), 0);
623   g_return_val_if_fail (channel->label != NULL, 0);
624
625   g_mutex_lock (&src->config_lock);
626
627   if (!g_ascii_strcasecmp (channel->label, "SATURATION")) {
628     value = src->capture_config.camera_parameters.saturation;
629   } else if (!g_ascii_strcasecmp (channel->label, "BRIGHTNESS")) {
630     value = src->capture_config.camera_parameters.brightness;
631   } else if (!g_ascii_strcasecmp (channel->label, "CONTRAST")) {
632     value = src->capture_config.camera_parameters.contrast;
633   }
634
635   g_mutex_unlock (&src->config_lock);
636
637   return value;
638 }
639
640 static GstColorBalanceType
641 gst_rpi_cam_src_colorbalance_get_balance_type (GstColorBalance * balance)
642 {
643   return GST_COLOR_BALANCE_HARDWARE;
644 }
645
646 #ifdef GST_RPI_CAM_SRC_ENABLE_VIDEO_DIRECTION
647 static void gst_rpi_cam_src_set_orientation (GstRpiCamSrc * src, GstVideoOrientationMethod orientation)
648 {
649   switch (orientation) {
650     case GST_VIDEO_ORIENTATION_IDENTITY:
651       src->capture_config.camera_parameters.rotation = 0;
652       src->capture_config.camera_parameters.hflip = FALSE;
653       src->capture_config.camera_parameters.vflip = FALSE;
654       GST_DEBUG_OBJECT (src, "set orientation identity");
655       break;
656     case GST_VIDEO_ORIENTATION_90R:
657       src->capture_config.camera_parameters.rotation = 90;
658       src->capture_config.camera_parameters.hflip = FALSE;
659       src->capture_config.camera_parameters.vflip = FALSE;
660       GST_DEBUG_OBJECT (src, "set orientation 90R");
661       break;
662     case GST_VIDEO_ORIENTATION_180:
663       src->capture_config.camera_parameters.rotation = 180;
664       src->capture_config.camera_parameters.hflip = FALSE;
665       src->capture_config.camera_parameters.vflip = FALSE;
666       GST_DEBUG_OBJECT (src, "set orientation 180");
667       break;
668     case GST_VIDEO_ORIENTATION_90L:
669       src->capture_config.camera_parameters.rotation = 270;
670       src->capture_config.camera_parameters.hflip = FALSE;
671       src->capture_config.camera_parameters.vflip = FALSE;
672       GST_DEBUG_OBJECT (src, "set orientation 90L");
673       break;
674     case GST_VIDEO_ORIENTATION_HORIZ:
675       src->capture_config.camera_parameters.rotation = 0;
676       src->capture_config.camera_parameters.hflip = TRUE;
677       src->capture_config.camera_parameters.vflip = FALSE;
678       GST_DEBUG_OBJECT (src, "set orientation hflip");
679       break;
680     case GST_VIDEO_ORIENTATION_VERT:
681       src->capture_config.camera_parameters.rotation = 0;
682       src->capture_config.camera_parameters.hflip = FALSE;
683       src->capture_config.camera_parameters.vflip = TRUE;
684       GST_DEBUG_OBJECT (src, "set orientation vflip");
685       break;
686     case GST_VIDEO_ORIENTATION_UL_LR:
687       src->capture_config.camera_parameters.rotation = 90;
688       src->capture_config.camera_parameters.hflip = FALSE;
689       src->capture_config.camera_parameters.vflip = TRUE;
690       GST_DEBUG_OBJECT (src, "set orientation trans");
691       break;
692     case GST_VIDEO_ORIENTATION_UR_LL:
693       src->capture_config.camera_parameters.rotation = 270;
694       src->capture_config.camera_parameters.hflip = FALSE;
695       src->capture_config.camera_parameters.vflip = TRUE;
696       GST_DEBUG_OBJECT (src, "set orientation trans");
697       break;
698     case GST_VIDEO_ORIENTATION_CUSTOM:
699       break;
700     default:
701       GST_WARNING_OBJECT (src, "unsupported orientation %d", orientation);
702       break;
703   }
704   src->orientation =
705     orientation >= GST_VIDEO_ORIENTATION_IDENTITY &&
706     orientation <= GST_VIDEO_ORIENTATION_CUSTOM ?
707       orientation : GST_VIDEO_ORIENTATION_CUSTOM;
708   src->capture_config.change_flags |= PROP_CHANGE_ORIENTATION;
709 }
710
711 static void
712 gst_rpi_cam_src_direction_init (GstVideoDirectionInterface * iface)
713 {
714   /* We implement the video-direction property */
715 }
716 #endif
717
718 static void
719 gst_rpi_cam_src_colorbalance_init (GstColorBalanceInterface * iface)
720 {
721   iface->list_channels = gst_rpi_cam_src_colorbalance_list_channels;
722   iface->set_value = gst_rpi_cam_src_colorbalance_set_value;
723   iface->get_value = gst_rpi_cam_src_colorbalance_get_value;
724   iface->get_balance_type = gst_rpi_cam_src_colorbalance_get_balance_type;
725 }
726
727 static gboolean
728 gst_rpi_cam_src_orientation_get_hflip (GstVideoOrientation * orientation, gboolean * flip)
729 {
730   GstRpiCamSrc *src = GST_RPICAMSRC (orientation);
731
732   g_return_val_if_fail (src != NULL, FALSE);
733   g_return_val_if_fail (GST_IS_RPICAMSRC (src), FALSE);
734
735   g_mutex_lock (&src->config_lock);
736   *flip = src->capture_config.camera_parameters.hflip;
737   g_mutex_unlock (&src->config_lock);
738
739   return TRUE;
740 }
741
742 static gboolean
743 gst_rpi_cam_src_orientation_get_vflip (GstVideoOrientation * orientation, gboolean * flip)
744 {
745   GstRpiCamSrc *src = GST_RPICAMSRC (orientation);
746
747   g_return_val_if_fail (src != NULL, FALSE);
748   g_return_val_if_fail (GST_IS_RPICAMSRC (src), FALSE);
749
750   g_mutex_lock (&src->config_lock);
751   *flip = src->capture_config.camera_parameters.vflip;
752   g_mutex_unlock (&src->config_lock);
753
754   return TRUE;
755 }
756
757 static gboolean
758 gst_rpi_cam_src_orientation_set_hflip (GstVideoOrientation * orientation, gboolean flip)
759 {
760   GstRpiCamSrc *src = GST_RPICAMSRC (orientation);
761
762   g_return_val_if_fail (src != NULL, FALSE);
763   g_return_val_if_fail (GST_IS_RPICAMSRC (src), FALSE);
764
765   g_mutex_lock (&src->config_lock);
766   gst_rpi_cam_src_reset_custom_orientation(src);
767   src->capture_config.camera_parameters.hflip = flip;
768   src->capture_config.change_flags |= PROP_CHANGE_ORIENTATION;
769   g_mutex_unlock (&src->config_lock);
770
771   return TRUE;
772 }
773
774 static gboolean
775 gst_rpi_cam_src_orientation_set_vflip (GstVideoOrientation * orientation, gboolean flip)
776 {
777   GstRpiCamSrc *src = GST_RPICAMSRC (orientation);
778
779   g_return_val_if_fail (src != NULL, FALSE);
780   g_return_val_if_fail (GST_IS_RPICAMSRC (src), FALSE);
781
782   g_mutex_lock (&src->config_lock);
783   gst_rpi_cam_src_reset_custom_orientation(src);
784   src->capture_config.camera_parameters.vflip = flip;
785   src->capture_config.change_flags |= PROP_CHANGE_ORIENTATION;
786   g_mutex_unlock (&src->config_lock);
787
788   return TRUE;
789 }
790
791 static void
792 gst_rpi_cam_src_orientation_init (GstVideoOrientationInterface * iface)
793 {
794   iface->get_hflip = gst_rpi_cam_src_orientation_get_hflip;
795   iface->set_hflip = gst_rpi_cam_src_orientation_set_hflip;
796   iface->get_vflip = gst_rpi_cam_src_orientation_get_vflip;
797   iface->set_vflip = gst_rpi_cam_src_orientation_set_vflip;
798
799   /* TODO: hcenter / vcenter support */
800 }
801
802 static void
803 gst_rpi_cam_src_set_property (GObject * object, guint prop_id,
804     const GValue * value, GParamSpec * pspec)
805 {
806   GstRpiCamSrc *src = GST_RPICAMSRC (object);
807
808   g_mutex_lock (&src->config_lock);
809
810   switch (prop_id) {
811     case PROP_CAMERA_NUMBER:
812       src->capture_config.cameraNum = g_value_get_int (value);
813       break;
814     case PROP_BITRATE:
815       src->capture_config.bitrate = g_value_get_int (value);
816       src->capture_config.change_flags |= PROP_CHANGE_ENCODING;
817       break;
818     case PROP_JPEG_QUALITY:
819       src->capture_config.jpegQuality = g_value_get_int (value);
820       src->capture_config.change_flags |= PROP_CHANGE_ENCODING;
821       break;
822     case PROP_KEYFRAME_INTERVAL:
823       src->capture_config.intraperiod = g_value_get_int (value);
824       src->capture_config.change_flags |= PROP_CHANGE_ENCODING;
825       break;
826     case PROP_PREVIEW:
827       src->capture_config.preview_parameters.wantPreview =
828           g_value_get_boolean (value);
829       src->capture_config.change_flags |= PROP_CHANGE_PREVIEW;
830       break;
831     case PROP_PREVIEW_ENCODED:
832       src->capture_config.immutableInput = g_value_get_boolean (value);
833       src->capture_config.change_flags |= PROP_CHANGE_PREVIEW;
834       break;
835     case PROP_FULLSCREEN:
836       src->capture_config.preview_parameters.wantFullScreenPreview =
837           g_value_get_boolean (value);
838       src->capture_config.change_flags |= PROP_CHANGE_PREVIEW;
839       break;
840     case PROP_PREVIEW_OPACITY:
841       src->capture_config.preview_parameters.opacity = g_value_get_int (value);
842       src->capture_config.change_flags |= PROP_CHANGE_PREVIEW;
843       break;
844     case PROP_PREVIEW_X:
845       src->capture_config.preview_parameters.previewWindow.x = g_value_get_int (value);
846       src->capture_config.change_flags |= PROP_CHANGE_PREVIEW;
847       break;
848     case PROP_PREVIEW_Y:
849       src->capture_config.preview_parameters.previewWindow.y = g_value_get_int (value);
850       src->capture_config.change_flags |= PROP_CHANGE_PREVIEW;
851       break;
852     case PROP_PREVIEW_W:
853       src->capture_config.preview_parameters.previewWindow.width = g_value_get_int (value);
854       src->capture_config.change_flags |= PROP_CHANGE_PREVIEW;
855       break;
856     case PROP_PREVIEW_H:
857       src->capture_config.preview_parameters.previewWindow.height = g_value_get_int (value);
858       src->capture_config.change_flags |= PROP_CHANGE_PREVIEW;
859       break;
860     case PROP_SHARPNESS:
861       src->capture_config.camera_parameters.sharpness = g_value_get_int (value);
862       src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE;
863       break;
864     case PROP_CONTRAST:
865       src->capture_config.camera_parameters.contrast = g_value_get_int (value);
866       src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE;
867       break;
868     case PROP_BRIGHTNESS:
869       src->capture_config.camera_parameters.brightness =
870           g_value_get_int (value);
871       src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE;
872       break;
873     case PROP_SATURATION:
874       src->capture_config.camera_parameters.saturation =
875           g_value_get_int (value);
876       src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE;
877       break;
878     case PROP_ISO:
879       src->capture_config.camera_parameters.ISO = g_value_get_int (value);
880       src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
881       break;
882     case PROP_VIDEO_STABILISATION:
883       src->capture_config.camera_parameters.videoStabilisation =
884           g_value_get_boolean (value);
885       src->capture_config.change_flags |= PROP_CHANGE_VIDEO_STABILISATION;
886       break;
887     case PROP_EXPOSURE_COMPENSATION:
888       src->capture_config.camera_parameters.exposureCompensation =
889           g_value_get_int (value);
890       src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
891       break;
892     case PROP_EXPOSURE_MODE:
893       src->capture_config.camera_parameters.exposureMode =
894           g_value_get_enum (value);
895       src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
896       break;
897     case PROP_EXPOSURE_METERING_MODE:
898       src->capture_config.camera_parameters.exposureMeterMode =
899           g_value_get_enum (value);
900       src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
901       break;
902     case PROP_ROTATION:
903       gst_rpi_cam_src_reset_custom_orientation(src);
904       src->capture_config.camera_parameters.rotation = g_value_get_int (value);
905       break;
906     case PROP_AWB_MODE:
907       src->capture_config.camera_parameters.awbMode = g_value_get_enum (value);
908       src->capture_config.change_flags |= PROP_CHANGE_AWB;
909       break;
910     case PROP_AWB_GAIN_RED:
911       src->capture_config.camera_parameters.awb_gains_r =
912           g_value_get_float (value);
913       src->capture_config.change_flags |= PROP_CHANGE_AWB;
914       break;
915     case PROP_AWB_GAIN_BLUE:
916       src->capture_config.camera_parameters.awb_gains_b =
917           g_value_get_float (value);
918       src->capture_config.change_flags |= PROP_CHANGE_AWB;
919       break;
920     case PROP_IMAGE_EFFECT:
921       src->capture_config.camera_parameters.imageEffect =
922           g_value_get_enum (value);
923       src->capture_config.change_flags |= PROP_CHANGE_IMAGE_COLOUR_EFFECT;
924       break;
925     case PROP_HFLIP:
926       gst_rpi_cam_src_reset_custom_orientation(src);
927       src->capture_config.camera_parameters.hflip = g_value_get_boolean (value);
928       src->capture_config.change_flags |= PROP_CHANGE_ORIENTATION;
929       break;
930     case PROP_VFLIP:
931       gst_rpi_cam_src_reset_custom_orientation(src);
932       src->capture_config.camera_parameters.vflip = g_value_get_boolean (value);
933       src->capture_config.change_flags |= PROP_CHANGE_ORIENTATION;
934       break;
935     case PROP_ROI_X:
936       src->capture_config.camera_parameters.roi.x = g_value_get_float (value);
937       src->capture_config.change_flags |= PROP_CHANGE_ROI;
938       break;
939     case PROP_ROI_Y:
940       src->capture_config.camera_parameters.roi.y = g_value_get_float (value);
941       src->capture_config.change_flags |= PROP_CHANGE_ROI;
942       break;
943     case PROP_ROI_W:
944       src->capture_config.camera_parameters.roi.w = g_value_get_float (value);
945       src->capture_config.change_flags |= PROP_CHANGE_ROI;
946       break;
947     case PROP_ROI_H:
948       src->capture_config.camera_parameters.roi.h = g_value_get_float (value);
949       src->capture_config.change_flags |= PROP_CHANGE_ROI;
950       break;
951     case PROP_QUANTISATION_PARAMETER:
952       src->capture_config.quantisationParameter = g_value_get_int (value);
953       src->capture_config.change_flags |= PROP_CHANGE_ENCODING;
954       break;
955     case PROP_INLINE_HEADERS:
956       src->capture_config.bInlineHeaders = g_value_get_boolean (value);
957       break;
958     case PROP_SHUTTER_SPEED:
959       src->capture_config.camera_parameters.shutter_speed =
960           g_value_get_int (value);
961       src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
962       break;
963     case PROP_DRC:
964       src->capture_config.camera_parameters.drc_level =
965           g_value_get_enum (value);
966       src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
967       break;
968     case PROP_SENSOR_MODE:
969       src->capture_config.sensor_mode = g_value_get_enum (value);
970       src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
971       break;
972     case PROP_ANNOTATION_MODE:
973       src->capture_config.camera_parameters.enable_annotate =
974           g_value_get_flags (value);
975       src->capture_config.change_flags |= PROP_CHANGE_ANNOTATION;
976       break;
977     case PROP_ANNOTATION_TEXT:
978       strncpy (src->capture_config.camera_parameters.annotate_string,
979           g_value_get_string (value), MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V2);
980       src->capture_config.
981           camera_parameters.annotate_string[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V2
982           - 1] = '\0';
983       src->capture_config.change_flags |= PROP_CHANGE_ANNOTATION;
984       break;
985     case PROP_ANNOTATION_TEXT_SIZE:
986       src->capture_config.
987           camera_parameters.annotate_text_size = g_value_get_int (value);
988       src->capture_config.change_flags |= PROP_CHANGE_ANNOTATION;
989       break;
990     case PROP_ANNOTATION_TEXT_COLOUR:
991       src->capture_config.
992           camera_parameters.annotate_text_colour = g_value_get_int (value);
993       src->capture_config.change_flags |= PROP_CHANGE_ANNOTATION;
994       break;
995     case PROP_ANNOTATION_TEXT_BG_COLOUR:
996       src->capture_config.
997           camera_parameters.annotate_bg_colour = g_value_get_int (value);
998       src->capture_config.change_flags |= PROP_CHANGE_ANNOTATION;
999       break;
1000     case PROP_INTRA_REFRESH_TYPE:
1001       src->capture_config.intra_refresh_type = g_value_get_enum (value);
1002       src->capture_config.change_flags |= PROP_CHANGE_ENCODING;
1003       break;
1004 #ifdef GST_RPI_CAM_SRC_ENABLE_VIDEO_DIRECTION
1005     case PROP_VIDEO_DIRECTION:
1006       gst_rpi_cam_src_set_orientation (src, g_value_get_enum (value));
1007       break;
1008 #endif
1009     default:
1010       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1011       break;
1012   }
1013
1014   g_mutex_unlock (&src->config_lock);
1015 }
1016
1017 static void
1018 gst_rpi_cam_src_get_property (GObject * object, guint prop_id,
1019     GValue * value, GParamSpec * pspec)
1020 {
1021   GstRpiCamSrc *src = GST_RPICAMSRC (object);
1022
1023   g_mutex_lock (&src->config_lock);
1024   switch (prop_id) {
1025     case PROP_CAMERA_NUMBER:
1026       g_value_set_int (value, src->capture_config.cameraNum);
1027       break;
1028     case PROP_BITRATE:
1029       g_value_set_int (value, src->capture_config.bitrate);
1030       break;
1031     case PROP_JPEG_QUALITY:
1032       g_value_set_int (value, src->capture_config.jpegQuality);
1033       break;
1034     case PROP_KEYFRAME_INTERVAL:
1035       g_value_set_int (value, src->capture_config.intraperiod);
1036       break;
1037     case PROP_PREVIEW:
1038       g_value_set_boolean (value,
1039           src->capture_config.preview_parameters.wantPreview);
1040       break;
1041     case PROP_PREVIEW_ENCODED:
1042       g_value_set_boolean (value, src->capture_config.immutableInput);
1043       break;
1044     case PROP_FULLSCREEN:
1045       g_value_set_boolean (value,
1046           src->capture_config.preview_parameters.wantFullScreenPreview);
1047       break;
1048     case PROP_PREVIEW_OPACITY:
1049       g_value_set_int (value, src->capture_config.preview_parameters.opacity);
1050       break;
1051     case PROP_PREVIEW_X:
1052       g_value_set_int (value, src->capture_config.preview_parameters.previewWindow.x);
1053       break;
1054     case PROP_PREVIEW_Y:
1055       g_value_set_int (value, src->capture_config.preview_parameters.previewWindow.y);
1056       break;
1057     case PROP_PREVIEW_W:
1058       g_value_set_int (value, src->capture_config.preview_parameters.previewWindow.width);
1059       break;
1060     case PROP_PREVIEW_H:
1061       g_value_set_int (value, src->capture_config.preview_parameters.previewWindow.height);
1062       break;
1063     case PROP_SHARPNESS:
1064       g_value_set_int (value, src->capture_config.camera_parameters.sharpness);
1065       break;
1066     case PROP_CONTRAST:
1067       g_value_set_int (value, src->capture_config.camera_parameters.contrast);
1068       break;
1069     case PROP_BRIGHTNESS:
1070       g_value_set_int (value, src->capture_config.camera_parameters.brightness);
1071       break;
1072     case PROP_SATURATION:
1073       g_value_set_int (value, src->capture_config.camera_parameters.saturation);
1074       break;
1075     case PROP_ISO:
1076       g_value_set_int (value, src->capture_config.camera_parameters.ISO);
1077       break;
1078     case PROP_VIDEO_STABILISATION:
1079       g_value_set_boolean (value,
1080           ! !(src->capture_config.camera_parameters.videoStabilisation));
1081       break;
1082     case PROP_EXPOSURE_COMPENSATION:
1083       g_value_set_int (value,
1084           src->capture_config.camera_parameters.exposureCompensation);
1085       break;
1086     case PROP_EXPOSURE_MODE:
1087       g_value_set_enum (value,
1088           src->capture_config.camera_parameters.exposureMode);
1089       break;
1090     case PROP_EXPOSURE_METERING_MODE:
1091       g_value_set_enum (value,
1092           src->capture_config.camera_parameters.exposureMeterMode);
1093       break;
1094     case PROP_ROTATION:
1095       g_value_set_int (value, src->capture_config.camera_parameters.rotation);
1096       break;
1097     case PROP_AWB_MODE:
1098       g_value_set_enum (value, src->capture_config.camera_parameters.awbMode);
1099       break;
1100     case PROP_AWB_GAIN_RED:
1101       g_value_set_float (value,
1102           src->capture_config.camera_parameters.awb_gains_r);
1103       break;
1104     case PROP_AWB_GAIN_BLUE:
1105       g_value_set_float (value,
1106           src->capture_config.camera_parameters.awb_gains_b);
1107       break;
1108     case PROP_IMAGE_EFFECT:
1109       g_value_set_enum (value,
1110           src->capture_config.camera_parameters.imageEffect);
1111       break;
1112     case PROP_HFLIP:
1113       g_value_set_boolean (value,
1114           ! !(src->capture_config.camera_parameters.hflip));
1115       break;
1116     case PROP_VFLIP:
1117       g_value_set_boolean (value,
1118           ! !(src->capture_config.camera_parameters.vflip));
1119       break;
1120     case PROP_ROI_X:
1121       g_value_set_float (value, src->capture_config.camera_parameters.roi.x);
1122       break;
1123     case PROP_ROI_Y:
1124       g_value_set_float (value, src->capture_config.camera_parameters.roi.y);
1125       break;
1126     case PROP_ROI_W:
1127       g_value_set_float (value, src->capture_config.camera_parameters.roi.w);
1128       break;
1129     case PROP_ROI_H:
1130       g_value_set_float (value, src->capture_config.camera_parameters.roi.h);
1131       break;
1132     case PROP_QUANTISATION_PARAMETER:
1133       g_value_set_int (value, src->capture_config.quantisationParameter);
1134       break;
1135     case PROP_INLINE_HEADERS:
1136       g_value_set_boolean (value, src->capture_config.bInlineHeaders);
1137       break;
1138     case PROP_SHUTTER_SPEED:
1139       g_value_set_int (value,
1140           src->capture_config.camera_parameters.shutter_speed);
1141       break;
1142     case PROP_DRC:
1143       g_value_set_enum (value, src->capture_config.camera_parameters.drc_level);
1144       break;
1145     case PROP_SENSOR_MODE:
1146       g_value_set_enum (value, src->capture_config.sensor_mode);
1147       break;
1148     case PROP_ANNOTATION_MODE:
1149       g_value_set_flags (value,
1150           src->capture_config.camera_parameters.enable_annotate);
1151       break;
1152     case PROP_ANNOTATION_TEXT:
1153       g_value_set_string (value,
1154           src->capture_config.camera_parameters.annotate_string);
1155       break;
1156     case PROP_ANNOTATION_TEXT_SIZE:
1157       g_value_set_int (value, src->capture_config.camera_parameters.annotate_text_size);
1158       break;
1159     case PROP_ANNOTATION_TEXT_COLOUR:
1160       g_value_set_int (value, src->capture_config.camera_parameters.annotate_text_colour);
1161       break;
1162     case PROP_ANNOTATION_TEXT_BG_COLOUR:
1163       g_value_set_int (value, src->capture_config.camera_parameters.annotate_bg_colour);
1164       break;
1165     case PROP_INTRA_REFRESH_TYPE:
1166       g_value_set_enum (value, src->capture_config.intra_refresh_type);
1167       break;
1168 #ifdef GST_RPI_CAM_SRC_ENABLE_VIDEO_DIRECTION
1169     case PROP_VIDEO_DIRECTION:
1170       g_value_set_enum (value, src->orientation);
1171       break;
1172 #endif
1173     default:
1174       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1175       break;
1176   }
1177   g_mutex_unlock (&src->config_lock);
1178 }
1179
1180 static gboolean
1181 gst_rpi_cam_src_start (GstBaseSrc * parent)
1182 {
1183   GstRpiCamSrc *src = GST_RPICAMSRC (parent);
1184   GST_LOG_OBJECT (src, "In src_start()");
1185   g_mutex_lock (&src->config_lock);
1186   src->capture_state = raspi_capture_setup (&src->capture_config);
1187   /* Clear all capture flags */
1188   src->capture_config.change_flags = 0;
1189   g_mutex_unlock (&src->config_lock);
1190   if (src->capture_state == NULL)
1191     return FALSE;
1192   return TRUE;
1193 }
1194
1195 static gboolean
1196 gst_rpi_cam_src_stop (GstBaseSrc * parent)
1197 {
1198   GstRpiCamSrc *src = GST_RPICAMSRC (parent);
1199   if (src->started)
1200     raspi_capture_stop (src->capture_state);
1201   raspi_capture_free (src->capture_state);
1202   src->capture_state = NULL;
1203   return TRUE;
1204 }
1205
1206 static gboolean
1207 gst_rpi_cam_src_send_event (GstElement * parent, GstEvent * event)
1208 {
1209   GstRpiCamSrc *src = GST_RPICAMSRC (parent);
1210   gboolean ret;
1211   switch (GST_EVENT_TYPE (event)) {
1212     case GST_EVENT_CUSTOM_DOWNSTREAM:
1213     case GST_EVENT_CUSTOM_UPSTREAM:
1214       if (gst_video_event_is_force_key_unit (event)) {
1215         if (src->started) {
1216           ret = raspi_capture_request_i_frame (src->capture_state);
1217         } else {
1218           ret = FALSE;
1219         }
1220         gst_event_unref (event);
1221       } else {
1222         ret = GST_ELEMENT_CLASS (parent_class)->send_event (parent, event);
1223       }
1224       break;
1225     default:
1226       ret = GST_ELEMENT_CLASS (parent_class)->send_event (parent, event);
1227       break;
1228   }
1229   return ret;
1230 }
1231
1232 static gboolean
1233 gst_rpi_cam_src_event (GstBaseSrc * parent, GstEvent * event)
1234 {
1235   GstRpiCamSrc *src = GST_RPICAMSRC (parent);
1236   gboolean ret;
1237   switch (GST_EVENT_TYPE (event)) {
1238     case GST_EVENT_CUSTOM_DOWNSTREAM:
1239     case GST_EVENT_CUSTOM_UPSTREAM:
1240       if (gst_video_event_is_force_key_unit (event)) {
1241         if (src->started) {
1242           ret = raspi_capture_request_i_frame (src->capture_state);
1243         } else {
1244           ret = FALSE;
1245         }
1246       } else {
1247         ret = GST_BASE_SRC_CLASS (parent_class)->event (parent, event);
1248       }
1249       break;
1250     default:
1251       ret = GST_BASE_SRC_CLASS (parent_class)->event (parent, event);
1252       break;
1253   }
1254   return ret;
1255 }
1256
1257 static GstCaps *
1258 gst_rpi_cam_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
1259 {
1260   GstRpiCamSrc *src = GST_RPICAMSRC (bsrc);
1261   GstCaps *caps;
1262   gint i;
1263
1264   caps = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (bsrc));
1265   if (src->capture_state == NULL)
1266     goto done;
1267   /* FIXME: Retrieve limiting parameters from the camera module, max width/height fps-range */
1268   caps = gst_caps_make_writable (caps);
1269   for (i = 0; i < gst_caps_get_size (caps); i++) {
1270     GstStructure *s = gst_caps_get_structure (caps, i);
1271     if (gst_structure_has_name (s, "video/x-h264")) {
1272        gst_caps_set_simple (caps, "width", GST_TYPE_INT_RANGE, 1, 1920, "height",
1273            GST_TYPE_INT_RANGE, 1, 1080, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
1274            90, 1, NULL);
1275     }
1276     else {
1277        gst_caps_set_simple (caps, "width", GST_TYPE_INT_RANGE, 1, 3240, "height",
1278            GST_TYPE_INT_RANGE, 1, 2464, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1,
1279            90, 1, NULL);
1280     }
1281   }
1282 done:
1283   GST_DEBUG_OBJECT (src, "get_caps returning %" GST_PTR_FORMAT, caps);
1284   return caps;
1285 }
1286
1287 static gboolean
1288 gst_rpi_cam_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
1289 {
1290   GstRpiCamSrc *src = GST_RPICAMSRC (bsrc);
1291   GstVideoInfo info;
1292   GstStructure *structure;
1293   const gchar *profile_str = NULL;
1294
1295   GST_DEBUG_OBJECT (src, "In set_caps %" GST_PTR_FORMAT, caps);
1296   if (!gst_video_info_from_caps (&info, caps))
1297     return FALSE;
1298
1299   structure = gst_caps_get_structure (caps, 0);
1300   if (gst_structure_has_name (structure, "video/x-h264")) {
1301     src->capture_config.encoding = MMAL_ENCODING_H264;
1302     profile_str = gst_structure_get_string (structure, "profile");
1303     if (profile_str) {
1304       if (g_str_equal (profile_str, "baseline"))
1305         src->capture_config.profile = MMAL_VIDEO_PROFILE_H264_BASELINE;
1306       else if (g_str_equal (profile_str, "main"))
1307         src->capture_config.profile = MMAL_VIDEO_PROFILE_H264_MAIN;
1308       else if (g_str_equal (profile_str, "high"))
1309         src->capture_config.profile = MMAL_VIDEO_PROFILE_H264_HIGH;
1310       else
1311         g_warning ("Unknown profile string in rpicamsrc caps: %s", profile_str);
1312     }
1313   }
1314   else if (gst_structure_has_name (structure, "image/jpeg")) {
1315 #ifdef USE_JPEG_CODEC
1316     src->capture_config.encoding = MMAL_ENCODING_JPEG;
1317 #else
1318     src->capture_config.encoding = MMAL_ENCODING_MJPEG;
1319 #endif
1320   }
1321   else {
1322     /* Raw caps */
1323     switch (GST_VIDEO_INFO_FORMAT(&info)) {
1324     case GST_VIDEO_FORMAT_I420:
1325       src->capture_config.encoding = MMAL_ENCODING_I420;
1326       break;
1327     case GST_VIDEO_FORMAT_RGB:
1328       src->capture_config.encoding = MMAL_ENCODING_RGB24;
1329       break;
1330     case GST_VIDEO_FORMAT_BGR:
1331       src->capture_config.encoding = MMAL_ENCODING_BGR24;
1332       break;
1333     case GST_VIDEO_FORMAT_RGBA:
1334       src->capture_config.encoding = MMAL_ENCODING_RGBA;
1335       break;
1336     default:
1337       return FALSE;
1338     }
1339   }
1340
1341   src->capture_config.width = info.width;
1342   src->capture_config.height = info.height;
1343   src->capture_config.fps_n = info.fps_n;
1344   src->capture_config.fps_d = info.fps_d;
1345
1346   if (info.fps_n != 0 && info.fps_d != 0)
1347     src->duration = gst_util_uint64_scale_int (GST_SECOND, info.fps_d,
1348                         info.fps_n);
1349   else
1350     src->duration = GST_CLOCK_TIME_NONE;
1351
1352   return TRUE;
1353 }
1354
1355 static gboolean
1356 gst_rpi_cam_src_decide_allocation (GstBaseSrc * bsrc, GstQuery * query)
1357 {
1358   GST_LOG_OBJECT (bsrc, "In decide_allocation");
1359   return GST_BASE_SRC_CLASS (parent_class)->decide_allocation (bsrc, query);
1360 }
1361
1362 static GstCaps *
1363 gst_rpi_cam_src_fixate (GstBaseSrc * basesrc, GstCaps * caps)
1364 {
1365   GstStructure *structure;
1366   gint i;
1367   GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps);
1368   caps = gst_caps_make_writable (caps);
1369   for (i = 0; i < gst_caps_get_size (caps); ++i) {
1370     structure = gst_caps_get_structure (caps, i);
1371     /* Fixate to 1920x1080 resolution if possible */
1372     gst_structure_fixate_field_nearest_int (structure, "width", 1920);
1373     gst_structure_fixate_field_nearest_int (structure, "height", 1080);
1374     gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1);
1375     gst_structure_fixate_field (structure, "format");
1376   }
1377
1378   GST_DEBUG_OBJECT (basesrc, "fixated caps %" GST_PTR_FORMAT, caps);
1379   caps = GST_BASE_SRC_CLASS (parent_class)->fixate (basesrc, caps);
1380   return caps;
1381 }
1382
1383 static GstFlowReturn
1384 gst_rpi_cam_src_create (GstPushSrc * parent, GstBuffer ** buf)
1385 {
1386   GstRpiCamSrc *src = GST_RPICAMSRC (parent);
1387   GstFlowReturn ret;
1388   GstClock *clock = NULL;
1389   GstClockTime base_time;
1390
1391   if (!src->started) {
1392     g_mutex_lock (&src->config_lock);
1393     raspi_capture_update_config (src->capture_state, &src->capture_config, FALSE);
1394     src->capture_config.change_flags = 0;
1395     g_mutex_unlock (&src->config_lock);
1396     
1397     if (!raspi_capture_start (src->capture_state))
1398       return GST_FLOW_ERROR;
1399     src->started = TRUE;
1400   }
1401
1402   GST_OBJECT_LOCK (src);
1403   if ((clock = GST_ELEMENT_CLOCK (src)) != NULL)
1404     gst_object_ref (clock);
1405   base_time = GST_ELEMENT_CAST (src)->base_time;
1406   GST_OBJECT_UNLOCK (src);
1407
1408   g_mutex_lock (&src->config_lock);
1409   if (src->capture_config.change_flags) {
1410     raspi_capture_update_config (src->capture_state, &src->capture_config, TRUE);
1411     src->capture_config.change_flags = 0;
1412   }
1413   g_mutex_unlock (&src->config_lock);
1414
1415   /* FIXME: Use custom allocator */
1416   ret = raspi_capture_fill_buffer (src->capture_state, buf, clock, base_time);
1417   if (*buf) {
1418     GST_LOG_OBJECT (src, "Made buffer of size %" G_GSIZE_FORMAT,
1419         gst_buffer_get_size (*buf));
1420     GST_BUFFER_DURATION (*buf) = src->duration;
1421   }
1422
1423   if (clock)
1424     gst_object_unref (clock);
1425   return ret;
1426 }
1427
1428 static gboolean
1429 plugin_init (GstPlugin * plugin)
1430 {
1431   gboolean ret;
1432   GST_DEBUG_CATEGORY_INIT (gst_rpi_cam_src_debug, "rpicamsrc",
1433       0, "rpicamsrc debug");
1434   ret = gst_element_register (plugin, "rpicamsrc", GST_RANK_NONE,
1435       GST_TYPE_RPICAMSRC);
1436 #if GST_CHECK_VERSION (1,4,0)
1437   ret &= gst_device_provider_register (plugin, "rpicamsrcdeviceprovider",
1438       GST_RANK_PRIMARY, GST_TYPE_RPICAMSRC_DEVICE_PROVIDER);
1439 #endif
1440   return ret;
1441 }
1442
1443 #ifndef PACKAGE
1444 #define PACKAGE "gstrpicamsrc"
1445 #endif
1446
1447 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1448     GST_VERSION_MINOR,
1449     rpicamsrc,
1450     "Raspberry Pi Camera Source",
1451     plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")