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