rpicamsrc: RaspiCapture: handle MMAL_EVENT_ERROR
[platform/upstream/gstreamer.git] / sys / rpicamsrc / RaspiCapture.c
1 /*
2  * Copyright (c) 2013-2016 Jan Schmidt <jan@centricular.com>
3 Portions:
4 Copyright (c) 2013, Broadcom Europe Ltd
5 Copyright (c) 2013, James Hughes
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10     * Redistributions of source code must retain the above copyright
11       notice, this list of conditions and the following disclaimer.
12     * Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in the
14       documentation and/or other materials provided with the distribution.
15     * Neither the name of the copyright holder nor the
16       names of its contributors may be used to endorse or promote products
17       derived from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /**
32  * \file RaspiCapture.c
33  *
34  * Modification of the RaspiVid command line capture program for GStreamer
35  * use.
36  *
37  * \date 28th Feb 2013, 11 Oct 2013, 5 Mar 2015
38  * \Author: James Hughes, Jan Schmidt
39  *
40  * Description
41  *
42  * 3 components are created; camera, preview and video encoder.
43  * Camera component has three ports, preview, video and stills.
44  * This program connects preview and stills to the preview and video
45  * encoder. Using mmal we don't need to worry about buffers between these
46  * components, but we do need to handle buffers from the encoder, which
47  * are simply written straight to the file in the requisite buffer callback.
48  *
49  * We use the RaspiCamControl code to handle the specific camera settings.
50  * We use the RaspiPreview code to handle the (generic) preview window
51  */
52
53 // We use some GNU extensions (basename, asprintf)
54 #define _GNU_SOURCE
55
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <memory.h>
60 #include <sysexits.h>
61
62 #include <gst/gst.h>
63
64 #include "bcm_host.h"
65 #include "interface/vcos/vcos.h"
66
67 #include "interface/mmal/mmal.h"
68 #include "interface/mmal/mmal_logging.h"
69 #include "interface/mmal/mmal_buffer.h"
70 #include "interface/mmal/util/mmal_util.h"
71 #include "interface/mmal/util/mmal_util_params.h"
72 #include "interface/mmal/util/mmal_default_components.h"
73 #include "interface/mmal/util/mmal_connection.h"
74
75 #include "RaspiCapture.h"
76 #include "RaspiCamControl.h"
77 #include "RaspiPreview.h"
78 #include "RaspiCLI.h"
79
80 #include <semaphore.h>
81
82 // Standard port setting for the camera component
83 #define MMAL_CAMERA_PREVIEW_PORT 0
84 #define MMAL_CAMERA_VIDEO_PORT 1
85 #define MMAL_CAMERA_CAPTURE_PORT 2
86
87 // Video format information
88 // 0 implies variable
89 #define VIDEO_FRAME_RATE_NUM 30
90 #define VIDEO_FRAME_RATE_DEN 1
91
92 /// Video render needs at least 2 buffers.
93 #define VIDEO_OUTPUT_BUFFERS_NUM 3
94
95 // Max bitrate we allow for recording
96 const int MAX_BITRATE = 25000000; // 25Mbits/s
97
98 /// Interval at which we check for an failure abort during capture
99 const int ABORT_INTERVAL = 100; // ms
100
101
102 int mmal_status_to_int(MMAL_STATUS_T status);
103
104 /** Struct used to pass information in encoder port userdata to callback
105  */
106 typedef struct
107 {
108    RASPIVID_STATE *state; /// pointer to our state in case required in callback
109    int abort;             /// Set to 1 in callback if an error occurs to attempt to abort the capture
110 } PORT_USERDATA;
111
112 struct RASPIVID_STATE_T
113 {
114    RASPIVID_CONFIG config;
115
116    FILE *output_file;
117
118    MMAL_COMPONENT_T *camera_component;    /// Pointer to the camera component
119    MMAL_COMPONENT_T *encoder_component;   /// Pointer to the encoder component
120    MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera to preview
121    MMAL_CONNECTION_T *encoder_connection; /// Pointer to the connection from camera to encoder
122
123    MMAL_PORT_T *camera_video_port;
124    MMAL_PORT_T *camera_still_port;
125    MMAL_PORT_T *encoder_output_port;
126
127    MMAL_POOL_T *encoder_pool; /// Pointer to the pool of buffers used by encoder output port
128
129    PORT_USERDATA callback_data;
130
131    MMAL_QUEUE_T *encoded_buffer_q;
132
133    int64_t base_time;
134    int64_t last_second;
135
136    RASPIPREVIEW_STATE preview_state;
137 };
138
139
140 /// Structure to cross reference H264 profile strings against the MMAL parameter equivalent
141 static XREF_T  profile_map[] =
142 {
143    {"baseline",     MMAL_VIDEO_PROFILE_H264_BASELINE},
144    {"main",         MMAL_VIDEO_PROFILE_H264_MAIN},
145    {"high",         MMAL_VIDEO_PROFILE_H264_HIGH},
146 //   {"constrained",  MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE} // Does anyone need this?
147 };
148
149 static int profile_map_size = sizeof(profile_map) / sizeof(profile_map[0]);
150
151 #if 0
152 static XREF_T  initial_map[] =
153 {
154    {"record",     0},
155    {"pause",      1},
156 };
157
158 static int initial_map_size = sizeof(initial_map) / sizeof(initial_map[0]);
159 #endif
160
161 static XREF_T  intra_refresh_map[] =
162 {
163    {"cyclic",       MMAL_VIDEO_INTRA_REFRESH_CYCLIC},
164    {"adaptive",     MMAL_VIDEO_INTRA_REFRESH_ADAPTIVE},
165    {"both",         MMAL_VIDEO_INTRA_REFRESH_BOTH},
166    {"cyclicrows",   MMAL_VIDEO_INTRA_REFRESH_CYCLIC_MROWS},
167 //   {"random",       MMAL_VIDEO_INTRA_REFRESH_PSEUDO_RAND} Cannot use random, crashes the encoder. No idea why.
168 };
169
170 static int intra_refresh_map_size = sizeof(intra_refresh_map) / sizeof(intra_refresh_map[0]);
171
172 #if 0
173
174 static void display_valid_parameters(char *app_name);
175
176 /// Command ID's and Structure defining our command line options
177 #define CommandHelp         0
178 #define CommandWidth        1
179 #define CommandHeight       2
180 #define CommandBitrate      3
181 #define CommandOutput       4
182 #define CommandVerbose      5
183 #define CommandTimeout      6
184 #define CommandDemoMode     7
185 #define CommandFramerate    8
186 #define CommandPreviewEnc   9
187 #define CommandIntraPeriod  10
188 #define CommandProfile      11
189 #define CommandTimed        12
190 #define CommandSignal       13
191 #define CommandKeypress     14
192 #define CommandInitialState 15
193 #define CommandQP           16
194 #define CommandInlineHeaders 17
195 #define CommandSegmentFile  18
196 #define CommandSegmentWrap  19
197 #define CommandSegmentStart 20
198 #define CommandSplitWait    21
199 #define CommandCircular     22
200 #define CommandIMV          23
201 #define CommandCamSelect    24
202 #define CommandSettings     25
203 #define CommandSensorMode   26
204 #define CommandIntraRefreshType 27
205
206 static COMMAND_LIST cmdline_commands[] =
207 {
208    { CommandHelp,          "-help",       "?",  "This help information", 0 },
209    { CommandWidth,         "-width",      "w",  "Set image width <size>. Default 1920", 1 },
210    { CommandHeight,        "-height",     "h",  "Set image height <size>. Default 1080", 1 },
211    { CommandBitrate,       "-bitrate",    "b",  "Set bitrate. Use bits per second (e.g. 10MBits/s would be -b 10000000)", 1 },
212    { CommandOutput,        "-output",     "o",  "Output filename <filename> (to write to stdout, use '-o -')", 1 },
213    { CommandVerbose,       "-verbose",    "v",  "Output verbose information during run", 0 },
214    { CommandTimeout,       "-timeout",    "t",  "Time (in ms) to capture for. If not specified, set to 5s. Zero to disable", 1 },
215    { CommandDemoMode,      "-demo",       "d",  "Run a demo mode (cycle through range of camera options, no capture)", 1},
216    { CommandFramerate,     "-framerate",  "fps","Specify the frames per second to record", 1},
217    { CommandPreviewEnc,    "-penc",       "e",  "Display preview image *after* encoding (shows compression artifacts)", 0},
218    { CommandIntraPeriod,   "-intra",      "g",  "Specify the intra refresh period (key frame rate/GoP size). Zero to produce an initial I-frame and then just P-frames.", 1},
219    { CommandProfile,       "-profile",    "pf", "Specify H264 profile to use for encoding", 1},
220    { CommandTimed,         "-timed",      "td", "Cycle between capture and pause. -cycle on,off where on is record time and off is pause time in ms", 0},
221    { CommandSignal,        "-signal",     "s",  "Cycle between capture and pause on Signal", 0},
222    { CommandKeypress,      "-keypress",   "k",  "Cycle between capture and pause on ENTER", 0},
223    { CommandInitialState,  "-initial",    "i",  "Initial state. Use 'record' or 'pause'. Default 'record'", 1},
224    { CommandQP,            "-qp",         "qp", "Quantisation parameter. Use approximately 10-40. Default 0 (off)", 1},
225    { CommandInlineHeaders, "-inline",     "ih", "Insert inline headers (SPS, PPS) to stream", 0},
226    { CommandSegmentFile,   "-segment",    "sg", "Segment output file in to multiple files at specified interval <ms>", 1},
227    { CommandSegmentWrap,   "-wrap",       "wr", "In segment mode, wrap any numbered filename back to 1 when reach number", 1},
228    { CommandSegmentStart,  "-start",      "sn", "In segment mode, start with specified segment number", 1},
229    { CommandSplitWait,     "-split",      "sp", "In wait mode, create new output file for each start event", 0},
230    { CommandCircular,      "-circular",   "c",  "Run encoded data through circular buffer until triggered then save", 0},
231    { CommandIMV,           "-vectors",    "x",  "Output filename <filename> for inline motion vectors", 1 },
232    { CommandCamSelect,     "-camselect",  "cs", "Select camera <number>. Default 0", 1 },
233    { CommandSettings,      "-settings",   "set","Retrieve camera settings and write to stdout", 0},
234    { CommandSensorMode,    "-mode",       "md", "Force sensor mode. 0=auto. See docs for other modes available", 1},
235    { CommandIntraRefreshType,"-irefresh", "if", "Set intra refresh type", 1},
236 };
237
238 static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
239 #endif
240
241 static void dump_state(RASPIVID_STATE *state);
242
243 /**
244  * Assign a default set of parameters to the state passed in
245  *
246  * @param state Pointer to state structure to assign defaults to
247  */
248 void raspicapture_default_config(RASPIVID_CONFIG *config)
249 {
250    if (!config)
251    {
252       vcos_assert(0);
253       return;
254    }
255
256    // Default everything to zero
257    memset(config, 0, sizeof(RASPIVID_CONFIG));
258
259    // Now set anything non-zero
260    config->timeout = 5000;     // 5s delay before take image
261    config->width = 1920;       // Default to 1080p
262    config->height = 1080;
263    config->bitrate = 17000000; // This is a decent default bitrate for 1080p
264    config->fps_n = VIDEO_FRAME_RATE_NUM;
265    config->fps_d = VIDEO_FRAME_RATE_DEN;
266    config->intraperiod = -1;    // Not set
267    config->quantisationParameter = 0;
268    config->demoMode = 0;
269    config->demoInterval = 250; // ms
270    config->immutableInput = 1;
271    config->profile = MMAL_VIDEO_PROFILE_H264_HIGH;
272    config->encoding = MMAL_ENCODING_H264;
273
274    config->bInlineHeaders = 0;
275
276    config->inlineMotionVectors = 0;
277
278    config->cameraNum = 0;
279    config->settings = 0;
280    config->sensor_mode = 0;
281
282    config->intra_refresh_type = -1;
283
284    // Setup preview window defaults
285    raspipreview_set_defaults(&config->preview_parameters);
286
287    // Set up the camera_parameters to default
288    raspicamcontrol_set_defaults(&config->camera_parameters);
289
290 }
291
292
293 /**
294  * Dump image state parameters to printf. Used for debugging
295  *
296  * @param state Pointer to state structure to assign defaults to
297  */
298 static void dump_state(RASPIVID_STATE *state)
299 {
300    RASPIVID_CONFIG *config;
301
302    if (!state)
303    {
304       vcos_assert(0);
305       return;
306    }
307
308    config = &state->config;
309
310    fprintf(stderr, "Width %d, Height %d\n", config->width, config->height);
311    fprintf(stderr, "bitrate %d, framerate %d/%d, time delay %d\n",
312        config->bitrate, config->fps_n, config->fps_d, config->timeout);
313    //fprintf(stderr, "H264 Profile %s\n", raspicli_unmap_xref(config->profile, profile_map, profile_map_size));
314
315    raspipreview_dump_parameters(&config->preview_parameters);
316    raspicamcontrol_dump_parameters(&config->camera_parameters);
317 }
318
319 #if 0
320 /**
321  * Parse the incoming command line and put resulting parameters in to the state
322  *
323  * @param argc Number of arguments in command line
324  * @param argv Array of pointers to strings from command line
325  * @param state Pointer to state structure to assign any discovered parameters to
326  * @return Non-0 if failed for some reason, 0 otherwise
327  */
328 static int parse_cmdline(int argc, const char **argv, RASPIVID_STATE *state)
329 {
330    // Parse the command line arguments.
331    // We are looking for --<something> or -<abreviation of something>
332
333    int valid = 1;
334    int i;
335
336    for (i = 1; i < argc && valid; i++)
337    {
338       int command_id, num_parameters;
339
340       if (!argv[i])
341          continue;
342
343       if (argv[i][0] != '-')
344       {
345          valid = 0;
346          continue;
347       }
348
349       // Assume parameter is valid until proven otherwise
350       valid = 1;
351
352       command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, &argv[i][1], &num_parameters);
353
354       // If we found a command but are missing a parameter, continue (and we will drop out of the loop)
355       if (command_id != -1 && num_parameters > 0 && (i + 1 >= argc) )
356          continue;
357
358       //  We are now dealing with a command line option
359       switch (command_id)
360       {
361       case CommandHelp:
362          display_valid_parameters(basename(argv[0]));
363          return -1;
364
365       case CommandWidth: // Width > 0
366          if (sscanf(argv[i + 1], "%u", &state->width) != 1)
367             valid = 0;
368          else
369             i++;
370          break;
371
372       case CommandHeight: // Height > 0
373          if (sscanf(argv[i + 1], "%u", &state->height) != 1)
374             valid = 0;
375          else
376             i++;
377          break;
378
379       case CommandBitrate: // 1-100
380          if (sscanf(argv[i + 1], "%u", &state->bitrate) == 1)
381          {
382             if (state->bitrate > MAX_BITRATE)
383             {
384                state->bitrate = MAX_BITRATE;
385             }
386             i++;
387          }
388          else
389             valid = 0;
390
391          break;
392
393       case CommandOutput:  // output filename
394       {
395          int len = strlen(argv[i + 1]);
396          if (len)
397          {
398             state->filename = malloc(len + 1);
399             vcos_assert(state->filename);
400             if (state->filename)
401                strncpy(state->filename, argv[i + 1], len+1);
402             i++;
403          }
404          else
405             valid = 0;
406          break;
407       }
408
409       case CommandVerbose: // display lots of data during run
410          state->verbose = 1;
411          break;
412
413       case CommandTimeout: // Time to run viewfinder/capture
414       {
415          if (sscanf(argv[i + 1], "%u", &state->timeout) == 1)
416          {
417             // Ensure that if previously selected a waitMethod we dont overwrite it
418             if (state->timeout == 0 && state->waitMethod == WAIT_METHOD_NONE)
419                state->waitMethod = WAIT_METHOD_FOREVER;
420
421             i++;
422          }
423          else
424             valid = 0;
425          break;
426       }
427
428       case CommandDemoMode: // Run in demo mode - no capture
429       {
430          // Demo mode might have a timing parameter
431          // so check if a) we have another parameter, b) its not the start of the next option
432          if (i + 1 < argc  && argv[i+1][0] != '-')
433          {
434             if (sscanf(argv[i + 1], "%u", &state->demoInterval) == 1)
435             {
436                // TODO : What limits do we need for timeout?
437                if (state->demoInterval == 0)
438                   state->demoInterval = 250; // ms
439
440                state->demoMode = 1;
441                i++;
442             }
443             else
444                valid = 0;
445          }
446          else
447          {
448             state->demoMode = 1;
449          }
450
451          break;
452       }
453
454       case CommandFramerate: // fps to record
455       {
456          if (sscanf(argv[i + 1], "%u", &state->framerate) == 1)
457          {
458             // TODO : What limits do we need for fps 1 - 30 - 120??
459             i++;
460          }
461          else
462             valid = 0;
463          break;
464       }
465
466       case CommandPreviewEnc:
467          state->immutableInput = 0;
468          break;
469
470       case CommandIntraPeriod: // key frame rate
471       {
472          if (sscanf(argv[i + 1], "%u", &state->intraperiod) == 1)
473             i++;
474          else
475             valid = 0;
476          break;
477       }
478
479       case CommandQP: // quantisation parameter
480       {
481          if (sscanf(argv[i + 1], "%u", &state->quantisationParameter) == 1)
482             i++;
483          else
484             valid = 0;
485          break;
486       }
487
488       case CommandProfile: // H264 profile
489       {
490          state->profile = raspicli_map_xref(argv[i + 1], profile_map, profile_map_size);
491
492          if( state->profile == -1)
493             state->profile = MMAL_VIDEO_PROFILE_H264_HIGH;
494
495          i++;
496          break;
497       }
498
499       case CommandInlineHeaders: // H264 inline headers
500       {
501          state->bInlineHeaders = 1;
502          break;
503       }
504
505       case CommandTimed:
506       {
507          if (sscanf(argv[i + 1], "%u,%u", &state->onTime, &state->offTime) == 2)
508          {
509             i++;
510
511             if (state->onTime < 1000)
512                state->onTime = 1000;
513
514             if (state->offTime < 1000)
515                state->offTime = 1000;
516
517             state->waitMethod = WAIT_METHOD_TIMED;
518          }
519          else
520             valid = 0;
521          break;
522       }
523
524       case CommandKeypress:
525          state->waitMethod = WAIT_METHOD_KEYPRESS;
526          break;
527
528       case CommandSignal:
529          state->waitMethod = WAIT_METHOD_SIGNAL;
530          // Reenable the signal
531          signal(SIGUSR1, signal_handler);
532          break;
533
534       case CommandInitialState:
535       {
536          state->bCapturing = raspicli_map_xref(argv[i + 1], initial_map, initial_map_size);
537
538          if( state->bCapturing == -1)
539             state->bCapturing = 0;
540
541          i++;
542          break;
543       }
544
545       case CommandSegmentFile: // Segment file in to chunks of specified time
546       {
547          if (sscanf(argv[i + 1], "%u", &state->segmentSize) == 1)
548          {
549             // Must enable inline headers for this to work
550             state->bInlineHeaders = 1;
551             i++;
552          }
553          else
554             valid = 0;
555          break;
556       }
557
558       case CommandSegmentWrap: // segment wrap value
559       {
560          if (sscanf(argv[i + 1], "%u", &state->segmentWrap) == 1)
561             i++;
562          else
563             valid = 0;
564          break;
565       }
566
567       case CommandSegmentStart: // initial segment number
568       {
569          if((sscanf(argv[i + 1], "%u", &state->segmentNumber) == 1) && (!state->segmentWrap || (state->segmentNumber <= state->segmentWrap)))
570             i++;
571          else
572             valid = 0;
573          break;
574       }
575
576       case CommandSplitWait: // split files on restart
577       {
578          // Must enable inline headers for this to work
579          state->bInlineHeaders = 1;
580          state->splitWait = 1;
581          break;
582       }
583
584       case CommandCircular:
585       {
586          state->bCircularBuffer = 1;
587          break;
588       }
589
590       case CommandIMV:  // output filename
591       {
592          state->inlineMotionVectors = 1;
593          int len = strlen(argv[i + 1]);
594          if (len)
595          {
596             state->imv_filename = malloc(len + 1);
597             vcos_assert(state->imv_filename);
598             if (state->imv_filename)
599                strncpy(state->imv_filename, argv[i + 1], len+1);
600             i++;
601          }
602          else
603             valid = 0;
604          break;
605       }
606       case CommandCamSelect:  //Select camera input port
607       {
608          if (sscanf(argv[i + 1], "%u", &state->cameraNum) == 1)
609          {
610             i++;
611          }
612          else
613             valid = 0;
614          break;
615       }
616
617       case CommandSettings:
618          state->settings = 1;
619          break;
620
621       case CommandSensorMode:
622       {
623          if (sscanf(argv[i + 1], "%u", &state->sensor_mode) == 1)
624          {
625             i++;
626          }
627          else
628             valid = 0;
629          break;
630       }
631
632       case CommandIntraRefreshType:
633       {
634          state->config.intra_refresh_type = raspicli_map_xref(argv[i + 1], intra_refresh_map, intra_refresh_map_size);
635          i++;
636          break;
637       }
638
639       default:
640       {
641          // Try parsing for any image specific parameters
642          // result indicates how many parameters were used up, 0,1,2
643          // but we adjust by -1 as we have used one already
644          const char *second_arg = (i + 1 < argc) ? argv[i + 1] : NULL;
645          int parms_used = (raspicamcontrol_parse_cmdline(&state->camera_parameters, &argv[i][1], second_arg));
646
647          // Still unused, try preview options
648          if (!parms_used)
649             parms_used = raspipreview_parse_cmdline(&state->preview_parameters, &argv[i][1], second_arg);
650
651
652          // If no parms were used, this must be a bad parameters
653          if (!parms_used)
654             valid = 0;
655          else
656             i += parms_used - 1;
657
658          break;
659       }
660       }
661    }
662
663    if (!valid)
664    {
665       fprintf(stderr, "Invalid command line option (%s)\n", argv[i-1]);
666       return 1;
667    }
668
669    // Always disable verbose if output going to stdout
670    if (state->filename && state->filename[0] == '-')
671    {
672       state->verbose = 0;
673    }
674
675    return 0;
676 }
677
678 /**
679  * Display usage information for the application to stdout
680  *
681  * @param app_name String to display as the application name
682  */
683 static void display_valid_parameters(char *app_name)
684 {
685    int i;
686
687    fprintf(stderr, "Display camera output to display, and optionally saves an H264 capture at requested bitrate\n\n");
688    fprintf(stderr, "\nusage: %s [options]\n\n", app_name);
689
690    fprintf(stderr, "Image parameter commands\n\n");
691
692    raspicli_display_help(cmdline_commands, cmdline_commands_size);
693
694    // Profile options
695    fprintf(stderr, "\n\nH264 Profile options :\n%s", profile_map[0].mode );
696
697    for (i=1;i<profile_map_size;i++)
698    {
699       fprintf(stderr, ",%s", profile_map[i].mode);
700    }
701
702    fprintf(stderr, "\n");
703
704    // Intra refresh options
705    fprintf(stderr, "\n\nH264 Intra refresh options :\n%s", intra_refresh_map[0].mode );
706
707    for (i=1;i<intra_refresh_map_size;i++)
708    {
709       fprintf(stderr, ",%s", intra_refresh_map[i].mode);
710    }
711
712    fprintf(stderr, "\n");
713
714    // Help for preview options
715    raspipreview_display_help();
716
717    // Now display any help information from the camcontrol code
718    raspicamcontrol_display_help();
719
720    fprintf(stderr, "\n");
721
722    return;
723 }
724 #endif
725
726 /**
727  *  buffer header callback function for camera control
728  *
729  *  Callback will dump buffer data to the specific file
730  *
731  * @param port Pointer to port from which callback originated
732  * @param buffer mmal buffer header pointer
733  */
734 static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
735 {
736    if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED)
737    {
738       MMAL_EVENT_PARAMETER_CHANGED_T *param = (MMAL_EVENT_PARAMETER_CHANGED_T *)buffer->data;
739       switch (param->hdr.id) {
740          case MMAL_PARAMETER_CAMERA_SETTINGS:
741          {
742             MMAL_PARAMETER_CAMERA_SETTINGS_T *settings = (MMAL_PARAMETER_CAMERA_SETTINGS_T*)param;
743             vcos_log_error("Exposure now %u, analog gain %u/%u, digital gain %u/%u",
744             settings->exposure,
745                         settings->analog_gain.num, settings->analog_gain.den,
746                         settings->digital_gain.num, settings->digital_gain.den);
747             vcos_log_error("AWB R=%u/%u, B=%u/%u",
748                         settings->awb_red_gain.num, settings->awb_red_gain.den,
749                         settings->awb_blue_gain.num, settings->awb_blue_gain.den
750                         );
751          }
752          break;
753       }
754    }
755    else if (buffer->cmd == MMAL_EVENT_ERROR) {
756       vcos_log_error("Camera control callback got an error");
757    } else {
758       vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd);
759    }
760
761    mmal_buffer_header_release(buffer);
762 }
763
764 #if 0
765 /**
766  * Open a file based on the settings in state
767  *
768  * @param state Pointer to state
769  */
770 static FILE *open_filename(RASPIVID_STATE *pState)
771 {
772    FILE *new_handle = NULL;
773    char *tempname = NULL, *filename = NULL;
774
775    if (pState->segmentSize || pState->splitWait)
776    {
777       // Create a new filename string
778       asprintf(&tempname, pState->filename, pState->segmentNumber);
779       filename = tempname;
780    }
781    else
782    {
783       filename = pState->filename;
784    }
785
786    if (filename)
787       new_handle = fopen(filename, "wb");
788
789    if (pState->verbose)
790    {
791       if (new_handle)
792          fprintf(stderr, "Opening output file \"%s\"\n", filename);
793       else
794          fprintf(stderr, "Failed to open new file \"%s\"\n", filename);
795    }
796
797    if (tempname)
798       free(tempname);
799
800    return new_handle;
801 }
802
803 /**
804  * Open a file based on the settings in state
805  *
806  * This time for the imv output file
807  *
808  * @param state Pointer to state
809  */
810 static FILE *open_imv_filename(RASPIVID_STATE *pState)
811 {
812    FILE *new_handle = NULL;
813    char *tempname = NULL, *filename = NULL;
814
815    if (pState->segmentSize || pState->splitWait)
816    {
817       // Create a new filename string
818       asprintf(&tempname, pState->imv_filename, pState->segmentNumber);
819       filename = tempname;
820    }
821    else
822    {
823       filename = pState->imv_filename;
824    }
825
826    if (filename)
827       new_handle = fopen(filename, "wb");
828
829    if (pState->verbose)
830    {
831       if (new_handle)
832          fprintf(stderr, "Opening imv output file \"%s\"\n", filename);
833       else
834          fprintf(stderr, "Failed to open new imv file \"%s\"\n", filename);
835    }
836
837    if (tempname)
838       free(tempname);
839
840    return new_handle;
841 }
842 #endif
843
844 /**
845  * Update any annotation data specific to the video.
846  * This simply passes on the setting from cli, or
847  * if application defined annotate requested, updates
848  * with the H264 parameters
849  *
850  * @param state Pointer to state control struct
851  *
852  */
853 static void update_annotation_data(RASPIVID_STATE *state)
854 {
855    RASPIVID_CONFIG *config = &state->config;
856
857    // So, if we have asked for a application supplied string, set it to the H264 parameters
858    if (config->camera_parameters.enable_annotate & ANNOTATE_APP_TEXT)
859    {
860       char *text;
861       const char *refresh = raspicli_unmap_xref(config->intra_refresh_type, intra_refresh_map, intra_refresh_map_size);
862
863       asprintf(&text,  "%dk,%ff,%s,%d,%s",
864             config->bitrate / 1000,  ((float)(config->fps_n) / config->fps_d),
865             refresh ? refresh : "(none)",
866             config->intraperiod,
867             raspicli_unmap_xref(config->profile, profile_map, profile_map_size));
868
869       raspicamcontrol_set_annotate(state->camera_component, config->camera_parameters.enable_annotate, text,
870                        config->camera_parameters.annotate_text_size,
871                        config->camera_parameters.annotate_text_colour,
872                        config->camera_parameters.annotate_bg_colour);
873
874       free(text);
875    }
876    else
877    {
878       raspicamcontrol_set_annotate(state->camera_component, config->camera_parameters.enable_annotate,
879                        config->camera_parameters.annotate_string,
880                        config->camera_parameters.annotate_text_size,
881                        config->camera_parameters.annotate_text_colour,
882                        config->camera_parameters.annotate_bg_colour);
883    }
884 }
885
886
887
888 /**
889  *  buffer header callback function for encoder
890  *
891  *  Callback will dump buffer data to the specific file
892  *
893  * @param port Pointer to port from which callback originated
894  * @param buffer mmal buffer header pointer
895  */
896 static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
897 {
898    PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata;
899    RASPIVID_STATE *state  = pData->state;
900    int64_t current_time;
901
902    // All our segment times based on the receipt of the first encoder callback
903    if (state->base_time == -1)
904       state->base_time = vcos_getmicrosecs64()/1000;
905
906    if (pData == NULL)
907    {
908       vcos_log_error("Received a encoder buffer callback with no state");
909       // release buffer back to the pool
910       mmal_buffer_header_release(buffer);
911       return;
912    }
913
914    current_time = vcos_getmicrosecs64()/1000;
915    if (state->base_time == -1)
916      state->base_time = current_time;
917
918    // See if the second count has changed and we need to update any annotation
919    if (current_time/1000 != state->last_second)
920    {
921       update_annotation_data(state);
922       state->last_second = current_time/1000;
923    }
924
925    /* Send buffer to GStreamer element for pushing to the pipeline */
926    mmal_queue_put(state->encoded_buffer_q, buffer);
927 }
928
929 GstFlowReturn
930 raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **bufp,
931     GstClock *clock, GstClockTime base_time)
932 {
933   RASPIVID_CONFIG *config = &state->config;
934   GstBuffer *buf;
935   MMAL_BUFFER_HEADER_T *buffer;
936   GstFlowReturn ret = GST_FLOW_ERROR;
937   /* No timestamps if no clockm or invalid PTS */
938   GstClockTime gst_pts = GST_CLOCK_TIME_NONE;
939
940   /* FIXME: Use our own interruptible cond wait: */
941   buffer = mmal_queue_wait(state->encoded_buffer_q);
942
943
944   if (G_LIKELY (config->useSTC && clock)) {
945     MMAL_PARAMETER_INT64_T param;
946     GstClockTime runtime;
947
948     runtime = gst_clock_get_time (clock) - base_time;
949
950     param.hdr.id = MMAL_PARAMETER_SYSTEM_TIME;
951     param.hdr.size = sizeof(param);
952     param.value = -1;
953
954     mmal_port_parameter_get(state->encoder_output_port, &param.hdr);
955
956     if (buffer->pts != -1 && param.value != -1 && param.value >= buffer->pts) {
957       /* Convert microsecond RPi TS to GStreamer clock: */
958       GstClockTime offset = (param.value - buffer->pts) * 1000;
959       if (runtime >= offset)
960         gst_pts = runtime - offset;
961     }
962     GST_LOG ("Buf (uS) PTS %" G_GINT64_FORMAT " DTS %" G_GINT64_FORMAT
963         " STC %" G_GINT64_FORMAT " (latency %" G_GINT64_FORMAT
964         "uS) TS %" GST_TIME_FORMAT,
965         buffer->pts, buffer->dts, param.value, param.value - buffer->pts,
966         GST_TIME_ARGS (gst_pts));
967   }
968   else {
969     GST_LOG ("use-stc=false. Not applying STC to buffer");
970   }
971
972   mmal_buffer_header_mem_lock(buffer);
973   buf = gst_buffer_new_allocate(NULL, buffer->length, NULL);
974   if (buf) {
975     if (config->useSTC)
976         GST_BUFFER_DTS(buf) = GST_BUFFER_PTS(buf) = gst_pts;
977     /* FIXME: Can we avoid copies and give MMAL our own buffers to fill? */
978     gst_buffer_fill(buf, 0, buffer->data, buffer->length);
979     ret = GST_FLOW_OK;
980   }
981
982   mmal_buffer_header_mem_unlock(buffer);
983
984   *bufp = buf;
985   // release buffer back to the pool
986   mmal_buffer_header_release(buffer);
987
988   // and send one back to the port (if still open)
989   if (state->encoder_output_port->is_enabled)
990   {
991      MMAL_STATUS_T status = MMAL_SUCCESS;
992
993      buffer = mmal_queue_get(state->encoder_pool->queue);
994      if (buffer)
995         status = mmal_port_send_buffer(state->encoder_output_port, buffer);
996
997      if (!buffer || status != MMAL_SUCCESS) {
998        vcos_log_error("Unable to return a buffer to the encoder port");
999        ret = GST_FLOW_ERROR;
1000      }
1001   }
1002
1003   return ret;
1004 }
1005
1006 /**
1007  * Create the camera component, set up its ports
1008  *
1009  * @param state Pointer to state control struct
1010  *
1011  * @return MMAL_SUCCESS if all OK, something else otherwise
1012  *
1013  */
1014 static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
1015 {
1016    MMAL_COMPONENT_T *camera = NULL;
1017    MMAL_STATUS_T status;
1018    RASPIVID_CONFIG *config = &state->config;
1019
1020    /* Create the component */
1021    status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
1022
1023    if (status != MMAL_SUCCESS)
1024    {
1025       vcos_log_error("Failed to create camera component");
1026       goto error;
1027    }
1028
1029    MMAL_PARAMETER_INT32_T camera_num =
1030       {{MMAL_PARAMETER_CAMERA_NUM, sizeof(camera_num)}, config->cameraNum};
1031
1032    status = mmal_port_parameter_set(camera->control, &camera_num.hdr);
1033
1034    if (status != MMAL_SUCCESS)
1035    {
1036       vcos_log_error("Could not select camera : error %d", status);
1037       goto error;
1038    }
1039
1040    if (!camera->output_num)
1041    {
1042       status = MMAL_ENOSYS;
1043       vcos_log_error("Camera doesn't have output ports");
1044       goto error;
1045    }
1046
1047    status = mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, config->sensor_mode);
1048
1049    if (status != MMAL_SUCCESS)
1050    {
1051       vcos_log_error("Could not set sensor mode : error %d", status);
1052       goto error;
1053    }
1054
1055    if (config->settings)
1056    {
1057       MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T change_event_request =
1058          {{MMAL_PARAMETER_CHANGE_EVENT_REQUEST, sizeof(MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T)},
1059           MMAL_PARAMETER_CAMERA_SETTINGS, 1};
1060
1061       status = mmal_port_parameter_set(camera->control, &change_event_request.hdr);
1062       if ( status != MMAL_SUCCESS )
1063       {
1064          vcos_log_error("No camera settings events");
1065       }
1066    }
1067
1068    // Enable the camera, and tell it its control callback function
1069    status = mmal_port_enable(camera->control, camera_control_callback);
1070
1071    if (status != MMAL_SUCCESS)
1072    {
1073       vcos_log_error("Unable to enable control port : error %d", status);
1074       goto error;
1075    }
1076
1077    state->camera_component = camera;
1078
1079    return status;
1080
1081 error:
1082    if (camera)
1083      mmal_component_destroy(camera);
1084
1085    return status;
1086 }
1087
1088 MMAL_STATUS_T
1089 raspi_capture_set_format_and_start(RASPIVID_STATE *state)
1090 {
1091    MMAL_COMPONENT_T *camera = NULL;
1092    MMAL_STATUS_T status;
1093    MMAL_ES_FORMAT_T *format;
1094    MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL;
1095    RASPIVID_CONFIG *config = &state->config;
1096
1097    //  set up the camera configuration
1098
1099    MMAL_PARAMETER_CAMERA_CONFIG_T cam_config =
1100    {
1101       { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) },
1102       .max_stills_w = config->width,
1103       .max_stills_h = config->height,
1104       .stills_yuv422 = 0,
1105       .one_shot_stills = 0,
1106       .max_preview_video_w = config->width,
1107       .max_preview_video_h = config->height,
1108       .num_preview_video_frames = 3,
1109       .stills_capture_circular_buffer_height = 0,
1110       .fast_preview_resume = 0,
1111       .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RAW_STC
1112    };
1113
1114    camera = state->camera_component;
1115    preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT];
1116    video_port = camera->output[MMAL_CAMERA_VIDEO_PORT];
1117    still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT];
1118
1119    mmal_port_parameter_set(camera->control, &cam_config.hdr);
1120
1121    // Now set up the port formats
1122
1123    // Set the encode format on the Preview port
1124    // HW limitations mean we need the preview to be the same size as the required recorded output
1125
1126    format = preview_port->format;
1127
1128    if(config->camera_parameters.shutter_speed > 6000000)
1129    {
1130         MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
1131                                                      { 50, 1000 }, {166, 1000}};
1132         mmal_port_parameter_set(preview_port, &fps_range.hdr);
1133    }
1134    else if(config->camera_parameters.shutter_speed > 1000000)
1135    {
1136         MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
1137                                                      { 166, 1000 }, {999, 1000}};
1138         mmal_port_parameter_set(preview_port, &fps_range.hdr);
1139    }
1140
1141    //enable dynamic framerate if necessary
1142    if (config->camera_parameters.shutter_speed)
1143    {
1144       if (((float)(config->fps_n) / config->fps_d) > 1000000.0 / config->camera_parameters.shutter_speed)
1145       {
1146          config->fps_n = 0;
1147          config->fps_d = 1;
1148          GST_INFO ("Enabling dynamic frame rate to fulfil shutter speed requirement");
1149       }
1150    }
1151
1152    format->encoding = MMAL_ENCODING_OPAQUE;
1153    format->encoding_variant = MMAL_ENCODING_I420;
1154
1155    format->es->video.width = VCOS_ALIGN_UP(config->width, 32);
1156    format->es->video.height = VCOS_ALIGN_UP(config->height, 16);
1157    format->es->video.crop.x = 0;
1158    format->es->video.crop.y = 0;
1159    format->es->video.crop.width = config->width;
1160    format->es->video.crop.height = config->height;
1161    format->es->video.frame_rate.num = config->fps_n;
1162    format->es->video.frame_rate.den = config->fps_d;
1163
1164    status = mmal_port_format_commit(preview_port);
1165
1166    if (status != MMAL_SUCCESS)
1167    {
1168       vcos_log_error("camera viewfinder format couldn't be set");
1169       goto error;
1170    }
1171
1172    // Set the encode format on the video  port
1173    format = video_port->format;
1174
1175    if(config->camera_parameters.shutter_speed > 6000000)
1176    {
1177         MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
1178                                                      { 50, 1000 }, {166, 1000}};
1179         mmal_port_parameter_set(video_port, &fps_range.hdr);
1180    }
1181    else if(config->camera_parameters.shutter_speed > 1000000)
1182    {
1183         MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
1184                                                      { 167, 1000 }, {999, 1000}};
1185         mmal_port_parameter_set(video_port, &fps_range.hdr);
1186    }
1187
1188    /* If encoding, set opaque tunneling format */
1189    if (state->encoder_component) {
1190      format->encoding = MMAL_ENCODING_OPAQUE;
1191      format->encoding_variant = MMAL_ENCODING_I420;
1192    }
1193    else {
1194      format->encoding = config->encoding;
1195      format->encoding_variant = config->encoding;
1196    }
1197
1198    format->es->video.width = VCOS_ALIGN_UP(config->width, 32);
1199    format->es->video.height = VCOS_ALIGN_UP(config->height, 16);
1200    format->es->video.crop.x = 0;
1201    format->es->video.crop.y = 0;
1202    format->es->video.crop.width = config->width;
1203    format->es->video.crop.height = config->height;
1204    format->es->video.frame_rate.num = config->fps_n;
1205    format->es->video.frame_rate.den = config->fps_d;
1206
1207    status = mmal_port_format_commit(video_port);
1208
1209    if (status != MMAL_SUCCESS)
1210    {
1211       vcos_log_error("camera video format couldn't be set");
1212       goto error;
1213    }
1214
1215    // Ensure there are enough buffers to avoid dropping frames
1216    if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
1217       video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
1218
1219
1220    // Set the encode format on the still  port
1221
1222    format = still_port->format;
1223
1224    format->encoding = MMAL_ENCODING_OPAQUE;
1225    format->encoding_variant = MMAL_ENCODING_I420;
1226
1227    format->es->video.width = VCOS_ALIGN_UP(config->width, 32);
1228    format->es->video.height = VCOS_ALIGN_UP(config->height, 16);
1229    format->es->video.crop.x = 0;
1230    format->es->video.crop.y = 0;
1231    format->es->video.crop.width = config->width;
1232    format->es->video.crop.height = config->height;
1233    format->es->video.frame_rate.num = 0;
1234    format->es->video.frame_rate.den = 1;
1235
1236    status = mmal_port_format_commit(still_port);
1237
1238    if (status != MMAL_SUCCESS)
1239    {
1240       vcos_log_error("camera still format couldn't be set");
1241       goto error;
1242    }
1243
1244    /* Ensure there are enough buffers to avoid dropping frames */
1245    if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
1246       still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
1247
1248    /* Enable component */
1249    status = mmal_component_enable(camera);
1250
1251    if (status != MMAL_SUCCESS)
1252    {
1253       vcos_log_error("camera component couldn't be enabled");
1254       goto error;
1255    }
1256
1257    raspicamcontrol_set_all_parameters(camera, &config->camera_parameters);
1258
1259    update_annotation_data(state);
1260
1261    if (config->verbose)
1262       fprintf(stderr, "Camera component done\n");
1263
1264    return status;
1265
1266 error:
1267
1268    if (camera)
1269       mmal_component_destroy(camera);
1270
1271    return status;
1272 }
1273
1274 /**
1275  * Destroy the camera component
1276  *
1277  * @param state Pointer to state control struct
1278  *
1279  */
1280 static void destroy_camera_component(RASPIVID_STATE *state)
1281 {
1282    if (state->camera_component)
1283    {
1284       mmal_component_destroy(state->camera_component);
1285       state->camera_component = NULL;
1286    }
1287 }
1288
1289 gboolean raspi_capture_request_i_frame(RASPIVID_STATE *state)
1290 {
1291    MMAL_PORT_T *encoder_output = NULL;
1292    MMAL_STATUS_T status;
1293    MMAL_PARAMETER_BOOLEAN_T param = {{  MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME, sizeof(param)}, 1};
1294
1295    if (state->encoder_component)
1296      return TRUE;
1297
1298    encoder_output = state->encoder_component->output[0];
1299    status = mmal_port_parameter_set(encoder_output, &param.hdr);
1300    if (status != MMAL_SUCCESS)
1301    {
1302       vcos_log_error("Unable to request I-frame");
1303       return FALSE;
1304    }
1305    return TRUE;
1306 }
1307
1308 /**
1309  * Create the encoder component, set up its ports
1310  *
1311  * @param state Pointer to state control struct
1312  *
1313  * @return MMAL_SUCCESS if all OK, something else otherwise
1314  *
1315  */
1316 static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
1317 {
1318    MMAL_COMPONENT_T *encoder = 0;
1319    MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL;
1320    MMAL_STATUS_T status;
1321    RASPIVID_CONFIG *config = &state->config;
1322
1323    gboolean encoded_format =
1324      (config->encoding == MMAL_ENCODING_H264 ||
1325       config->encoding == MMAL_ENCODING_MJPEG ||
1326       config->encoding == MMAL_ENCODING_JPEG);
1327
1328    if (!encoded_format)
1329      return MMAL_SUCCESS;
1330
1331    if (config->encoding == MMAL_ENCODING_JPEG)
1332      status = mmal_component_create(MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER, &encoder);
1333    else
1334      status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, &encoder);
1335
1336    if (status != MMAL_SUCCESS) {
1337      vcos_log_error("Unable to create video encoder component");
1338      goto error;
1339    }
1340
1341    if (!encoder->input_num || !encoder->output_num)
1342    {
1343       status = MMAL_ENOSYS;
1344       vcos_log_error("Video encoder doesn't have input/output ports");
1345       goto error;
1346    }
1347
1348    encoder_input = encoder->input[0];
1349    encoder_output = encoder->output[0];
1350
1351    // We want same format on input and output
1352    mmal_format_copy(encoder_output->format, encoder_input->format);
1353
1354    // Configure desired encoding
1355    encoder_output->format->encoding = config->encoding;
1356
1357    encoder_output->format->bitrate = config->bitrate;
1358
1359    if (config->encoding == MMAL_ENCODING_H264)
1360      encoder_output->buffer_size = encoder_output->buffer_size_recommended;
1361    else
1362      encoder_output->buffer_size = 256<<10;
1363
1364    if (encoder_output->buffer_size < encoder_output->buffer_size_min)
1365       encoder_output->buffer_size = encoder_output->buffer_size_min;
1366
1367    encoder_output->buffer_num = encoder_output->buffer_num_recommended;
1368
1369    if (encoder_output->buffer_num < encoder_output->buffer_num_min)
1370       encoder_output->buffer_num = encoder_output->buffer_num_min;
1371
1372    GST_DEBUG ("encoder wants %d buffers of size %u",
1373        (guint)encoder_output->buffer_num, (guint)encoder_output->buffer_size);
1374
1375    // We need to set the frame rate on output to 0, to ensure it gets
1376    // updated correctly from the input framerate when port connected
1377    encoder_output->format->es->video.frame_rate.num = 0;
1378    encoder_output->format->es->video.frame_rate.den = 1;
1379
1380    // Commit the port changes to the output port
1381    status = mmal_port_format_commit(encoder_output);
1382    if (status != MMAL_SUCCESS) {
1383       vcos_log_error("Unable to set format on video encoder output port");
1384       goto error;
1385    }
1386
1387    // Set the rate control parameter
1388    if (0)
1389    {
1390       MMAL_PARAMETER_VIDEO_RATECONTROL_T param = {{ MMAL_PARAMETER_RATECONTROL, sizeof(param)}, MMAL_VIDEO_RATECONTROL_DEFAULT};
1391       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1392       if (status != MMAL_SUCCESS)
1393       {
1394          vcos_log_error("Unable to set ratecontrol");
1395          goto error;
1396       }
1397
1398    }
1399
1400    if (config->encoding == MMAL_ENCODING_H264 && config->intraperiod != -1)
1401    {
1402       MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, config->intraperiod};
1403       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1404       if (status != MMAL_SUCCESS)
1405       {
1406          vcos_log_error("Unable to set intraperiod");
1407          goto error;
1408       }
1409    }
1410
1411    if (config->encoding == MMAL_ENCODING_H264 && config->quantisationParameter)
1412    {
1413       MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, config->quantisationParameter};
1414       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1415       if (status != MMAL_SUCCESS)
1416       {
1417          vcos_log_error("Unable to set initial QP");
1418          goto error;
1419       }
1420
1421       MMAL_PARAMETER_UINT32_T param2 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, sizeof(param)}, config->quantisationParameter};
1422       status = mmal_port_parameter_set(encoder_output, &param2.hdr);
1423       if (status != MMAL_SUCCESS)
1424       {
1425          vcos_log_error("Unable to set min QP");
1426          goto error;
1427       }
1428
1429       MMAL_PARAMETER_UINT32_T param3 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, sizeof(param)}, config->quantisationParameter};
1430       status = mmal_port_parameter_set(encoder_output, &param3.hdr);
1431       if (status != MMAL_SUCCESS)
1432       {
1433          vcos_log_error("Unable to set max QP");
1434          goto error;
1435       }
1436    }
1437
1438    if (config->encoding == MMAL_ENCODING_H264)
1439    {
1440       MMAL_PARAMETER_VIDEO_PROFILE_T  param;
1441       param.hdr.id = MMAL_PARAMETER_PROFILE;
1442       param.hdr.size = sizeof(param);
1443
1444       param.profile[0].profile = config->profile;
1445       param.profile[0].level = MMAL_VIDEO_LEVEL_H264_4; // This is the only value supported
1446
1447       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1448       if (status != MMAL_SUCCESS)
1449       {
1450          vcos_log_error("Unable to set H264 profile");
1451          goto error;
1452       }
1453    }
1454
1455    if (config->encoding != MMAL_ENCODING_JPEG)
1456    {
1457      if (mmal_port_parameter_set_boolean(encoder_input, MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, config->immutableInput) != MMAL_SUCCESS)
1458      {
1459         vcos_log_error("Unable to set immutable input flag");
1460         // Continue rather than abort..
1461      }
1462
1463      //set INLINE HEADER flag to generate SPS and PPS for every IDR if requested
1464      if (mmal_port_parameter_set_boolean(encoder_output, MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, config->bInlineHeaders) != MMAL_SUCCESS)
1465      {
1466         vcos_log_error("failed to set INLINE HEADER FLAG parameters");
1467         // Continue rather than abort..
1468      }
1469   }
1470
1471   if (config->encoding == MMAL_ENCODING_H264)
1472   {
1473      //set INLINE VECTORS flag to request motion vector estimates
1474      if (mmal_port_parameter_set_boolean(encoder_output, MMAL_PARAMETER_VIDEO_ENCODE_INLINE_VECTORS, config->inlineMotionVectors) != MMAL_SUCCESS)
1475      {
1476         vcos_log_error("failed to set INLINE VECTORS parameters");
1477         // Continue rather than abort..
1478      }
1479
1480      // Adaptive intra refresh settings
1481      if (config->intra_refresh_type != -1)
1482      {
1483         MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T  param;
1484
1485         /* Need to memset, apparently mmal_port_parameter_get()
1486          * doesn't retrieve all parameters, causing random failures
1487          * when we set it
1488          */
1489         memset (&param, 0, sizeof (MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T));
1490
1491         param.hdr.id = MMAL_PARAMETER_VIDEO_INTRA_REFRESH;
1492         param.hdr.size = sizeof(param);
1493
1494         // Get first so we don't overwrite anything unexpectedly
1495         status = mmal_port_parameter_get(encoder_output, &param.hdr);
1496
1497         param.refresh_mode = config->intra_refresh_type;
1498
1499         //if (state->intra_refresh_type == MMAL_VIDEO_INTRA_REFRESH_CYCLIC_MROWS)
1500         //   param.cir_mbs = 10;
1501
1502         status = mmal_port_parameter_set(encoder_output, &param.hdr);
1503         if (status != MMAL_SUCCESS)
1504         {
1505          vcos_log_error("Unable to set H264 intra-refresh values");
1506            goto error;
1507         }
1508      }
1509    }
1510
1511    if (config->encoding == MMAL_ENCODING_JPEG)
1512    {
1513       status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_Q_FACTOR, config->jpegQuality);
1514       if (status != MMAL_SUCCESS) {
1515          vcos_log_error("Unable to set JPEG quality");
1516          // Continue after warning
1517       }
1518
1519 #ifdef MMAL_PARAMETER_JPEG_RESTART_INTERVAL
1520       status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_RESTART_INTERVAL, config->jpegRestartInterval);
1521       if (status != MMAL_SUCCESS) {
1522          vcos_log_error("Unable to set JPEG restart interval");
1523          // Continue after warning
1524       }
1525 #endif
1526    }
1527
1528    //  Enable component
1529    status = mmal_component_enable(encoder);
1530
1531    if (status != MMAL_SUCCESS)
1532    {
1533       vcos_log_error("Unable to enable video encoder component");
1534       goto error;
1535    }
1536
1537    state->encoder_component = encoder;
1538
1539    if (config->verbose)
1540       fprintf(stderr, "Encoder component done\n");
1541
1542    return status;
1543
1544    error:
1545    if (encoder)
1546       mmal_component_destroy(encoder);
1547
1548    state->encoder_component = NULL;
1549
1550    return status;
1551 }
1552
1553 /**
1554  * Destroy the encoder component
1555  *
1556  * @param state Pointer to state control struct
1557  *
1558  */
1559 static void destroy_encoder_component(RASPIVID_STATE *state)
1560 {
1561   /* Empty the buffer header q */
1562    if (state->encoded_buffer_q) {
1563       while (mmal_queue_length(state->encoded_buffer_q)) {
1564         MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->encoded_buffer_q);
1565         mmal_buffer_header_release(buffer);
1566       }
1567    }
1568
1569    // Get rid of any port buffers first
1570    if (state->encoder_pool)
1571    {
1572       mmal_port_pool_destroy(state->encoder_output_port, state->encoder_pool);
1573       state->encoder_pool = NULL;
1574    }
1575
1576    if (state->encoder_component) {
1577
1578       mmal_component_destroy(state->encoder_component);
1579       state->encoder_component = NULL;
1580    }
1581 }
1582
1583 /**
1584  * Connect two specific ports together
1585  *
1586  * @param output_port Pointer the output port
1587  * @param input_port Pointer the input port
1588  * @param Pointer to a mmal connection pointer, reassigned if function successful
1589  * @return Returns a MMAL_STATUS_T giving result of operation
1590  *
1591  */
1592 static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection)
1593 {
1594    MMAL_STATUS_T status;
1595
1596    status =  mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT);
1597
1598    if (status == MMAL_SUCCESS)
1599    {
1600       status =  mmal_connection_enable(*connection);
1601       if (status != MMAL_SUCCESS)
1602          mmal_connection_destroy(*connection);
1603    }
1604
1605    return status;
1606 }
1607
1608 /**
1609  * Checks if specified port is valid and enabled, then disables it
1610  *
1611  * @param port  Pointer the port
1612  *
1613  */
1614 static void check_disable_port(MMAL_PORT_T *port)
1615 {
1616    if (port && port->is_enabled)
1617       mmal_port_disable(port);
1618 }
1619
1620 void raspicapture_init()
1621 {
1622    bcm_host_init();
1623
1624    // Register our application with the logging system
1625    vcos_log_register("RaspiVid", VCOS_LOG_CATEGORY);
1626 }
1627
1628 RASPIVID_STATE *
1629 raspi_capture_setup(RASPIVID_CONFIG *config)
1630 {
1631   // Our main data storage vessel..
1632   RASPIVID_STATE *state;
1633
1634   MMAL_STATUS_T status = MMAL_SUCCESS;
1635
1636   /* Default everything to zero */
1637   state = calloc(1, sizeof(RASPIVID_STATE));
1638
1639   /* Apply passed in config */
1640   state->config = *config;
1641
1642   /* Initialize timestamping */
1643   state->base_time = state->last_second = -1;
1644
1645   /* So far, all we can do is create the camera component. Actual
1646    * config and connection of encoders etc happens in _start()
1647    */
1648   // OK, we have a nice set of parameters. Now set up our components
1649   // We have three components. Camera, Preview and encoder.
1650
1651   if ((status = create_camera_component(state)) != MMAL_SUCCESS)
1652   {
1653      vcos_log_error("%s: Failed to create camera component", __func__);
1654      return NULL;
1655   }
1656
1657   if ((status = raspipreview_create(&state->preview_state, &config->preview_parameters)) != MMAL_SUCCESS)
1658   {
1659      vcos_log_error("%s: Failed to create preview component", __func__);
1660      destroy_camera_component(state);
1661      return NULL;
1662   }
1663
1664   state->encoded_buffer_q = mmal_queue_create();
1665
1666   return state;
1667 }
1668
1669 gboolean
1670 raspi_capture_start(RASPIVID_STATE *state)
1671 {
1672   MMAL_STATUS_T status = MMAL_SUCCESS;
1673   RASPIVID_CONFIG *config = &state->config;
1674
1675   MMAL_PORT_T *camera_preview_port = NULL;
1676   MMAL_PORT_T *preview_input_port = NULL;
1677   MMAL_PORT_T *encoder_input_port = NULL;
1678
1679   MMAL_POOL_T *pool;
1680
1681   if ((status = create_encoder_component(state)) != MMAL_SUCCESS) {
1682     vcos_log_error("%s: Failed to create encode component", __func__);
1683     return FALSE;
1684   }
1685
1686   if (config->verbose)
1687   {
1688      dump_state(state);
1689   }
1690
1691   state->camera_video_port   = state->camera_component->output[MMAL_CAMERA_VIDEO_PORT];
1692   state->camera_still_port   = state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
1693   camera_preview_port = state->camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
1694   preview_input_port  = state->preview_state.preview_component->input[0];
1695
1696   if (state->encoder_component) {
1697     encoder_input_port  = state->encoder_component->input[0];
1698     state->encoder_output_port = state->encoder_component->output[0];
1699   } else {
1700     state->encoder_output_port = state->camera_video_port;
1701   }
1702
1703   if ((status = raspi_capture_set_format_and_start(state)) != MMAL_SUCCESS) {
1704      return FALSE;
1705   }
1706
1707   GST_DEBUG ("Creating pool of %d buffers of size %d",
1708       state->encoder_output_port->buffer_num, state->encoder_output_port->buffer_size);
1709   /* Create pool of buffer headers for the output port to consume */
1710   pool = mmal_port_pool_create(state->encoder_output_port,
1711              state->encoder_output_port->buffer_num, state->encoder_output_port->buffer_size);
1712   if (!pool)
1713   {
1714     vcos_log_error("Failed to create buffer header pool for encoder output port %s",
1715          state->encoder_output_port->name);
1716     return FALSE;
1717   }
1718   state->encoder_pool = pool;
1719
1720   if (state->config.verbose)
1721      fprintf(stderr, "Starting component connection stage\n");
1722
1723   if (config->preview_parameters.wantPreview )
1724   {
1725      if (config->verbose)
1726      {
1727         fprintf(stderr, "Connecting camera preview port to preview input port\n");
1728         fprintf(stderr, "Starting video preview\n");
1729      }
1730
1731      // Connect camera to preview
1732      status = connect_ports(camera_preview_port, preview_input_port, &state->preview_connection);
1733      if (status != MMAL_SUCCESS)
1734      {
1735         vcos_log_error("%s: Failed to connect camera to preview", __func__);
1736         return FALSE;
1737      }
1738   }
1739
1740   if (state->encoder_component) {
1741     if (config->verbose)
1742        fprintf(stderr, "Connecting camera video port to encoder input port\n");
1743
1744     // Now connect the camera to the encoder
1745     status = connect_ports(state->camera_video_port, encoder_input_port, &state->encoder_connection);
1746     if (status != MMAL_SUCCESS)
1747     {
1748       if (config->preview_parameters.wantPreview )
1749         mmal_connection_destroy(state->preview_connection);
1750       vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__);
1751       return FALSE;
1752     }
1753   }
1754
1755   // Set up our userdata - this is passed though to the callback where we need the information.
1756   state->callback_data.state = state;
1757   state->callback_data.abort = 0;
1758
1759   state->encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&state->callback_data;
1760
1761   if (config->verbose)
1762      fprintf(stderr, "Enabling encoder output port\n");
1763
1764   // Enable the encoder output port and tell it its callback function
1765   status = mmal_port_enable(state->encoder_output_port, encoder_buffer_callback);
1766   if (status != MMAL_SUCCESS)
1767   {
1768      vcos_log_error("Failed to setup encoder output");
1769      goto error;
1770   }
1771
1772   if (config->demoMode)
1773   {
1774      // Run for the user specific time..
1775      int num_iterations = config->timeout / config->demoInterval;
1776      int i;
1777
1778      if (config->verbose)
1779         fprintf(stderr, "Running in demo mode\n");
1780
1781      for (i=0;config->timeout == 0 || i<num_iterations;i++)
1782      {
1783         raspicamcontrol_cycle_test(state->camera_component);
1784         vcos_sleep(state->config.demoInterval);
1785      }
1786   }
1787
1788   if (config->verbose)
1789     fprintf(stderr, "Starting video capture\n");
1790
1791   if (mmal_port_parameter_set_boolean(state->camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
1792   {
1793      goto error;
1794   }
1795
1796   // Send all the buffers to the encoder output port
1797   {
1798      int num = mmal_queue_length(state->encoder_pool->queue);
1799      int q;
1800      for (q=0;q<num;q++)
1801      {
1802         MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->encoder_pool->queue);
1803
1804         if (!buffer)
1805            vcos_log_error("Unable to get a required buffer %d from pool queue", q);
1806
1807         if (mmal_port_send_buffer(state->encoder_output_port, buffer)!= MMAL_SUCCESS)
1808            vcos_log_error("Unable to send a buffer to encoder output port (%d)", q);
1809
1810      }
1811   }
1812
1813   // Now wait until we need to stop. Whilst waiting we do need to check to see if we have aborted (for example
1814   // out of storage space)
1815   // Going to check every ABORT_INTERVAL milliseconds
1816
1817 #if 0
1818   for (wait = 0; config->timeout == 0 || wait < config->timeout; wait+= ABORT_INTERVAL)
1819   {
1820      vcos_sleep(ABORT_INTERVAL);
1821      if (state->callback_data.abort)
1822         break;
1823   }
1824
1825   if (config->verbose)
1826      fprintf(stderr, "Finished capture\n");
1827 #endif
1828
1829   return (status == MMAL_SUCCESS);
1830
1831 error:
1832   raspi_capture_stop(state);
1833
1834   if (status != MMAL_SUCCESS) {
1835     mmal_status_to_int(status);
1836     raspicamcontrol_check_configuration(128);
1837   }
1838
1839   return FALSE;
1840 }
1841
1842 void
1843 raspi_capture_stop(RASPIVID_STATE *state)
1844 {
1845    RASPIVID_CONFIG *config = &state->config;
1846
1847   if (config->verbose)
1848      fprintf(stderr, "Closing down\n");
1849
1850   if (config->preview_parameters.wantPreview )
1851      mmal_connection_destroy(state->preview_connection);
1852
1853   // Disable all our ports that are not handled by connections
1854   check_disable_port(state->camera_still_port);
1855   check_disable_port(state->encoder_output_port);
1856
1857   if (state->encoder_component) {
1858      mmal_connection_destroy(state->encoder_connection);
1859      mmal_component_disable(state->encoder_component);
1860      destroy_encoder_component(state);
1861   }
1862 }
1863
1864 void
1865 raspi_capture_free(RASPIVID_STATE *state)
1866 {
1867    RASPIVID_CONFIG *config = &state->config;
1868
1869   // Can now close our file. Note disabling ports may flush buffers which causes
1870   // problems if we have already closed the file!
1871   if (state->output_file && state->output_file != stdout)
1872      fclose(state->output_file);
1873
1874   /* Disable components */
1875   if (state->encoder_component)
1876      mmal_component_disable(state->encoder_component);
1877
1878   if (state->preview_state.preview_component)
1879      mmal_component_disable(state->preview_state.preview_component);
1880
1881   if (state->camera_component)
1882      mmal_component_disable(state->camera_component);
1883
1884   destroy_encoder_component(state);
1885   raspipreview_destroy(&state->preview_state);
1886   destroy_camera_component(state);
1887
1888   if (state->encoded_buffer_q) {
1889     mmal_queue_destroy(state->encoded_buffer_q);
1890     state->encoded_buffer_q = NULL;
1891   }
1892
1893   if (config->verbose)
1894      fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
1895
1896   free(state);
1897 }
1898
1899 void
1900 raspi_capture_update_config (RASPIVID_STATE *state, RASPIVID_CONFIG *config, gboolean dynamic)
1901 {
1902   MMAL_STATUS_T status;
1903   RASPICAM_CAMERA_PARAMETERS *params = &config->camera_parameters;
1904   MMAL_COMPONENT_T *camera = state->camera_component;
1905
1906   /* Store the new config */
1907   state->config = *config;
1908   if (!dynamic)
1909     return;
1910
1911   if (state->encoder_component && config->change_flags & PROP_CHANGE_ENCODING) {
1912     /* BITRATE or QUANT or KEY Interval, intra refresh */
1913     MMAL_COMPONENT_T *encoder = state->encoder_component;
1914     MMAL_PORT_T *encoder_output = encoder->output[0];
1915
1916     status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_VIDEO_BIT_RATE, config->bitrate);
1917     if (status != MMAL_SUCCESS)
1918       vcos_log_warn("Unable to change bitrate dynamically");
1919
1920     {
1921       MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, config->intraperiod};
1922       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1923       if (status != MMAL_SUCCESS)
1924         vcos_log_warn("Unable to change intraperiod dynamically");
1925     }
1926
1927 #if 0 /* not dynamically change-able */
1928     {
1929       MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, config->quantisationParameter};
1930       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1931       if (status != MMAL_SUCCESS)
1932         vcos_log_warn("Unable to change Initial Quantisation Parameter dynamically");
1933
1934       MMAL_PARAMETER_UINT32_T param2 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, sizeof(param)}, config->quantisationParameter};
1935       status = mmal_port_parameter_set(encoder_output, &param2.hdr);
1936       if (status != MMAL_SUCCESS)
1937         vcos_log_warn("Unable to change Minimum Quantisation Parameter dynamically");
1938
1939       MMAL_PARAMETER_UINT32_T param3 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, sizeof(param)}, config->quantisationParameter};
1940       status = mmal_port_parameter_set(encoder_output, &param3.hdr);
1941       if (status != MMAL_SUCCESS)
1942         vcos_log_warn("Unable to change Maximum Quantisation Parameter dynamically");
1943     }
1944
1945     {
1946       // Adaptive intra refresh settings
1947       MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T  param;
1948       param.hdr.id = MMAL_PARAMETER_VIDEO_INTRA_REFRESH;
1949       param.hdr.size = sizeof(param);
1950
1951       // Get first so we don't overwrite anything unexpectedly
1952       status = mmal_port_parameter_get(encoder_output, &param.hdr);
1953       if (state != MMAL_SUCCESS) {
1954         /* Need to memset, apparently mmal_port_parameter_get()
1955          * doesn't retrieve all parameters, causing random failures
1956          * when we set it. On older firmware the get fails.
1957          */
1958         memset (&param, 0, sizeof (MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T));
1959       }
1960       param.refresh_mode = config->intra_refresh_type;
1961
1962       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1963       if (status != MMAL_SUCCESS)
1964          vcos_log_warn("Unable to set H264 intra-refresh values dynamically");
1965     }
1966 #endif
1967   }
1968   if (config->change_flags & PROP_CHANGE_PREVIEW) {
1969     /* Preview settings or fullscreen */
1970     status = raspipreview_update_config (&state->preview_state,
1971         &config->preview_parameters);
1972     if (status != MMAL_SUCCESS)
1973       vcos_log_warn("Unable to change preview config dynamically");
1974   }
1975   if (config->change_flags & PROP_CHANGE_COLOURBALANCE) {
1976     raspicamcontrol_set_saturation(camera, params->saturation);
1977     raspicamcontrol_set_sharpness(camera, params->sharpness);
1978     raspicamcontrol_set_contrast(camera, params->contrast);
1979     raspicamcontrol_set_brightness(camera, params->brightness);
1980   }
1981   if (config->change_flags & PROP_CHANGE_SENSOR_SETTINGS) {
1982     /* ISO, EXPOSURE, SHUTTER, DRC, Sensor Mode */
1983     raspicamcontrol_set_ISO(camera, params->ISO);
1984     raspicamcontrol_set_exposure_compensation(camera, params->exposureCompensation);
1985     raspicamcontrol_set_exposure_mode(camera, params->exposureMode);
1986     raspicamcontrol_set_metering_mode(camera, params->exposureMeterMode);
1987     raspicamcontrol_set_shutter_speed(camera, params->shutter_speed);
1988     raspicamcontrol_set_DRC(camera, params->drc_level);
1989
1990     /* Can we change sensor mode on the fly? Disable if not */
1991     status = mmal_port_parameter_set_uint32(camera->control,
1992        MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, config->sensor_mode);
1993     if (status != MMAL_SUCCESS)
1994       vcos_log_warn("Unable to change sensor mode dynamically");
1995   }
1996   if (config->change_flags & PROP_CHANGE_VIDEO_STABILISATION) {
1997     raspicamcontrol_set_video_stabilisation(camera, params->videoStabilisation);
1998   }
1999   if (config->change_flags & PROP_CHANGE_AWB) {
2000     raspicamcontrol_set_awb_mode(camera, params->awbMode);
2001     raspicamcontrol_set_awb_gains(camera, params->awb_gains_r, params->awb_gains_b);
2002   }
2003   if (config->change_flags & PROP_CHANGE_IMAGE_COLOUR_EFFECT) {
2004     raspicamcontrol_set_imageFX(camera, params->imageEffect);
2005     raspicamcontrol_set_colourFX(camera, &params->colourEffects);
2006   }
2007   if (config->change_flags & PROP_CHANGE_ORIENTATION) {
2008     raspicamcontrol_set_rotation(camera, params->rotation);
2009     raspicamcontrol_set_flips(camera, params->hflip, params->vflip);
2010   }
2011   if (config->change_flags & PROP_CHANGE_ROI) {
2012     raspicamcontrol_set_ROI(camera, params->roi);
2013   }
2014   if (config->change_flags & PROP_CHANGE_ANNOTATION)
2015     update_annotation_data(state);
2016 }