1 /*
2 Copyright (c) 2013, Broadcom Europe Ltd
3 Copyright (c) 2013, James Hughes
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8     * Redistributions of source code must retain the above copyright
9       notice, this list of conditions and the following disclaimer.
10     * Redistributions in binary form must reproduce the above copyright
11       notice, this list of conditions and the following disclaimer in the
12       documentation and/or other materials provided with the distribution.
13     * Neither the name of the copyright holder nor the
14       names of its contributors may be used to endorse or promote products
15       derived from this software without specific prior written permission.
16 
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include <stdio.h>
30 #include <memory.h>
31 #include <ctype.h>
32 
33 #include "interface/vcos/vcos.h"
34 
35 #include "interface/vmcs_host/vc_vchi_gencmd.h"
36 #include "interface/mmal/mmal.h"
37 #include "interface/mmal/mmal_logging.h"
38 #include "interface/mmal/util/mmal_util.h"
39 #include "interface/mmal/util/mmal_util_params.h"
40 #include "interface/mmal/util/mmal_default_components.h"
41 #include "interface/mmal/util/mmal_connection.h"
42 
43 #include "RaspiCamControl.h"
44 #include "RaspiCLI.h"
45 #include "RaspiHelpers.h"
46 
47 /// Structure to cross reference exposure strings against the MMAL parameter equivalent
48 static XREF_T  exposure_map[] =
49 {
50    {"off",           MMAL_PARAM_EXPOSUREMODE_OFF},
51    {"auto",          MMAL_PARAM_EXPOSUREMODE_AUTO},
52    {"night",         MMAL_PARAM_EXPOSUREMODE_NIGHT},
53    {"nightpreview",  MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW},
54    {"backlight",     MMAL_PARAM_EXPOSUREMODE_BACKLIGHT},
55    {"spotlight",     MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT},
56    {"sports",        MMAL_PARAM_EXPOSUREMODE_SPORTS},
57    {"snow",          MMAL_PARAM_EXPOSUREMODE_SNOW},
58    {"beach",         MMAL_PARAM_EXPOSUREMODE_BEACH},
59    {"verylong",      MMAL_PARAM_EXPOSUREMODE_VERYLONG},
60    {"fixedfps",      MMAL_PARAM_EXPOSUREMODE_FIXEDFPS},
61    {"antishake",     MMAL_PARAM_EXPOSUREMODE_ANTISHAKE},
62    {"fireworks",     MMAL_PARAM_EXPOSUREMODE_FIREWORKS}
63 };
64 
65 static const int exposure_map_size = sizeof(exposure_map) / sizeof(exposure_map[0]);
66 
67 /// Structure to cross reference flicker avoid strings against the MMAL parameter equivalent
68 
69 static XREF_T  flicker_avoid_map[] =
70 {
71    {"off",           MMAL_PARAM_FLICKERAVOID_OFF},
72    {"auto",          MMAL_PARAM_FLICKERAVOID_AUTO},
73    {"50hz",          MMAL_PARAM_FLICKERAVOID_50HZ},
74    {"60hz",          MMAL_PARAM_FLICKERAVOID_60HZ}
75 };
76 
77 static const int flicker_avoid_map_size = sizeof(flicker_avoid_map) / sizeof(flicker_avoid_map[0]);
78 
79 /// Structure to cross reference awb strings against the MMAL parameter equivalent
80 static XREF_T awb_map[] =
81 {
82    {"off",           MMAL_PARAM_AWBMODE_OFF},
83    {"auto",          MMAL_PARAM_AWBMODE_AUTO},
84    {"sun",           MMAL_PARAM_AWBMODE_SUNLIGHT},
85    {"cloud",         MMAL_PARAM_AWBMODE_CLOUDY},
86    {"shade",         MMAL_PARAM_AWBMODE_SHADE},
87    {"tungsten",      MMAL_PARAM_AWBMODE_TUNGSTEN},
88    {"fluorescent",   MMAL_PARAM_AWBMODE_FLUORESCENT},
89    {"incandescent",  MMAL_PARAM_AWBMODE_INCANDESCENT},
90    {"flash",         MMAL_PARAM_AWBMODE_FLASH},
91    {"horizon",       MMAL_PARAM_AWBMODE_HORIZON}
92 };
93 
94 static const int awb_map_size = sizeof(awb_map) / sizeof(awb_map[0]);
95 
96 /// Structure to cross reference image effect against the MMAL parameter equivalent
97 static XREF_T imagefx_map[] =
98 {
99    {"none",          MMAL_PARAM_IMAGEFX_NONE},
100    {"negative",      MMAL_PARAM_IMAGEFX_NEGATIVE},
101    {"solarise",      MMAL_PARAM_IMAGEFX_SOLARIZE},
102    {"sketch",        MMAL_PARAM_IMAGEFX_SKETCH},
103    {"denoise",       MMAL_PARAM_IMAGEFX_DENOISE},
104    {"emboss",        MMAL_PARAM_IMAGEFX_EMBOSS},
105    {"oilpaint",      MMAL_PARAM_IMAGEFX_OILPAINT},
106    {"hatch",         MMAL_PARAM_IMAGEFX_HATCH},
107    {"gpen",          MMAL_PARAM_IMAGEFX_GPEN},
108    {"pastel",        MMAL_PARAM_IMAGEFX_PASTEL},
109    {"watercolour",   MMAL_PARAM_IMAGEFX_WATERCOLOUR},
110    {"film",          MMAL_PARAM_IMAGEFX_FILM},
111    {"blur",          MMAL_PARAM_IMAGEFX_BLUR},
112    {"saturation",    MMAL_PARAM_IMAGEFX_SATURATION},
113    {"colourswap",    MMAL_PARAM_IMAGEFX_COLOURSWAP},
114    {"washedout",     MMAL_PARAM_IMAGEFX_WASHEDOUT},
115    {"posterise",     MMAL_PARAM_IMAGEFX_POSTERISE},
116    {"colourpoint",   MMAL_PARAM_IMAGEFX_COLOURPOINT},
117    {"colourbalance", MMAL_PARAM_IMAGEFX_COLOURBALANCE},
118    {"cartoon",       MMAL_PARAM_IMAGEFX_CARTOON}
119 };
120 
121 static const int imagefx_map_size = sizeof(imagefx_map) / sizeof(imagefx_map[0]);
122 
123 static XREF_T metering_mode_map[] =
124 {
125    {"average",       MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE},
126    {"spot",          MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT},
127    {"backlit",       MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT},
128    {"matrix",        MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX}
129 };
130 
131 static const int metering_mode_map_size = sizeof(metering_mode_map)/sizeof(metering_mode_map[0]);
132 
133 static XREF_T drc_mode_map[] =
134 {
135    {"off",           MMAL_PARAMETER_DRC_STRENGTH_OFF},
136    {"low",           MMAL_PARAMETER_DRC_STRENGTH_LOW},
137    {"med",           MMAL_PARAMETER_DRC_STRENGTH_MEDIUM},
138    {"high",          MMAL_PARAMETER_DRC_STRENGTH_HIGH}
139 };
140 
141 static const int drc_mode_map_size = sizeof(drc_mode_map)/sizeof(drc_mode_map[0]);
142 
143 static XREF_T stereo_mode_map[] =
144 {
145    {"off",           MMAL_STEREOSCOPIC_MODE_NONE},
146    {"sbs",           MMAL_STEREOSCOPIC_MODE_SIDE_BY_SIDE},
147    {"tb",            MMAL_STEREOSCOPIC_MODE_TOP_BOTTOM},
148 };
149 
150 static const int stereo_mode_map_size = sizeof(stereo_mode_map)/sizeof(stereo_mode_map[0]);
151 
152 enum
153 {
154    CommandSharpness,
155    CommandContrast,
156    CommandBrightness,
157    CommandSaturation,
158    CommandISO,
159    CommandVideoStab,
160    CommandEVComp,
161    CommandExposure,
162    CommandAWB,
163    CommandImageFX,
164    CommandColourFX,
165    CommandMeterMode,
166    CommandRotation,
167    CommandHFlip,
168    CommandVFlip,
169    CommandROI,
170    CommandShutterSpeed,
171    CommandAwbGains,
172    CommandDRCLevel,
173    CommandStatsPass,
174    CommandAnnotate,
175    CommandStereoMode,
176    CommandStereoDecimate,
177    CommandStereoSwap,
178    CommandAnnotateExtras,
179    CommandFlicker,
180    CommandAnalogGain,
181    CommandDigitalGain,
182    CommandSettings
183 };
184 
185 static COMMAND_LIST  cmdline_commands[] =
186 {
187    {CommandSharpness,   "-sharpness", "sh", "Set image sharpness (-100 to 100)",  1},
188    {CommandContrast,    "-contrast",  "co", "Set image contrast (-100 to 100)",  1},
189    {CommandBrightness,  "-brightness","br", "Set image brightness (0 to 100)",  1},
190    {CommandSaturation,  "-saturation","sa", "Set image saturation (-100 to 100)", 1},
191    {CommandISO,         "-ISO",       "ISO","Set capture ISO",  1},
192    {CommandVideoStab,   "-vstab",     "vs", "Turn on video stabilisation", 0},
193    {CommandEVComp,      "-ev",        "ev", "Set EV compensation - steps of 1/6 stop",  1},
194    {CommandExposure,    "-exposure",  "ex", "Set exposure mode (see Notes)", 1},
195    {CommandFlicker,     "-flicker",   "fli","Set flicker avoid mode (see Notes)", 1},
196    {CommandAWB,         "-awb",       "awb","Set AWB mode (see Notes)", 1},
197    {CommandImageFX,     "-imxfx",     "ifx","Set image effect (see Notes)", 1},
198    {CommandColourFX,    "-colfx",     "cfx","Set colour effect (U:V)",  1},
199    {CommandMeterMode,   "-metering",  "mm", "Set metering mode (see Notes)", 1},
200    {CommandRotation,    "-rotation",  "rot","Set image rotation (0-359)", 1},
201    {CommandHFlip,       "-hflip",     "hf", "Set horizontal flip", 0},
202    {CommandVFlip,       "-vflip",     "vf", "Set vertical flip", 0},
203    {CommandROI,         "-roi",       "roi","Set region of interest (x,y,w,d as normalised coordinates [0.0-1.0])", 1},
204    {CommandShutterSpeed,"-shutter",   "ss", "Set shutter speed in microseconds", 1},
205    {CommandAwbGains,    "-awbgains",  "awbg", "Set AWB gains - AWB mode must be off", 1},
206    {CommandDRCLevel,    "-drc",       "drc", "Set DRC Level (see Notes)", 1},
207    {CommandStatsPass,   "-stats",     "st", "Force recomputation of statistics on stills capture pass"},
208    {CommandAnnotate,    "-annotate",  "a",  "Enable/Set annotate flags or text", 1},
209    {CommandStereoMode,  "-stereo",    "3d", "Select stereoscopic mode", 1},
210    {CommandStereoDecimate,"-decimate","dec", "Half width/height of stereo image"},
211    {CommandStereoSwap,  "-3dswap",    "3dswap", "Swap camera order for stereoscopic"},
212    {CommandAnnotateExtras,"-annotateex","ae",  "Set extra annotation parameters (text size, text colour(hex YUV), bg colour(hex YUV), justify, x, y)", 2},
213    {CommandAnalogGain,  "-analoggain", "ag", "Set the analog gain (floating point)", 1},
214    {CommandDigitalGain, "-digitalgain", "dg", "Set the digital gain (floating point)", 1},
215    {CommandSettings,    "-settings",   "set","Retrieve camera settings and write to stdout", 0},
216 };
217 
218 static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
219 
220 #define parameter_reset -99999
221 
222 #define zoom_full_16P16 ((unsigned int)(65536 * 0.15))
223 #define zoom_increment_16P16 (65536UL / 10)
224 
225 /**
226  * Update the passed in parameter according to the rest of the parameters
227  * passed in.
228  *
229  *
230  * @return 0 if reached end of cycle for this parameter, !0 otherwise
231  */
update_cycle_parameter(int * option,int min,int max,int increment)232 static int update_cycle_parameter(int *option, int min, int max, int increment)
233 {
234    vcos_assert(option);
235    if (!option)
236       return 0;
237 
238    if (*option == parameter_reset)
239       *option = min - increment;
240 
241    *option += increment;
242 
243    if (*option > max)
244    {
245       *option = parameter_reset;
246       return 0;
247    }
248    else
249       return 1;
250 }
251 
252 /**
253  * Test/Demo code to cycle through a bunch of camera settings
254  * This code is pretty hacky so please don't complain!!
255  * It only does stuff that should have a visual impact (hence demo!)
256  * This will override any user supplied parameters
257  *
258  * Each call of this function will move on to the next setting
259  *
260  * @param camera Pointer to the camera to change settings on.
261  * @return 0 if reached end of complete sequence, !0 otherwise
262  */
263 
raspicamcontrol_cycle_test(MMAL_COMPONENT_T * camera)264 int raspicamcontrol_cycle_test(MMAL_COMPONENT_T *camera)
265 {
266    static int parameter = 0;
267    static int parameter_option = parameter_reset; // which value the parameter currently has
268 
269    vcos_assert(camera);
270 
271    // We are going to cycle through all the relevant entries in the parameter block
272    // and send options to the camera.
273    if (parameter == 0)
274    {
275       // sharpness
276       if (update_cycle_parameter(&parameter_option, -100, 100, 10))
277          raspicamcontrol_set_sharpness(camera, parameter_option);
278       else
279       {
280          raspicamcontrol_set_sharpness(camera, 0);
281          parameter++;
282       }
283    }
284    else if (parameter == 1)
285    {
286       // contrast
287       if (update_cycle_parameter(&parameter_option, -100, 100, 10))
288          raspicamcontrol_set_contrast(camera, parameter_option);
289       else
290       {
291          raspicamcontrol_set_contrast(camera, 0);
292          parameter++;
293       }
294    }
295    else if (parameter == 2)
296    {
297       // brightness
298       if (update_cycle_parameter(&parameter_option, 0, 100, 10))
299          raspicamcontrol_set_brightness(camera, parameter_option);
300       else
301       {
302          raspicamcontrol_set_brightness(camera, 50);
303          parameter++;
304       }
305    }
306    else if (parameter == 3)
307    {
308       // contrast
309       if (update_cycle_parameter(&parameter_option, -100, 100, 10))
310          raspicamcontrol_set_saturation(camera, parameter_option);
311       else
312       {
313          parameter++;
314          raspicamcontrol_set_saturation(camera, 0);
315       }
316    }
317    else if (parameter == 4)
318    {
319       // EV
320       if (update_cycle_parameter(&parameter_option, -10, 10, 4))
321          raspicamcontrol_set_exposure_compensation(camera, parameter_option);
322       else
323       {
324          raspicamcontrol_set_exposure_compensation(camera, 0);
325          parameter++;
326       }
327    }
328    else if (parameter == 5)
329    {
330       // MMAL_PARAM_EXPOSUREMODE_T
331       if (update_cycle_parameter(&parameter_option, 0, exposure_map_size, 1))
332          raspicamcontrol_set_exposure_mode(camera, exposure_map[parameter_option].mmal_mode);
333       else
334       {
335          raspicamcontrol_set_exposure_mode(camera, MMAL_PARAM_EXPOSUREMODE_AUTO);
336          parameter++;
337       }
338    }
339    else if (parameter == 6)
340    {
341       // MMAL_PARAM_AWB_T
342       if (update_cycle_parameter(&parameter_option, 0, awb_map_size, 1))
343          raspicamcontrol_set_awb_mode(camera, awb_map[parameter_option].mmal_mode);
344       else
345       {
346          raspicamcontrol_set_awb_mode(camera, MMAL_PARAM_AWBMODE_AUTO);
347          parameter++;
348       }
349    }
350    if (parameter == 7)
351    {
352       // MMAL_PARAM_IMAGEFX_T
353       if (update_cycle_parameter(&parameter_option, 0, imagefx_map_size, 1))
354          raspicamcontrol_set_imageFX(camera, imagefx_map[parameter_option].mmal_mode);
355       else
356       {
357          raspicamcontrol_set_imageFX(camera, MMAL_PARAM_IMAGEFX_NONE);
358          parameter++;
359       }
360    }
361    if (parameter == 8)
362    {
363       MMAL_PARAM_COLOURFX_T colfx = {0,0,0};
364       switch (parameter_option)
365       {
366       case parameter_reset :
367          parameter_option = 1;
368          colfx.u = 128;
369          colfx.v = 128;
370          break;
371       case 1 :
372          parameter_option = 2;
373          colfx.u = 100;
374          colfx.v = 200;
375          break;
376       case 2 :
377          parameter_option = parameter_reset;
378          colfx.enable = 0;
379          parameter++;
380          break;
381       }
382       raspicamcontrol_set_colourFX(camera, &colfx);
383    }
384 
385    // Orientation
386    if (parameter == 9)
387    {
388       switch (parameter_option)
389       {
390       case parameter_reset:
391          raspicamcontrol_set_rotation(camera, 90);
392          parameter_option = 1;
393          break;
394 
395       case 1 :
396          raspicamcontrol_set_rotation(camera, 180);
397          parameter_option = 2;
398          break;
399 
400       case 2 :
401          raspicamcontrol_set_rotation(camera, 270);
402          parameter_option = 3;
403          break;
404 
405       case 3 :
406       {
407          raspicamcontrol_set_rotation(camera, 0);
408          raspicamcontrol_set_flips(camera, 1,0);
409          parameter_option = 4;
410          break;
411       }
412       case 4 :
413       {
414          raspicamcontrol_set_flips(camera, 0,1);
415          parameter_option = 5;
416          break;
417       }
418       case 5 :
419       {
420          raspicamcontrol_set_flips(camera, 1, 1);
421          parameter_option = 6;
422          break;
423       }
424       case 6 :
425       {
426          raspicamcontrol_set_flips(camera, 0, 0);
427          parameter_option = parameter_reset;
428          parameter++;
429          break;
430       }
431       }
432    }
433 
434    if (parameter == 10)
435    {
436       parameter = 1;
437       return 0;
438    }
439 
440    return 1;
441 }
442 
443 /**
444  * Convert string to the MMAL parameter for exposure mode
445  * @param str Incoming string to match
446  * @return MMAL parameter matching the string, or the AUTO option if no match found
447  */
exposure_mode_from_string(const char * str)448 static MMAL_PARAM_EXPOSUREMODE_T exposure_mode_from_string(const char *str)
449 {
450    int i = raspicli_map_xref(str, exposure_map, exposure_map_size);
451 
452    if( i != -1)
453       return (MMAL_PARAM_EXPOSUREMODE_T)i;
454 
455    vcos_log_error("Unknown exposure mode: %s", str);
456    return MMAL_PARAM_EXPOSUREMODE_AUTO;
457 }
458 
459 /**
460  * Convert string to the MMAL parameter for flicker avoid mode
461  * @param str Incoming string to match
462  * @return MMAL parameter matching the string, or the AUTO option if no match found
463  */
flicker_avoid_mode_from_string(const char * str)464 static MMAL_PARAM_FLICKERAVOID_T flicker_avoid_mode_from_string(const char *str)
465 {
466    int i = raspicli_map_xref(str, flicker_avoid_map, flicker_avoid_map_size);
467 
468    if( i != -1)
469       return (MMAL_PARAM_FLICKERAVOID_T)i;
470 
471    vcos_log_error("Unknown flicker avoid mode: %s", str);
472    return MMAL_PARAM_FLICKERAVOID_OFF;
473 }
474 
475 /**
476  * Convert string to the MMAL parameter for AWB mode
477  * @param str Incoming string to match
478  * @return MMAL parameter matching the string, or the AUTO option if no match found
479  */
awb_mode_from_string(const char * str)480 static MMAL_PARAM_AWBMODE_T awb_mode_from_string(const char *str)
481 {
482    int i = raspicli_map_xref(str, awb_map, awb_map_size);
483 
484    if( i != -1)
485       return (MMAL_PARAM_AWBMODE_T)i;
486 
487    vcos_log_error("Unknown awb mode: %s", str);
488    return MMAL_PARAM_AWBMODE_AUTO;
489 }
490 
491 /**
492  * Convert string to the MMAL parameter for image effects mode
493  * @param str Incoming string to match
494  * @return MMAL parameter matching the strong, or the AUTO option if no match found
495  */
imagefx_mode_from_string(const char * str)496 MMAL_PARAM_IMAGEFX_T imagefx_mode_from_string(const char *str)
497 {
498    int i = raspicli_map_xref(str, imagefx_map, imagefx_map_size);
499 
500    if( i != -1)
501       return (MMAL_PARAM_IMAGEFX_T)i;
502 
503    vcos_log_error("Unknown image fx: %s", str);
504    return MMAL_PARAM_IMAGEFX_NONE;
505 }
506 
507 /**
508  * Convert string to the MMAL parameter for exposure metering mode
509  * @param str Incoming string to match
510  * @return MMAL parameter matching the string, or the AUTO option if no match found
511  */
metering_mode_from_string(const char * str)512 static MMAL_PARAM_EXPOSUREMETERINGMODE_T metering_mode_from_string(const char *str)
513 {
514    int i = raspicli_map_xref(str, metering_mode_map, metering_mode_map_size);
515 
516    if( i != -1)
517       return (MMAL_PARAM_EXPOSUREMETERINGMODE_T)i;
518 
519    vcos_log_error("Unknown metering mode: %s", str);
520    return MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE;
521 }
522 
523 /**
524  * Convert string to the MMAL parameter for DRC level
525  * @param str Incoming string to match
526  * @return MMAL parameter matching the string, or the AUTO option if no match found
527  */
drc_mode_from_string(const char * str)528 static MMAL_PARAMETER_DRC_STRENGTH_T drc_mode_from_string(const char *str)
529 {
530    int i = raspicli_map_xref(str, drc_mode_map, drc_mode_map_size);
531 
532    if( i != -1)
533       return (MMAL_PARAMETER_DRC_STRENGTH_T)i;
534 
535    vcos_log_error("Unknown DRC level: %s", str);
536    return MMAL_PARAMETER_DRC_STRENGTH_OFF;
537 }
538 
539 /**
540  * Convert string to the MMAL parameter for exposure metering mode
541  * @param str Incoming string to match
542  * @return MMAL parameter matching the string, or the AUTO option if no match found
543  */
stereo_mode_from_string(const char * str)544 static MMAL_STEREOSCOPIC_MODE_T stereo_mode_from_string(const char *str)
545 {
546    int i = raspicli_map_xref(str, stereo_mode_map, stereo_mode_map_size);
547 
548    if( i != -1)
549       return (MMAL_STEREOSCOPIC_MODE_T)i;
550 
551    vcos_log_error("Unknown metering mode: %s", str);
552    return MMAL_STEREOSCOPIC_MODE_NONE;
553 }
554 
555 /**
556  * Parse a possible command pair - command and parameter
557  * @param arg1 Command
558  * @param arg2 Parameter (could be NULL)
559  * @return How many parameters were used, 0,1,2
560  */
raspicamcontrol_parse_cmdline(RASPICAM_CAMERA_PARAMETERS * params,const char * arg1,const char * arg2)561 int raspicamcontrol_parse_cmdline(RASPICAM_CAMERA_PARAMETERS *params, const char *arg1, const char *arg2)
562 {
563    int command_id, used = 0, num_parameters;
564 
565    if (!arg1)
566       return 0;
567 
568    command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, arg1, &num_parameters);
569 
570    // If invalid command, or we are missing a parameter, drop out
571    if (command_id==-1 || (command_id != -1 && num_parameters > 0 && arg2 == NULL))
572       return 0;
573 
574    switch (command_id)
575    {
576    case CommandSharpness : // sharpness - needs single number parameter
577       sscanf(arg2, "%d", &params->sharpness);
578       used = 2;
579       break;
580 
581    case CommandContrast : // contrast - needs single number parameter
582       sscanf(arg2, "%d", &params->contrast);
583       used = 2;
584       break;
585 
586    case CommandBrightness : // brightness - needs single number parameter
587       sscanf(arg2, "%d", &params->brightness);
588       used = 2;
589       break;
590 
591    case CommandSaturation : // saturation - needs single number parameter
592       sscanf(arg2, "%d", &params->saturation);
593       used = 2;
594       break;
595 
596    case CommandISO : // ISO - needs single number parameter
597       sscanf(arg2, "%d", &params->ISO);
598       used = 2;
599       break;
600 
601    case CommandVideoStab : // video stabilisation - if here, its on
602       params->videoStabilisation = 1;
603       used = 1;
604       break;
605 
606    case CommandEVComp : // EV - needs single number parameter
607       sscanf(arg2, "%d", &params->exposureCompensation);
608       used = 2;
609       break;
610 
611    case CommandExposure : // exposure mode - needs string
612       params->exposureMode = exposure_mode_from_string(arg2);
613       used = 2;
614       break;
615 
616    case CommandFlicker : // flicker avoid mode - needs string
617       params->flickerAvoidMode = flicker_avoid_mode_from_string(arg2);
618       used = 2;
619       break;
620 
621    case CommandAWB : // AWB mode - needs single number parameter
622       params->awbMode = awb_mode_from_string(arg2);
623       used = 2;
624       break;
625 
626    case CommandImageFX : // Image FX - needs string
627       params->imageEffect = imagefx_mode_from_string(arg2);
628       used = 2;
629       break;
630 
631    case CommandColourFX : // Colour FX - needs string "u:v"
632       sscanf(arg2, "%d:%d", &params->colourEffects.u, &params->colourEffects.v);
633       params->colourEffects.enable = 1;
634       used = 2;
635       break;
636 
637    case CommandMeterMode:
638       params->exposureMeterMode = metering_mode_from_string(arg2);
639       used = 2;
640       break;
641 
642    case CommandRotation : // Rotation - degree
643       sscanf(arg2, "%d", &params->rotation);
644       used = 2;
645       break;
646 
647    case CommandHFlip :
648       params->hflip  = 1;
649       used = 1;
650       break;
651 
652    case CommandVFlip :
653       params->vflip = 1;
654       used = 1;
655       break;
656 
657    case CommandROI :
658    {
659       double x,y,w,h;
660       int args;
661 
662       args = sscanf(arg2, "%lf,%lf,%lf,%lf", &x,&y,&w,&h);
663 
664       if (args != 4 || x > 1.0 || y > 1.0 || w > 1.0 || h > 1.0)
665       {
666          return 0;
667       }
668 
669       // Make sure we stay within bounds
670       if (x + w > 1.0)
671          w = 1 - x;
672 
673       if (y + h > 1.0)
674          h = 1 - y;
675 
676       params->roi.x = x;
677       params->roi.y = y;
678       params->roi.w = w;
679       params->roi.h = h;
680 
681       used = 2;
682       break;
683    }
684 
685    case CommandShutterSpeed : // Shutter speed needs single number parameter
686    {
687       sscanf(arg2, "%d", &params->shutter_speed);
688       used = 2;
689       break;
690    }
691 
692    case CommandAwbGains :
693    {
694       double r,b;
695       int args;
696 
697       args = sscanf(arg2, "%lf,%lf", &r,&b);
698 
699       if (args != 2 || r > 8.0 || b > 8.0)
700       {
701          return 0;
702       }
703 
704       params->awb_gains_r = r;
705       params->awb_gains_b = b;
706 
707       used = 2;
708       break;
709    }
710 
711    case CommandDRCLevel:
712    {
713       params->drc_level = drc_mode_from_string(arg2);
714       used = 2;
715       break;
716    }
717 
718    case CommandStatsPass:
719    {
720       params->stats_pass = MMAL_TRUE;
721       used = 1;
722       break;
723    }
724 
725    case CommandAnnotate:
726    {
727       char dummy;
728       unsigned int bitmask;
729       // If parameter is a number, assume its a bitmask, otherwise a string
730       if (sscanf(arg2, "%u%c", &bitmask, &dummy) == 1)
731       {
732          params->enable_annotate |= bitmask;
733       }
734       else
735       {
736          params->enable_annotate |= ANNOTATE_USER_TEXT;
737          //copy string char by char and replace "\n" with newline character
738          unsigned char c;
739          char const *s = arg2;
740          char *t = &params->annotate_string[0];
741          int n=0;
742          while ((c = *s++) && n < MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3-1)
743          {
744             if (c == '\\' && *s)
745             {
746                switch (c = *s++)
747                {
748                case 'n':
749                   c = '\n';
750                   break;
751 
752                default:
753                   c = '\\';
754                   s--;
755                   break;
756                }
757             }
758             *(t++) = c;
759             n++;
760          }
761          *t='\0';
762 
763          //params->annotate_string[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3-1] = '\0';
764       }
765       used=2;
766       break;
767    }
768 
769    case CommandAnnotateExtras:
770    {
771       // 3 parameters - text size (6-80), text colour (Hex VVUUYY) and background colour (Hex VVUUYY)
772       sscanf(arg2, "%u,%X,%X,%u,%u,%u", &params->annotate_text_size,
773              &params->annotate_text_colour,
774              &params->annotate_bg_colour,
775              &params->annotate_justify,
776              &params->annotate_x,
777              &params->annotate_y
778             );
779       used=2;
780       break;
781    }
782 
783    case CommandStereoMode:
784    {
785       params->stereo_mode.mode = stereo_mode_from_string(arg2);
786       used = 2;
787       break;
788    }
789 
790    case CommandStereoDecimate:
791    {
792       params->stereo_mode.decimate = MMAL_TRUE;
793       used = 1;
794       break;
795    }
796 
797    case CommandStereoSwap:
798    {
799       params->stereo_mode.swap_eyes = MMAL_TRUE;
800       used = 1;
801       break;
802    }
803 
804    case CommandAnalogGain:
805    {
806       double gain;
807       int args;
808 
809       args = sscanf(arg2, "%lf", &gain);
810 
811       if (args != 1 || gain > 16.0)
812       {
813          return 0;
814       }
815 
816       params->analog_gain = gain;
817 
818       used = 2;
819       break;
820    }
821    case CommandDigitalGain:
822    {
823       double gain;
824       int args;
825 
826       args = sscanf(arg2, "%lf", &gain);
827 
828       if (args != 1 || gain > 64.0)
829       {
830          return 0;
831       }
832 
833       params->digital_gain = gain;
834 
835       used = 2;
836       break;
837    }
838 
839    case CommandSettings:
840    {
841       params->settings = 1;
842       used = 1;
843       break;
844    }
845 
846    }
847 
848    return used;
849 }
850 
851 /**
852  * Display help for command line options
853  */
raspicamcontrol_display_help()854 void raspicamcontrol_display_help()
855 {
856    int i;
857 
858    fprintf(stdout, "\nImage parameter commands\n\n");
859 
860    raspicli_display_help(cmdline_commands, cmdline_commands_size);
861 
862    fprintf(stdout, "\n\nNotes\n\nExposure mode options :\n%s", exposure_map[0].mode );
863 
864    for (i=1; i<exposure_map_size; i++)
865    {
866       fprintf(stdout, ",%s", exposure_map[i].mode);
867    }
868 
869    fprintf(stdout, "\n\nFlicker avoid mode options :\n%s", flicker_avoid_map[0].mode );
870 
871    for (i=1; i<flicker_avoid_map_size; i++)
872    {
873       fprintf(stdout, ",%s", flicker_avoid_map[i].mode);
874    }
875 
876    fprintf(stdout, "\n\nAWB mode options :\n%s", awb_map[0].mode );
877 
878    for (i=1; i<awb_map_size; i++)
879    {
880       fprintf(stdout, ",%s", awb_map[i].mode);
881    }
882 
883    fprintf(stdout, "\n\nImage Effect mode options :\n%s", imagefx_map[0].mode );
884 
885    for (i=1; i<imagefx_map_size; i++)
886    {
887       fprintf(stdout, ",%s", imagefx_map[i].mode);
888    }
889 
890    fprintf(stdout, "\n\nMetering Mode options :\n%s", metering_mode_map[0].mode );
891 
892    for (i=1; i<metering_mode_map_size; i++)
893    {
894       fprintf(stdout, ",%s", metering_mode_map[i].mode);
895    }
896 
897    fprintf(stdout, "\n\nDynamic Range Compression (DRC) options :\n%s", drc_mode_map[0].mode );
898 
899    for (i=1; i<drc_mode_map_size; i++)
900    {
901       fprintf(stdout, ",%s", drc_mode_map[i].mode);
902    }
903 
904    fprintf(stdout, "\n");
905 }
906 
907 /**
908  * Dump contents of camera parameter structure to stderr for debugging/verbose logging
909  *
910  * @param params Const pointer to parameters structure to dump
911  */
raspicamcontrol_dump_parameters(const RASPICAM_CAMERA_PARAMETERS * params)912 void raspicamcontrol_dump_parameters(const RASPICAM_CAMERA_PARAMETERS *params)
913 {
914    const char *exp_mode = raspicli_unmap_xref(params->exposureMode, exposure_map, exposure_map_size);
915    const char *fl_mode = raspicli_unmap_xref(params->flickerAvoidMode, flicker_avoid_map, flicker_avoid_map_size);
916    const char *awb_mode = raspicli_unmap_xref(params->awbMode, awb_map, awb_map_size);
917    const char *image_effect = raspicli_unmap_xref(params->imageEffect, imagefx_map, imagefx_map_size);
918    const char *metering_mode = raspicli_unmap_xref(params->exposureMeterMode, metering_mode_map, metering_mode_map_size);
919 
920    fprintf(stderr, "Sharpness %d, Contrast %d, Brightness %d\n", params->sharpness, params->contrast, params->brightness);
921    fprintf(stderr, "Saturation %d, ISO %d, Video Stabilisation %s, Exposure compensation %d\n", params->saturation, params->ISO, params->videoStabilisation ? "Yes": "No", params->exposureCompensation);
922    fprintf(stderr, "Exposure Mode '%s', AWB Mode '%s', Image Effect '%s'\n", exp_mode, awb_mode, image_effect);
923    fprintf(stderr, "Flicker Avoid Mode '%s'\n", fl_mode);
924    fprintf(stderr, "Metering Mode '%s', Colour Effect Enabled %s with U = %d, V = %d\n", metering_mode, params->colourEffects.enable ? "Yes":"No", params->colourEffects.u, params->colourEffects.v);
925    fprintf(stderr, "Rotation %d, hflip %s, vflip %s\n", params->rotation, params->hflip ? "Yes":"No",params->vflip ? "Yes":"No");
926    fprintf(stderr, "ROI x %lf, y %f, w %f h %f\n", params->roi.x, params->roi.y, params->roi.w, params->roi.h);
927 }
928 
929 /**
930  * Give the supplied parameter block a set of default values
931  * @params Pointer to parameter block
932  */
raspicamcontrol_set_defaults(RASPICAM_CAMERA_PARAMETERS * params)933 void raspicamcontrol_set_defaults(RASPICAM_CAMERA_PARAMETERS *params)
934 {
935    vcos_assert(params);
936 
937    params->sharpness = 0;
938    params->contrast = 0;
939    params->brightness = 50;
940    params->saturation = 0;
941    params->ISO = 0;                    // 0 = auto
942    params->videoStabilisation = 0;
943    params->exposureCompensation = 0;
944    params->exposureMode = MMAL_PARAM_EXPOSUREMODE_AUTO;
945    params->flickerAvoidMode = MMAL_PARAM_FLICKERAVOID_OFF;
946    params->exposureMeterMode = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE;
947    params->awbMode = MMAL_PARAM_AWBMODE_AUTO;
948    params->imageEffect = MMAL_PARAM_IMAGEFX_NONE;
949    params->colourEffects.enable = 0;
950    params->colourEffects.u = 128;
951    params->colourEffects.v = 128;
952    params->rotation = 0;
953    params->hflip = params->vflip = 0;
954    params->roi.x = params->roi.y = 0.0;
955    params->roi.w = params->roi.h = 1.0;
956    params->shutter_speed = 0;          // 0 = auto
957    params->awb_gains_r = 0;      // Only have any function if AWB OFF is used.
958    params->awb_gains_b = 0;
959    params->drc_level = MMAL_PARAMETER_DRC_STRENGTH_OFF;
960    params->stats_pass = MMAL_FALSE;
961    params->enable_annotate = 0;
962    params->annotate_string[0] = '\0';
963    params->annotate_text_size = 0;	//Use firmware default
964    params->annotate_text_colour = -1;   //Use firmware default
965    params->annotate_bg_colour = -1;     //Use firmware default
966    params->stereo_mode.mode = MMAL_STEREOSCOPIC_MODE_NONE;
967    params->stereo_mode.decimate = MMAL_FALSE;
968    params->stereo_mode.swap_eyes = MMAL_FALSE;
969 }
970 
971 /**
972  * Get all the current camera parameters from specified camera component
973  * @param camera Pointer to camera component
974  * @param params Pointer to parameter block to accept settings
975  * @return 0 if successful, non-zero if unsuccessful
976  */
raspicamcontrol_get_all_parameters(MMAL_COMPONENT_T * camera,RASPICAM_CAMERA_PARAMETERS * params)977 int raspicamcontrol_get_all_parameters(MMAL_COMPONENT_T *camera, RASPICAM_CAMERA_PARAMETERS *params)
978 {
979    vcos_assert(camera);
980    vcos_assert(params);
981 
982    if (!camera || !params)
983       return 1;
984 
985    /* TODO : Write these get functions
986       params->sharpness = raspicamcontrol_get_sharpness(camera);
987       params->contrast = raspicamcontrol_get_contrast(camera);
988       params->brightness = raspicamcontrol_get_brightness(camera);
989       params->saturation = raspicamcontrol_get_saturation(camera);
990       params->ISO = raspicamcontrol_get_ISO(camera);
991       params->videoStabilisation = raspicamcontrol_get_video_stabilisation(camera);
992       params->exposureCompensation = raspicamcontrol_get_exposure_compensation(camera);
993       params->exposureMode = raspicamcontrol_get_exposure_mode(camera);
994       params->flickerAvoidMode = raspicamcontrol_get_flicker_avoid_mode(camera);
995       params->awbMode = raspicamcontrol_get_awb_mode(camera);
996       params->imageEffect = raspicamcontrol_get_image_effect(camera);
997       params->colourEffects = raspicamcontrol_get_colour_effect(camera);
998       params->thumbnailConfig = raspicamcontrol_get_thumbnail_config(camera);
999    */
1000    return 0;
1001 }
1002 
1003 /**
1004  * Set the specified camera to all the specified settings
1005  * @param camera Pointer to camera component
1006  * @param params Pointer to parameter block containing parameters
1007  * @return 0 if successful, none-zero if unsuccessful.
1008  */
raspicamcontrol_set_all_parameters(MMAL_COMPONENT_T * camera,const RASPICAM_CAMERA_PARAMETERS * params)1009 int raspicamcontrol_set_all_parameters(MMAL_COMPONENT_T *camera, const RASPICAM_CAMERA_PARAMETERS *params)
1010 {
1011    int result;
1012 
1013    result  = raspicamcontrol_set_saturation(camera, params->saturation);
1014    result += raspicamcontrol_set_sharpness(camera, params->sharpness);
1015    result += raspicamcontrol_set_contrast(camera, params->contrast);
1016    result += raspicamcontrol_set_brightness(camera, params->brightness);
1017    result += raspicamcontrol_set_ISO(camera, params->ISO);
1018    result += raspicamcontrol_set_video_stabilisation(camera, params->videoStabilisation);
1019    result += raspicamcontrol_set_exposure_compensation(camera, params->exposureCompensation);
1020    result += raspicamcontrol_set_exposure_mode(camera, params->exposureMode);
1021    result += raspicamcontrol_set_flicker_avoid_mode(camera, params->flickerAvoidMode);
1022    result += raspicamcontrol_set_metering_mode(camera, params->exposureMeterMode);
1023    result += raspicamcontrol_set_awb_mode(camera, params->awbMode);
1024    result += raspicamcontrol_set_awb_gains(camera, params->awb_gains_r, params->awb_gains_b);
1025    result += raspicamcontrol_set_imageFX(camera, params->imageEffect);
1026    result += raspicamcontrol_set_colourFX(camera, &params->colourEffects);
1027    //result += raspicamcontrol_set_thumbnail_parameters(camera, &params->thumbnailConfig);  TODO Not working for some reason
1028    result += raspicamcontrol_set_rotation(camera, params->rotation);
1029    result += raspicamcontrol_set_flips(camera, params->hflip, params->vflip);
1030    result += raspicamcontrol_set_ROI(camera, params->roi);
1031    result += raspicamcontrol_set_shutter_speed(camera, params->shutter_speed);
1032    result += raspicamcontrol_set_DRC(camera, params->drc_level);
1033    result += raspicamcontrol_set_stats_pass(camera, params->stats_pass);
1034    result += raspicamcontrol_set_annotate(camera, params->enable_annotate, params->annotate_string,
1035                                           params->annotate_text_size,
1036                                           params->annotate_text_colour,
1037                                           params->annotate_bg_colour,
1038                                           params->annotate_justify,
1039                                           params->annotate_x,
1040                                           params->annotate_y);
1041    result += raspicamcontrol_set_gains(camera, params->analog_gain, params->digital_gain);
1042 
1043    if (params->settings)
1044    {
1045       MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T change_event_request =
1046       {
1047          {MMAL_PARAMETER_CHANGE_EVENT_REQUEST, sizeof(MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T)},
1048          MMAL_PARAMETER_CAMERA_SETTINGS, 1
1049       };
1050 
1051       MMAL_STATUS_T status = mmal_port_parameter_set(camera->control, &change_event_request.hdr);
1052       if ( status != MMAL_SUCCESS )
1053       {
1054          vcos_log_error("No camera settings events");
1055       }
1056 
1057       result += status;
1058    }
1059 
1060    return result;
1061 }
1062 
1063 /**
1064  * Adjust the saturation level for images
1065  * @param camera Pointer to camera component
1066  * @param saturation Value to adjust, -100 to 100
1067  * @return 0 if successful, non-zero if any parameters out of range
1068  */
raspicamcontrol_set_saturation(MMAL_COMPONENT_T * camera,int saturation)1069 int raspicamcontrol_set_saturation(MMAL_COMPONENT_T *camera, int saturation)
1070 {
1071    int ret = 0;
1072 
1073    if (!camera)
1074       return 1;
1075 
1076    if (saturation >= -100 && saturation <= 100)
1077    {
1078       MMAL_RATIONAL_T value = {saturation, 100};
1079       ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_SATURATION, value));
1080    }
1081    else
1082    {
1083       vcos_log_error("Invalid saturation value");
1084       ret = 1;
1085    }
1086 
1087    return ret;
1088 }
1089 
1090 /**
1091  * Set the sharpness of the image
1092  * @param camera Pointer to camera component
1093  * @param sharpness Sharpness adjustment -100 to 100
1094  */
raspicamcontrol_set_sharpness(MMAL_COMPONENT_T * camera,int sharpness)1095 int raspicamcontrol_set_sharpness(MMAL_COMPONENT_T *camera, int sharpness)
1096 {
1097    int ret = 0;
1098 
1099    if (!camera)
1100       return 1;
1101 
1102    if (sharpness >= -100 && sharpness <= 100)
1103    {
1104       MMAL_RATIONAL_T value = {sharpness, 100};
1105       ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_SHARPNESS, value));
1106    }
1107    else
1108    {
1109       vcos_log_error("Invalid sharpness value");
1110       ret = 1;
1111    }
1112 
1113    return ret;
1114 }
1115 
1116 /**
1117  * Set the contrast adjustment for the image
1118  * @param camera Pointer to camera component
1119  * @param contrast Contrast adjustment -100 to  100
1120  * @return
1121  */
raspicamcontrol_set_contrast(MMAL_COMPONENT_T * camera,int contrast)1122 int raspicamcontrol_set_contrast(MMAL_COMPONENT_T *camera, int contrast)
1123 {
1124    int ret = 0;
1125 
1126    if (!camera)
1127       return 1;
1128 
1129    if (contrast >= -100 && contrast <= 100)
1130    {
1131       MMAL_RATIONAL_T value = {contrast, 100};
1132       ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_CONTRAST, value));
1133    }
1134    else
1135    {
1136       vcos_log_error("Invalid contrast value");
1137       ret = 1;
1138    }
1139 
1140    return ret;
1141 }
1142 
1143 /**
1144  * Adjust the brightness level for images
1145  * @param camera Pointer to camera component
1146  * @param brightness Value to adjust, 0 to 100
1147  * @return 0 if successful, non-zero if any parameters out of range
1148  */
raspicamcontrol_set_brightness(MMAL_COMPONENT_T * camera,int brightness)1149 int raspicamcontrol_set_brightness(MMAL_COMPONENT_T *camera, int brightness)
1150 {
1151    int ret = 0;
1152 
1153    if (!camera)
1154       return 1;
1155 
1156    if (brightness >= 0 && brightness <= 100)
1157    {
1158       MMAL_RATIONAL_T value = {brightness, 100};
1159       ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_BRIGHTNESS, value));
1160    }
1161    else
1162    {
1163       vcos_log_error("Invalid brightness value");
1164       ret = 1;
1165    }
1166 
1167    return ret;
1168 }
1169 
1170 /**
1171  * Adjust the ISO used for images
1172  * @param camera Pointer to camera component
1173  * @param ISO Value to set TODO :
1174  * @return 0 if successful, non-zero if any parameters out of range
1175  */
raspicamcontrol_set_ISO(MMAL_COMPONENT_T * camera,int ISO)1176 int raspicamcontrol_set_ISO(MMAL_COMPONENT_T *camera, int ISO)
1177 {
1178    if (!camera)
1179       return 1;
1180 
1181    return mmal_status_to_int(mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_ISO, ISO));
1182 }
1183 
1184 /**
1185  * Adjust the metering mode for images
1186  * @param camera Pointer to camera component
1187  * @param saturation Value from following
1188  *   - MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE,
1189  *   - MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT,
1190  *   - MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT,
1191  *   - MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX
1192  * @return 0 if successful, non-zero if any parameters out of range
1193  */
raspicamcontrol_set_metering_mode(MMAL_COMPONENT_T * camera,MMAL_PARAM_EXPOSUREMETERINGMODE_T m_mode)1194 int raspicamcontrol_set_metering_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMETERINGMODE_T m_mode )
1195 {
1196    MMAL_PARAMETER_EXPOSUREMETERINGMODE_T meter_mode = {{MMAL_PARAMETER_EXP_METERING_MODE,sizeof(meter_mode)},
1197       m_mode
1198    };
1199    if (!camera)
1200       return 1;
1201 
1202    return mmal_status_to_int(mmal_port_parameter_set(camera->control, &meter_mode.hdr));
1203 }
1204 
1205 /**
1206  * Set the video stabilisation flag. Only used in video mode
1207  * @param camera Pointer to camera component
1208  * @param saturation Flag 0 off 1 on
1209  * @return 0 if successful, non-zero if any parameters out of range
1210  */
raspicamcontrol_set_video_stabilisation(MMAL_COMPONENT_T * camera,int vstabilisation)1211 int raspicamcontrol_set_video_stabilisation(MMAL_COMPONENT_T *camera, int vstabilisation)
1212 {
1213    if (!camera)
1214       return 1;
1215 
1216    return mmal_status_to_int(mmal_port_parameter_set_boolean(camera->control, MMAL_PARAMETER_VIDEO_STABILISATION, vstabilisation));
1217 }
1218 
1219 /**
1220  * Adjust the exposure compensation for images (EV)
1221  * @param camera Pointer to camera component
1222  * @param exp_comp Value to adjust, -10 to +10
1223  * @return 0 if successful, non-zero if any parameters out of range
1224  */
raspicamcontrol_set_exposure_compensation(MMAL_COMPONENT_T * camera,int exp_comp)1225 int raspicamcontrol_set_exposure_compensation(MMAL_COMPONENT_T *camera, int exp_comp)
1226 {
1227    if (!camera)
1228       return 1;
1229 
1230    return mmal_status_to_int(mmal_port_parameter_set_int32(camera->control, MMAL_PARAMETER_EXPOSURE_COMP, exp_comp));
1231 }
1232 
1233 /**
1234  * Set exposure mode for images
1235  * @param camera Pointer to camera component
1236  * @param mode Exposure mode to set from
1237  *   - MMAL_PARAM_EXPOSUREMODE_OFF,
1238  *   - MMAL_PARAM_EXPOSUREMODE_AUTO,
1239  *   - MMAL_PARAM_EXPOSUREMODE_NIGHT,
1240  *   - MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW,
1241  *   - MMAL_PARAM_EXPOSUREMODE_BACKLIGHT,
1242  *   - MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT,
1243  *   - MMAL_PARAM_EXPOSUREMODE_SPORTS,
1244  *   - MMAL_PARAM_EXPOSUREMODE_SNOW,
1245  *   - MMAL_PARAM_EXPOSUREMODE_BEACH,
1246  *   - MMAL_PARAM_EXPOSUREMODE_VERYLONG,
1247  *   - MMAL_PARAM_EXPOSUREMODE_FIXEDFPS,
1248  *   - MMAL_PARAM_EXPOSUREMODE_ANTISHAKE,
1249  *   - MMAL_PARAM_EXPOSUREMODE_FIREWORKS,
1250  *
1251  * @return 0 if successful, non-zero if any parameters out of range
1252  */
raspicamcontrol_set_exposure_mode(MMAL_COMPONENT_T * camera,MMAL_PARAM_EXPOSUREMODE_T mode)1253 int raspicamcontrol_set_exposure_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMODE_T mode)
1254 {
1255    MMAL_PARAMETER_EXPOSUREMODE_T exp_mode = {{MMAL_PARAMETER_EXPOSURE_MODE,sizeof(exp_mode)}, mode};
1256 
1257    if (!camera)
1258       return 1;
1259 
1260    return mmal_status_to_int(mmal_port_parameter_set(camera->control, &exp_mode.hdr));
1261 }
1262 
1263 /**
1264  * Set flicker avoid mode for images
1265  * @param camera Pointer to camera component
1266  * @param mode Exposure mode to set from
1267  *   - MMAL_PARAM_FLICKERAVOID_OFF,
1268  *   - MMAL_PARAM_FLICKERAVOID_AUTO,
1269  *   - MMAL_PARAM_FLICKERAVOID_50HZ,
1270  *   - MMAL_PARAM_FLICKERAVOID_60HZ,
1271  *
1272  * @return 0 if successful, non-zero if any parameters out of range
1273  */
raspicamcontrol_set_flicker_avoid_mode(MMAL_COMPONENT_T * camera,MMAL_PARAM_FLICKERAVOID_T mode)1274 int raspicamcontrol_set_flicker_avoid_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_FLICKERAVOID_T mode)
1275 {
1276    MMAL_PARAMETER_FLICKERAVOID_T fl_mode = {{MMAL_PARAMETER_FLICKER_AVOID,sizeof(fl_mode)}, mode};
1277 
1278    if (!camera)
1279       return 1;
1280 
1281    return mmal_status_to_int(mmal_port_parameter_set(camera->control, &fl_mode.hdr));
1282 }
1283 
1284 /**
1285  * Set the aWB (auto white balance) mode for images
1286  * @param camera Pointer to camera component
1287  * @param awb_mode Value to set from
1288  *   - MMAL_PARAM_AWBMODE_OFF,
1289  *   - MMAL_PARAM_AWBMODE_AUTO,
1290  *   - MMAL_PARAM_AWBMODE_SUNLIGHT,
1291  *   - MMAL_PARAM_AWBMODE_CLOUDY,
1292  *   - MMAL_PARAM_AWBMODE_SHADE,
1293  *   - MMAL_PARAM_AWBMODE_TUNGSTEN,
1294  *   - MMAL_PARAM_AWBMODE_FLUORESCENT,
1295  *   - MMAL_PARAM_AWBMODE_INCANDESCENT,
1296  *   - MMAL_PARAM_AWBMODE_FLASH,
1297  *   - MMAL_PARAM_AWBMODE_HORIZON,
1298  * @return 0 if successful, non-zero if any parameters out of range
1299  */
raspicamcontrol_set_awb_mode(MMAL_COMPONENT_T * camera,MMAL_PARAM_AWBMODE_T awb_mode)1300 int raspicamcontrol_set_awb_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_AWBMODE_T awb_mode)
1301 {
1302    MMAL_PARAMETER_AWBMODE_T param = {{MMAL_PARAMETER_AWB_MODE,sizeof(param)}, awb_mode};
1303 
1304    if (!camera)
1305       return 1;
1306 
1307    return mmal_status_to_int(mmal_port_parameter_set(camera->control, &param.hdr));
1308 }
1309 
raspicamcontrol_set_awb_gains(MMAL_COMPONENT_T * camera,float r_gain,float b_gain)1310 int raspicamcontrol_set_awb_gains(MMAL_COMPONENT_T *camera, float r_gain, float b_gain)
1311 {
1312    MMAL_PARAMETER_AWB_GAINS_T param = {{MMAL_PARAMETER_CUSTOM_AWB_GAINS,sizeof(param)}, {0,0}, {0,0}};
1313 
1314    if (!camera)
1315       return 1;
1316 
1317    if (!r_gain || !b_gain)
1318       return 0;
1319 
1320    param.r_gain.num = (unsigned int)(r_gain * 65536);
1321    param.b_gain.num = (unsigned int)(b_gain * 65536);
1322    param.r_gain.den = param.b_gain.den = 65536;
1323    return mmal_status_to_int(mmal_port_parameter_set(camera->control, &param.hdr));
1324 }
1325 
1326 /**
1327  * Set the image effect for the images
1328  * @param camera Pointer to camera component
1329  * @param imageFX Value from
1330  *   - MMAL_PARAM_IMAGEFX_NONE,
1331  *   - MMAL_PARAM_IMAGEFX_NEGATIVE,
1332  *   - MMAL_PARAM_IMAGEFX_SOLARIZE,
1333  *   - MMAL_PARAM_IMAGEFX_POSTERIZE,
1334  *   - MMAL_PARAM_IMAGEFX_WHITEBOARD,
1335  *   - MMAL_PARAM_IMAGEFX_BLACKBOARD,
1336  *   - MMAL_PARAM_IMAGEFX_SKETCH,
1337  *   - MMAL_PARAM_IMAGEFX_DENOISE,
1338  *   - MMAL_PARAM_IMAGEFX_EMBOSS,
1339  *   - MMAL_PARAM_IMAGEFX_OILPAINT,
1340  *   - MMAL_PARAM_IMAGEFX_HATCH,
1341  *   - MMAL_PARAM_IMAGEFX_GPEN,
1342  *   - MMAL_PARAM_IMAGEFX_PASTEL,
1343  *   - MMAL_PARAM_IMAGEFX_WATERCOLOUR,
1344  *   - MMAL_PARAM_IMAGEFX_FILM,
1345  *   - MMAL_PARAM_IMAGEFX_BLUR,
1346  *   - MMAL_PARAM_IMAGEFX_SATURATION,
1347  *   - MMAL_PARAM_IMAGEFX_COLOURSWAP,
1348  *   - MMAL_PARAM_IMAGEFX_WASHEDOUT,
1349  *   - MMAL_PARAM_IMAGEFX_POSTERISE,
1350  *   - MMAL_PARAM_IMAGEFX_COLOURPOINT,
1351  *   - MMAL_PARAM_IMAGEFX_COLOURBALANCE,
1352  *   - MMAL_PARAM_IMAGEFX_CARTOON,
1353  * @return 0 if successful, non-zero if any parameters out of range
1354  */
raspicamcontrol_set_imageFX(MMAL_COMPONENT_T * camera,MMAL_PARAM_IMAGEFX_T imageFX)1355 int raspicamcontrol_set_imageFX(MMAL_COMPONENT_T *camera, MMAL_PARAM_IMAGEFX_T imageFX)
1356 {
1357    MMAL_PARAMETER_IMAGEFX_T imgFX = {{MMAL_PARAMETER_IMAGE_EFFECT,sizeof(imgFX)}, imageFX};
1358 
1359    if (!camera)
1360       return 1;
1361 
1362    return mmal_status_to_int(mmal_port_parameter_set(camera->control, &imgFX.hdr));
1363 }
1364 
1365 /* TODO :what to do with the image effects parameters?
1366    MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = {{MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,sizeof(imfx_param)},
1367                               imageFX, 0, {0}};
1368 mmal_port_parameter_set(camera->control, &imfx_param.hdr);
1369                              */
1370 
1371 /**
1372  * Set the colour effect  for images (Set UV component)
1373  * @param camera Pointer to camera component
1374  * @param colourFX  Contains enable state and U and V numbers to set (e.g. 128,128 = Black and white)
1375  * @return 0 if successful, non-zero if any parameters out of range
1376  */
raspicamcontrol_set_colourFX(MMAL_COMPONENT_T * camera,const MMAL_PARAM_COLOURFX_T * colourFX)1377 int raspicamcontrol_set_colourFX(MMAL_COMPONENT_T *camera, const MMAL_PARAM_COLOURFX_T *colourFX)
1378 {
1379    MMAL_PARAMETER_COLOURFX_T colfx = {{MMAL_PARAMETER_COLOUR_EFFECT,sizeof(colfx)}, 0, 0, 0};
1380 
1381    if (!camera)
1382       return 1;
1383 
1384    colfx.enable = colourFX->enable;
1385    colfx.u = colourFX->u;
1386    colfx.v = colourFX->v;
1387 
1388    return mmal_status_to_int(mmal_port_parameter_set(camera->control, &colfx.hdr));
1389 
1390 }
1391 
1392 /**
1393  * Set the rotation of the image
1394  * @param camera Pointer to camera component
1395  * @param rotation Degree of rotation (any number, but will be converted to 0,90,180 or 270 only)
1396  * @return 0 if successful, non-zero if any parameters out of range
1397  */
raspicamcontrol_set_rotation(MMAL_COMPONENT_T * camera,int rotation)1398 int raspicamcontrol_set_rotation(MMAL_COMPONENT_T *camera, int rotation)
1399 {
1400    int ret;
1401    int my_rotation = ((rotation % 360 ) / 90) * 90;
1402 
1403    ret = mmal_port_parameter_set_int32(camera->output[0], MMAL_PARAMETER_ROTATION, my_rotation);
1404    mmal_port_parameter_set_int32(camera->output[1], MMAL_PARAMETER_ROTATION, my_rotation);
1405    mmal_port_parameter_set_int32(camera->output[2], MMAL_PARAMETER_ROTATION, my_rotation);
1406 
1407    return mmal_status_to_int(ret);
1408 }
1409 
1410 /**
1411  * Set the flips state of the image
1412  * @param camera Pointer to camera component
1413  * @param hflip If true, horizontally flip the image
1414  * @param vflip If true, vertically flip the image
1415  *
1416  * @return 0 if successful, non-zero if any parameters out of range
1417  */
raspicamcontrol_set_flips(MMAL_COMPONENT_T * camera,int hflip,int vflip)1418 int raspicamcontrol_set_flips(MMAL_COMPONENT_T *camera, int hflip, int vflip)
1419 {
1420    MMAL_PARAMETER_MIRROR_T mirror = {{MMAL_PARAMETER_MIRROR, sizeof(MMAL_PARAMETER_MIRROR_T)}, MMAL_PARAM_MIRROR_NONE};
1421 
1422    if (hflip && vflip)
1423       mirror.value = MMAL_PARAM_MIRROR_BOTH;
1424    else if (hflip)
1425       mirror.value = MMAL_PARAM_MIRROR_HORIZONTAL;
1426    else if (vflip)
1427       mirror.value = MMAL_PARAM_MIRROR_VERTICAL;
1428 
1429    mmal_port_parameter_set(camera->output[0], &mirror.hdr);
1430    mmal_port_parameter_set(camera->output[1], &mirror.hdr);
1431    return mmal_status_to_int(mmal_port_parameter_set(camera->output[2], &mirror.hdr));
1432 }
1433 
1434 /**
1435  * Set the ROI of the sensor to use for captures/preview
1436  * @param camera Pointer to camera component
1437  * @param rect   Normalised coordinates of ROI rectangle
1438  *
1439  * @return 0 if successful, non-zero if any parameters out of range
1440  */
raspicamcontrol_set_ROI(MMAL_COMPONENT_T * camera,PARAM_FLOAT_RECT_T rect)1441 int raspicamcontrol_set_ROI(MMAL_COMPONENT_T *camera, PARAM_FLOAT_RECT_T rect)
1442 {
1443    MMAL_PARAMETER_INPUT_CROP_T crop = {{MMAL_PARAMETER_INPUT_CROP, sizeof(MMAL_PARAMETER_INPUT_CROP_T)}};
1444 
1445    crop.rect.x = (65536 * rect.x);
1446    crop.rect.y = (65536 * rect.y);
1447    crop.rect.width = (65536 * rect.w);
1448    crop.rect.height = (65536 * rect.h);
1449 
1450    return mmal_status_to_int(mmal_port_parameter_set(camera->control, &crop.hdr));
1451 }
1452 
1453 /**
1454  * Zoom in and Zoom out by changing ROI
1455  * @param camera Pointer to camera component
1456  * @param zoom_command zoom command enum
1457  * @return 0 if successful, non-zero otherwise
1458  */
raspicamcontrol_zoom_in_zoom_out(MMAL_COMPONENT_T * camera,ZOOM_COMMAND_T zoom_command,PARAM_FLOAT_RECT_T * roi)1459 int raspicamcontrol_zoom_in_zoom_out(MMAL_COMPONENT_T *camera, ZOOM_COMMAND_T zoom_command, PARAM_FLOAT_RECT_T *roi)
1460 {
1461    MMAL_PARAMETER_INPUT_CROP_T crop;
1462    crop.hdr.id = MMAL_PARAMETER_INPUT_CROP;
1463    crop.hdr.size = sizeof(crop);
1464 
1465    if (mmal_port_parameter_get(camera->control, &crop.hdr) != MMAL_SUCCESS)
1466    {
1467       vcos_log_error("mmal_port_parameter_get(camera->control, &crop.hdr) failed, skip it");
1468       return 0;
1469    }
1470 
1471    if (zoom_command == ZOOM_IN)
1472    {
1473       if (crop.rect.width <= (zoom_full_16P16 + zoom_increment_16P16))
1474       {
1475          crop.rect.width = zoom_full_16P16;
1476          crop.rect.height = zoom_full_16P16;
1477       }
1478       else
1479       {
1480          crop.rect.width -= zoom_increment_16P16;
1481          crop.rect.height -= zoom_increment_16P16;
1482       }
1483    }
1484    else if (zoom_command == ZOOM_OUT)
1485    {
1486       unsigned int increased_size = crop.rect.width + zoom_increment_16P16;
1487       if (increased_size < crop.rect.width) //overflow
1488       {
1489          crop.rect.width = 65536;
1490          crop.rect.height = 65536;
1491       }
1492       else
1493       {
1494          crop.rect.width = increased_size;
1495          crop.rect.height = increased_size;
1496       }
1497    }
1498 
1499    if (zoom_command == ZOOM_RESET)
1500    {
1501       crop.rect.x = 0;
1502       crop.rect.y = 0;
1503       crop.rect.width = 65536;
1504       crop.rect.height = 65536;
1505    }
1506    else
1507    {
1508       unsigned int centered_top_coordinate = (65536 - crop.rect.width) / 2;
1509       crop.rect.x = centered_top_coordinate;
1510       crop.rect.y = centered_top_coordinate;
1511    }
1512 
1513    int ret = mmal_status_to_int(mmal_port_parameter_set(camera->control, &crop.hdr));
1514 
1515    if (ret == 0)
1516    {
1517       roi->x = roi->y = (double)crop.rect.x/65536;
1518       roi->w = roi->h = (double)crop.rect.width/65536;
1519    }
1520    else
1521    {
1522       vcos_log_error("Failed to set crop values, x/y: %u, w/h: %u", crop.rect.x, crop.rect.width);
1523       ret = 1;
1524    }
1525 
1526    return ret;
1527 }
1528 
1529 /**
1530  * Adjust the exposure time used for images
1531  * @param camera Pointer to camera component
1532  * @param shutter speed in microseconds
1533  * @return 0 if successful, non-zero if any parameters out of range
1534  */
raspicamcontrol_set_shutter_speed(MMAL_COMPONENT_T * camera,int speed)1535 int raspicamcontrol_set_shutter_speed(MMAL_COMPONENT_T *camera, int speed)
1536 {
1537    if (!camera)
1538       return 1;
1539 
1540    return mmal_status_to_int(mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_SHUTTER_SPEED, speed));
1541 }
1542 
1543 /**
1544  * Adjust the Dynamic range compression level
1545  * @param camera Pointer to camera component
1546  * @param strength Strength of DRC to apply
1547  *        MMAL_PARAMETER_DRC_STRENGTH_OFF
1548  *        MMAL_PARAMETER_DRC_STRENGTH_LOW
1549  *        MMAL_PARAMETER_DRC_STRENGTH_MEDIUM
1550  *        MMAL_PARAMETER_DRC_STRENGTH_HIGH
1551  *
1552  * @return 0 if successful, non-zero if any parameters out of range
1553  */
raspicamcontrol_set_DRC(MMAL_COMPONENT_T * camera,MMAL_PARAMETER_DRC_STRENGTH_T strength)1554 int raspicamcontrol_set_DRC(MMAL_COMPONENT_T *camera, MMAL_PARAMETER_DRC_STRENGTH_T strength)
1555 {
1556    MMAL_PARAMETER_DRC_T drc = {{MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, sizeof(MMAL_PARAMETER_DRC_T)}, strength};
1557 
1558    if (!camera)
1559       return 1;
1560 
1561    return mmal_status_to_int(mmal_port_parameter_set(camera->control, &drc.hdr));
1562 }
1563 
raspicamcontrol_set_stats_pass(MMAL_COMPONENT_T * camera,int stats_pass)1564 int raspicamcontrol_set_stats_pass(MMAL_COMPONENT_T *camera, int stats_pass)
1565 {
1566    if (!camera)
1567       return 1;
1568 
1569    return mmal_status_to_int(mmal_port_parameter_set_boolean(camera->control, MMAL_PARAMETER_CAPTURE_STATS_PASS, stats_pass));
1570 }
1571 
1572 /**
1573  * Set the annotate data
1574  * @param camera Pointer to camera component
1575  * @param Bitmask of required annotation data. 0 for off.
1576  * @param If set, a pointer to text string to use instead of bitmask, max length 32 characters
1577  *
1578  * @return 0 if successful, non-zero if any parameters out of range
1579  */
raspicamcontrol_set_annotate(MMAL_COMPONENT_T * camera,const int settings,const char * string,const int text_size,const int text_colour,const int bg_colour,const unsigned int justify,const unsigned int x,const unsigned int y)1580 int raspicamcontrol_set_annotate(MMAL_COMPONENT_T *camera, const int settings, const char *string,
1581                                  const int text_size, const int text_colour, const int bg_colour,
1582                                  const unsigned int justify, const unsigned int x, const unsigned int y)
1583 {
1584    MMAL_PARAMETER_CAMERA_ANNOTATE_V4_T annotate =
1585    {{MMAL_PARAMETER_ANNOTATE, sizeof(MMAL_PARAMETER_CAMERA_ANNOTATE_V4_T)}};
1586 
1587    if (settings)
1588    {
1589       time_t t = time(NULL);
1590       struct tm tm = *localtime(&t);
1591       char tmp[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V4];
1592       int process_datetime = 1;
1593 
1594       annotate.enable = 1;
1595 
1596       if (settings & (ANNOTATE_APP_TEXT | ANNOTATE_USER_TEXT))
1597       {
1598          if ((settings & (ANNOTATE_TIME_TEXT | ANNOTATE_DATE_TEXT)) && strchr(string,'%') != NULL)
1599          {
1600             //string contains strftime parameter?
1601             strftime(annotate.text, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3, string, &tm );
1602             process_datetime = 0;
1603          }
1604          else
1605          {
1606             strncpy(annotate.text, string, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3);
1607          }
1608          annotate.text[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3-1] = '\0';
1609       }
1610 
1611       if (process_datetime && (settings & ANNOTATE_TIME_TEXT))
1612       {
1613          if(strlen(annotate.text))
1614          {
1615             strftime(tmp, 32, " %X", &tm );
1616          }
1617          else
1618          {
1619             strftime(tmp, 32, "%X", &tm );
1620          }
1621          strncat(annotate.text, tmp, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3 - strlen(annotate.text) - 1);
1622       }
1623 
1624       if (process_datetime && (settings & ANNOTATE_DATE_TEXT))
1625       {
1626          if(strlen(annotate.text))
1627          {
1628             strftime(tmp, 32, " %x", &tm );
1629          }
1630          else
1631          {
1632             strftime(tmp, 32, "%x", &tm );
1633          }
1634          strncat(annotate.text, tmp, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3 - strlen(annotate.text) - 1);
1635       }
1636 
1637       if (settings & ANNOTATE_SHUTTER_SETTINGS)
1638          annotate.show_shutter = MMAL_TRUE;
1639 
1640       if (settings & ANNOTATE_GAIN_SETTINGS)
1641          annotate.show_analog_gain = MMAL_TRUE;
1642 
1643       if (settings & ANNOTATE_LENS_SETTINGS)
1644          annotate.show_lens = MMAL_TRUE;
1645 
1646       if (settings & ANNOTATE_CAF_SETTINGS)
1647          annotate.show_caf = MMAL_TRUE;
1648 
1649       if (settings & ANNOTATE_MOTION_SETTINGS)
1650          annotate.show_motion = MMAL_TRUE;
1651 
1652       if (settings & ANNOTATE_FRAME_NUMBER)
1653          annotate.show_frame_num = MMAL_TRUE;
1654 
1655       if (settings & ANNOTATE_BLACK_BACKGROUND)
1656          annotate.enable_text_background = MMAL_TRUE;
1657 
1658       annotate.text_size = text_size;
1659 
1660       if (text_colour != -1)
1661       {
1662          annotate.custom_text_colour = MMAL_TRUE;
1663          annotate.custom_text_Y = text_colour&0xff;
1664          annotate.custom_text_U = (text_colour>>8)&0xff;
1665          annotate.custom_text_V = (text_colour>>16)&0xff;
1666       }
1667       else
1668          annotate.custom_text_colour = MMAL_FALSE;
1669 
1670       if (bg_colour != -1)
1671       {
1672          annotate.custom_background_colour = MMAL_TRUE;
1673          annotate.custom_background_Y = bg_colour&0xff;
1674          annotate.custom_background_U = (bg_colour>>8)&0xff;
1675          annotate.custom_background_V = (bg_colour>>16)&0xff;
1676       }
1677       else
1678          annotate.custom_background_colour = MMAL_FALSE;
1679 
1680       annotate.justify = justify;
1681       annotate.x_offset = x;
1682       annotate.y_offset = y;
1683    }
1684    else
1685       annotate.enable = 0;
1686 
1687    return mmal_status_to_int(mmal_port_parameter_set(camera->control, &annotate.hdr));
1688 }
1689 
raspicamcontrol_set_stereo_mode(MMAL_PORT_T * port,MMAL_PARAMETER_STEREOSCOPIC_MODE_T * stereo_mode)1690 int raspicamcontrol_set_stereo_mode(MMAL_PORT_T *port, MMAL_PARAMETER_STEREOSCOPIC_MODE_T *stereo_mode)
1691 {
1692    MMAL_PARAMETER_STEREOSCOPIC_MODE_T stereo = { {MMAL_PARAMETER_STEREOSCOPIC_MODE, sizeof(stereo)},
1693       MMAL_STEREOSCOPIC_MODE_NONE, MMAL_FALSE, MMAL_FALSE
1694    };
1695    if (stereo_mode->mode != MMAL_STEREOSCOPIC_MODE_NONE)
1696    {
1697       stereo.mode = stereo_mode->mode;
1698       stereo.decimate = stereo_mode->decimate;
1699       stereo.swap_eyes = stereo_mode->swap_eyes;
1700    }
1701    return mmal_status_to_int(mmal_port_parameter_set(port, &stereo.hdr));
1702 }
1703 
raspicamcontrol_set_gains(MMAL_COMPONENT_T * camera,float analog,float digital)1704 int raspicamcontrol_set_gains(MMAL_COMPONENT_T *camera, float analog, float digital)
1705 {
1706    MMAL_RATIONAL_T rational = {0,65536};
1707    MMAL_STATUS_T status;
1708 
1709    if (!camera)
1710       return 1;
1711 
1712    rational.num = (unsigned int)(analog * 65536);
1713    status = mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_ANALOG_GAIN, rational);
1714    if (status != MMAL_SUCCESS)
1715       return mmal_status_to_int(status);
1716 
1717    rational.num = (unsigned int)(digital * 65536);
1718    status = mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_DIGITAL_GAIN, rational);
1719    return mmal_status_to_int(status);
1720 }
1721 
1722 /**
1723  * Asked GPU how much memory it has allocated
1724  *
1725  * @return amount of memory in MB
1726  */
raspicamcontrol_get_mem_gpu(void)1727 static int raspicamcontrol_get_mem_gpu(void)
1728 {
1729    char response[80] = "";
1730    int gpu_mem = 0;
1731    if (vc_gencmd(response, sizeof response, "get_mem gpu") == 0)
1732       vc_gencmd_number_property(response, "gpu", &gpu_mem);
1733    return gpu_mem;
1734 }
1735 
1736 /**
1737  * Ask GPU about its camera abilities
1738  * @param supported None-zero if software supports the camera
1739  * @param detected  None-zero if a camera has been detected
1740  */
raspicamcontrol_get_camera(int * supported,int * detected)1741 static void raspicamcontrol_get_camera(int *supported, int *detected)
1742 {
1743    char response[80] = "";
1744    if (vc_gencmd(response, sizeof response, "get_camera") == 0)
1745    {
1746       if (supported)
1747          vc_gencmd_number_property(response, "supported", supported);
1748       if (detected)
1749          vc_gencmd_number_property(response, "detected", detected);
1750    }
1751 }
1752 
1753 /**
1754  * Check to see if camera is supported, and we have allocated enough memory
1755  * Ask GPU about its camera abilities
1756  * @param supported None-zero if software supports the camera
1757  * @param detected  None-zero if a camera has been detected
1758  */
raspicamcontrol_check_configuration(int min_gpu_mem)1759 void raspicamcontrol_check_configuration(int min_gpu_mem)
1760 {
1761    int gpu_mem = raspicamcontrol_get_mem_gpu();
1762    int supported = 0, detected = 0;
1763    raspicamcontrol_get_camera(&supported, &detected);
1764    if (!supported)
1765       vcos_log_error("Camera is not enabled in this build. Try running \"sudo raspi-config\" and ensure that \"camera\" has been enabled\n");
1766    else if (gpu_mem < min_gpu_mem)
1767       vcos_log_error("Only %dM of gpu_mem is configured. Try running \"sudo raspi-config\" and ensure that \"memory_split\" has a value of %d or greater\n", gpu_mem, min_gpu_mem);
1768    else if (!detected)
1769       vcos_log_error("Camera is not detected. Please check carefully the camera module is installed correctly\n");
1770    else
1771       vcos_log_error("Failed to run camera app. Please check for firmware updates\n");
1772 }
1773 
1774 /** Default camera callback function
1775  * Handles the --settings
1776  * @param port
1777  * @param Callback data
1778  */
default_camera_control_callback(MMAL_PORT_T * port,MMAL_BUFFER_HEADER_T * buffer)1779 void default_camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
1780 {
1781    fprintf(stderr, "Camera control callback  cmd=0x%08x", buffer->cmd);
1782 
1783    if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED)
1784    {
1785       MMAL_EVENT_PARAMETER_CHANGED_T *param = (MMAL_EVENT_PARAMETER_CHANGED_T *)buffer->data;
1786       switch (param->hdr.id)
1787       {
1788       case MMAL_PARAMETER_CAMERA_SETTINGS:
1789       {
1790          MMAL_PARAMETER_CAMERA_SETTINGS_T *settings = (MMAL_PARAMETER_CAMERA_SETTINGS_T*)param;
1791          vcos_log_error("Exposure now %u, analog gain %u/%u, digital gain %u/%u",
1792                         settings->exposure,
1793                         settings->analog_gain.num, settings->analog_gain.den,
1794                         settings->digital_gain.num, settings->digital_gain.den);
1795          vcos_log_error("AWB R=%u/%u, B=%u/%u",
1796                         settings->awb_red_gain.num, settings->awb_red_gain.den,
1797                         settings->awb_blue_gain.num, settings->awb_blue_gain.den);
1798       }
1799       break;
1800       }
1801    }
1802    else if (buffer->cmd == MMAL_EVENT_ERROR)
1803    {
1804       vcos_log_error("No data received from sensor. Check all connections, including the Sunny one on the camera board");
1805    }
1806    else
1807    {
1808       vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd);
1809    }
1810 
1811    mmal_buffer_header_release(buffer);
1812 }
1813