rpicamsrc: Implement use-stc property to disable STC timestamps
[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
756    {
757       vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd);
758    }
759
760    mmal_buffer_header_release(buffer);
761 }
762
763 #if 0
764 /**
765  * Open a file based on the settings in state
766  *
767  * @param state Pointer to state
768  */
769 static FILE *open_filename(RASPIVID_STATE *pState)
770 {
771    FILE *new_handle = NULL;
772    char *tempname = NULL, *filename = NULL;
773
774    if (pState->segmentSize || pState->splitWait)
775    {
776       // Create a new filename string
777       asprintf(&tempname, pState->filename, pState->segmentNumber);
778       filename = tempname;
779    }
780    else
781    {
782       filename = pState->filename;
783    }
784
785    if (filename)
786       new_handle = fopen(filename, "wb");
787
788    if (pState->verbose)
789    {
790       if (new_handle)
791          fprintf(stderr, "Opening output file \"%s\"\n", filename);
792       else
793          fprintf(stderr, "Failed to open new file \"%s\"\n", filename);
794    }
795
796    if (tempname)
797       free(tempname);
798
799    return new_handle;
800 }
801
802 /**
803  * Open a file based on the settings in state
804  *
805  * This time for the imv output file
806  *
807  * @param state Pointer to state
808  */
809 static FILE *open_imv_filename(RASPIVID_STATE *pState)
810 {
811    FILE *new_handle = NULL;
812    char *tempname = NULL, *filename = NULL;
813
814    if (pState->segmentSize || pState->splitWait)
815    {
816       // Create a new filename string
817       asprintf(&tempname, pState->imv_filename, pState->segmentNumber);
818       filename = tempname;
819    }
820    else
821    {
822       filename = pState->imv_filename;
823    }
824
825    if (filename)
826       new_handle = fopen(filename, "wb");
827
828    if (pState->verbose)
829    {
830       if (new_handle)
831          fprintf(stderr, "Opening imv output file \"%s\"\n", filename);
832       else
833          fprintf(stderr, "Failed to open new imv file \"%s\"\n", filename);
834    }
835
836    if (tempname)
837       free(tempname);
838
839    return new_handle;
840 }
841 #endif
842
843 /**
844  * Update any annotation data specific to the video.
845  * This simply passes on the setting from cli, or
846  * if application defined annotate requested, updates
847  * with the H264 parameters
848  *
849  * @param state Pointer to state control struct
850  *
851  */
852 static void update_annotation_data(RASPIVID_STATE *state)
853 {
854    RASPIVID_CONFIG *config = &state->config;
855
856    // So, if we have asked for a application supplied string, set it to the H264 parameters
857    if (config->camera_parameters.enable_annotate & ANNOTATE_APP_TEXT)
858    {
859       char *text;
860       const char *refresh = raspicli_unmap_xref(config->intra_refresh_type, intra_refresh_map, intra_refresh_map_size);
861
862       asprintf(&text,  "%dk,%ff,%s,%d,%s",
863             config->bitrate / 1000,  ((float)(config->fps_n) / config->fps_d),
864             refresh ? refresh : "(none)",
865             config->intraperiod,
866             raspicli_unmap_xref(config->profile, profile_map, profile_map_size));
867
868       raspicamcontrol_set_annotate(state->camera_component, config->camera_parameters.enable_annotate, text,
869                        config->camera_parameters.annotate_text_size,
870                        config->camera_parameters.annotate_text_colour,
871                        config->camera_parameters.annotate_bg_colour);
872
873       free(text);
874    }
875    else
876    {
877       raspicamcontrol_set_annotate(state->camera_component, config->camera_parameters.enable_annotate,
878                        config->camera_parameters.annotate_string,
879                        config->camera_parameters.annotate_text_size,
880                        config->camera_parameters.annotate_text_colour,
881                        config->camera_parameters.annotate_bg_colour);
882    }
883 }
884
885
886
887 /**
888  *  buffer header callback function for encoder
889  *
890  *  Callback will dump buffer data to the specific file
891  *
892  * @param port Pointer to port from which callback originated
893  * @param buffer mmal buffer header pointer
894  */
895 static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
896 {
897    PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata;
898    RASPIVID_STATE *state  = pData->state;
899    int64_t current_time;
900
901    // All our segment times based on the receipt of the first encoder callback
902    if (state->base_time == -1)
903       state->base_time = vcos_getmicrosecs64()/1000;
904
905    if (pData == NULL)
906    {
907       vcos_log_error("Received a encoder buffer callback with no state");
908       // release buffer back to the pool
909       mmal_buffer_header_release(buffer);
910       return;
911    }
912
913    current_time = vcos_getmicrosecs64()/1000;
914    if (state->base_time == -1)
915      state->base_time = current_time;
916
917    // See if the second count has changed and we need to update any annotation
918    if (current_time/1000 != state->last_second)
919    {
920       update_annotation_data(state);
921       state->last_second = current_time/1000;
922    }
923
924    /* Send buffer to GStreamer element for pushing to the pipeline */
925    mmal_queue_put(state->encoded_buffer_q, buffer);
926 }
927
928 GstFlowReturn
929 raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **bufp,
930     GstClock *clock, GstClockTime base_time)
931 {
932   RASPIVID_CONFIG *config = &state->config;
933   GstBuffer *buf;
934   MMAL_BUFFER_HEADER_T *buffer;
935   GstFlowReturn ret = GST_FLOW_ERROR;
936   /* No timestamps if no clockm or invalid PTS */
937   GstClockTime gst_pts = GST_CLOCK_TIME_NONE;
938
939   /* FIXME: Use our own interruptible cond wait: */
940   buffer = mmal_queue_wait(state->encoded_buffer_q);
941
942
943   if (G_LIKELY (config->useSTC && clock)) {
944     MMAL_PARAMETER_INT64_T param;
945     GstClockTime runtime;
946
947     runtime = gst_clock_get_time (clock) - base_time;
948
949     param.hdr.id = MMAL_PARAMETER_SYSTEM_TIME;
950     param.hdr.size = sizeof(param);
951     param.value = -1;
952
953     mmal_port_parameter_get(state->encoder_output_port, &param.hdr);
954
955     if (buffer->pts != -1 && param.value != -1 && param.value >= buffer->pts) {
956       /* Convert microsecond RPi TS to GStreamer clock: */
957       GstClockTime offset = (param.value - buffer->pts) * 1000;
958       if (runtime >= offset)
959         gst_pts = runtime - offset;
960     }
961     GST_LOG ("Buf (uS) PTS %" G_GINT64_FORMAT " DTS %" G_GINT64_FORMAT
962         " STC %" G_GINT64_FORMAT " (latency %" G_GINT64_FORMAT
963         "uS) TS %" GST_TIME_FORMAT,
964         buffer->pts, buffer->dts, param.value, param.value - buffer->pts,
965         GST_TIME_ARGS (gst_pts));
966   }
967   else {
968     GST_LOG ("use-stc=false. Not applying STC to buffer");
969   }
970
971   mmal_buffer_header_mem_lock(buffer);
972   buf = gst_buffer_new_allocate(NULL, buffer->length, NULL);
973   if (buf) {
974     if (config->useSTC)
975         GST_BUFFER_DTS(buf) = GST_BUFFER_PTS(buf) = gst_pts;
976     /* FIXME: Can we avoid copies and give MMAL our own buffers to fill? */
977     gst_buffer_fill(buf, 0, buffer->data, buffer->length);
978     ret = GST_FLOW_OK;
979   }
980
981   mmal_buffer_header_mem_unlock(buffer);
982
983   *bufp = buf;
984   // release buffer back to the pool
985   mmal_buffer_header_release(buffer);
986
987   // and send one back to the port (if still open)
988   if (state->encoder_output_port->is_enabled)
989   {
990      MMAL_STATUS_T status = MMAL_SUCCESS;
991
992      buffer = mmal_queue_get(state->encoder_pool->queue);
993      if (buffer)
994         status = mmal_port_send_buffer(state->encoder_output_port, buffer);
995
996      if (!buffer || status != MMAL_SUCCESS) {
997        vcos_log_error("Unable to return a buffer to the encoder port");
998        ret = GST_FLOW_ERROR;
999      }
1000   }
1001
1002   return ret;
1003 }
1004
1005 /**
1006  * Create the camera component, set up its ports
1007  *
1008  * @param state Pointer to state control struct
1009  *
1010  * @return MMAL_SUCCESS if all OK, something else otherwise
1011  *
1012  */
1013 static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
1014 {
1015    MMAL_COMPONENT_T *camera = NULL;
1016    MMAL_STATUS_T status;
1017    RASPIVID_CONFIG *config = &state->config;
1018
1019    /* Create the component */
1020    status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
1021
1022    if (status != MMAL_SUCCESS)
1023    {
1024       vcos_log_error("Failed to create camera component");
1025       goto error;
1026    }
1027
1028    MMAL_PARAMETER_INT32_T camera_num =
1029       {{MMAL_PARAMETER_CAMERA_NUM, sizeof(camera_num)}, config->cameraNum};
1030
1031    status = mmal_port_parameter_set(camera->control, &camera_num.hdr);
1032
1033    if (status != MMAL_SUCCESS)
1034    {
1035       vcos_log_error("Could not select camera : error %d", status);
1036       goto error;
1037    }
1038
1039    if (!camera->output_num)
1040    {
1041       status = MMAL_ENOSYS;
1042       vcos_log_error("Camera doesn't have output ports");
1043       goto error;
1044    }
1045
1046    status = mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, config->sensor_mode);
1047
1048    if (status != MMAL_SUCCESS)
1049    {
1050       vcos_log_error("Could not set sensor mode : error %d", status);
1051       goto error;
1052    }
1053
1054    if (config->settings)
1055    {
1056       MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T change_event_request =
1057          {{MMAL_PARAMETER_CHANGE_EVENT_REQUEST, sizeof(MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T)},
1058           MMAL_PARAMETER_CAMERA_SETTINGS, 1};
1059
1060       status = mmal_port_parameter_set(camera->control, &change_event_request.hdr);
1061       if ( status != MMAL_SUCCESS )
1062       {
1063          vcos_log_error("No camera settings events");
1064       }
1065    }
1066
1067    // Enable the camera, and tell it its control callback function
1068    status = mmal_port_enable(camera->control, camera_control_callback);
1069
1070    if (status != MMAL_SUCCESS)
1071    {
1072       vcos_log_error("Unable to enable control port : error %d", status);
1073       goto error;
1074    }
1075
1076    state->camera_component = camera;
1077
1078    return status;
1079
1080 error:
1081    if (camera)
1082      mmal_component_destroy(camera);
1083
1084    return status;
1085 }
1086
1087 MMAL_STATUS_T
1088 raspi_capture_set_format_and_start(RASPIVID_STATE *state)
1089 {
1090    MMAL_COMPONENT_T *camera = NULL;
1091    MMAL_STATUS_T status;
1092    MMAL_ES_FORMAT_T *format;
1093    MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL;
1094    RASPIVID_CONFIG *config = &state->config;
1095
1096    //  set up the camera configuration
1097
1098    MMAL_PARAMETER_CAMERA_CONFIG_T cam_config =
1099    {
1100       { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) },
1101       .max_stills_w = config->width,
1102       .max_stills_h = config->height,
1103       .stills_yuv422 = 0,
1104       .one_shot_stills = 0,
1105       .max_preview_video_w = config->width,
1106       .max_preview_video_h = config->height,
1107       .num_preview_video_frames = 3,
1108       .stills_capture_circular_buffer_height = 0,
1109       .fast_preview_resume = 0,
1110       .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RAW_STC
1111    };
1112
1113    camera = state->camera_component;
1114    preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT];
1115    video_port = camera->output[MMAL_CAMERA_VIDEO_PORT];
1116    still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT];
1117
1118    mmal_port_parameter_set(camera->control, &cam_config.hdr);
1119
1120    // Now set up the port formats
1121
1122    // Set the encode format on the Preview port
1123    // HW limitations mean we need the preview to be the same size as the required recorded output
1124
1125    format = preview_port->format;
1126
1127    if(config->camera_parameters.shutter_speed > 6000000)
1128    {
1129         MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
1130                                                      { 50, 1000 }, {166, 1000}};
1131         mmal_port_parameter_set(preview_port, &fps_range.hdr);
1132    }
1133    else if(config->camera_parameters.shutter_speed > 1000000)
1134    {
1135         MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
1136                                                      { 166, 1000 }, {999, 1000}};
1137         mmal_port_parameter_set(preview_port, &fps_range.hdr);
1138    }
1139
1140    //enable dynamic framerate if necessary
1141    if (config->camera_parameters.shutter_speed)
1142    {
1143       if (((float)(config->fps_n) / config->fps_d) > 1000000.0 / config->camera_parameters.shutter_speed)
1144       {
1145          config->fps_n = 0;
1146          config->fps_d = 1;
1147          GST_INFO ("Enabling dynamic frame rate to fulfil shutter speed requirement");
1148       }
1149    }
1150
1151    format->encoding = MMAL_ENCODING_OPAQUE;
1152    format->encoding_variant = MMAL_ENCODING_I420;
1153
1154    format->es->video.width = VCOS_ALIGN_UP(config->width, 32);
1155    format->es->video.height = VCOS_ALIGN_UP(config->height, 16);
1156    format->es->video.crop.x = 0;
1157    format->es->video.crop.y = 0;
1158    format->es->video.crop.width = config->width;
1159    format->es->video.crop.height = config->height;
1160    format->es->video.frame_rate.num = config->fps_n;
1161    format->es->video.frame_rate.den = config->fps_d;
1162
1163    status = mmal_port_format_commit(preview_port);
1164
1165    if (status != MMAL_SUCCESS)
1166    {
1167       vcos_log_error("camera viewfinder format couldn't be set");
1168       goto error;
1169    }
1170
1171    // Set the encode format on the video  port
1172    format = video_port->format;
1173
1174    if(config->camera_parameters.shutter_speed > 6000000)
1175    {
1176         MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
1177                                                      { 50, 1000 }, {166, 1000}};
1178         mmal_port_parameter_set(video_port, &fps_range.hdr);
1179    }
1180    else if(config->camera_parameters.shutter_speed > 1000000)
1181    {
1182         MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
1183                                                      { 167, 1000 }, {999, 1000}};
1184         mmal_port_parameter_set(video_port, &fps_range.hdr);
1185    }
1186
1187    /* If encoding, set opaque tunneling format */
1188    if (state->encoder_component) {
1189      format->encoding = MMAL_ENCODING_OPAQUE;
1190      format->encoding_variant = MMAL_ENCODING_I420;
1191    }
1192    else {
1193      format->encoding = config->encoding;
1194      format->encoding_variant = config->encoding;
1195    }
1196
1197    format->es->video.width = VCOS_ALIGN_UP(config->width, 32);
1198    format->es->video.height = VCOS_ALIGN_UP(config->height, 16);
1199    format->es->video.crop.x = 0;
1200    format->es->video.crop.y = 0;
1201    format->es->video.crop.width = config->width;
1202    format->es->video.crop.height = config->height;
1203    format->es->video.frame_rate.num = config->fps_n;
1204    format->es->video.frame_rate.den = config->fps_d;
1205
1206    status = mmal_port_format_commit(video_port);
1207
1208    if (status != MMAL_SUCCESS)
1209    {
1210       vcos_log_error("camera video format couldn't be set");
1211       goto error;
1212    }
1213
1214    // Ensure there are enough buffers to avoid dropping frames
1215    if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
1216       video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
1217
1218
1219    // Set the encode format on the still  port
1220
1221    format = still_port->format;
1222
1223    format->encoding = MMAL_ENCODING_OPAQUE;
1224    format->encoding_variant = MMAL_ENCODING_I420;
1225
1226    format->es->video.width = VCOS_ALIGN_UP(config->width, 32);
1227    format->es->video.height = VCOS_ALIGN_UP(config->height, 16);
1228    format->es->video.crop.x = 0;
1229    format->es->video.crop.y = 0;
1230    format->es->video.crop.width = config->width;
1231    format->es->video.crop.height = config->height;
1232    format->es->video.frame_rate.num = 0;
1233    format->es->video.frame_rate.den = 1;
1234
1235    status = mmal_port_format_commit(still_port);
1236
1237    if (status != MMAL_SUCCESS)
1238    {
1239       vcos_log_error("camera still format couldn't be set");
1240       goto error;
1241    }
1242
1243    /* Ensure there are enough buffers to avoid dropping frames */
1244    if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
1245       still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
1246
1247    /* Enable component */
1248    status = mmal_component_enable(camera);
1249
1250    if (status != MMAL_SUCCESS)
1251    {
1252       vcos_log_error("camera component couldn't be enabled");
1253       goto error;
1254    }
1255
1256    raspicamcontrol_set_all_parameters(camera, &config->camera_parameters);
1257
1258    update_annotation_data(state);
1259
1260    if (config->verbose)
1261       fprintf(stderr, "Camera component done\n");
1262
1263    return status;
1264
1265 error:
1266
1267    if (camera)
1268       mmal_component_destroy(camera);
1269
1270    return status;
1271 }
1272
1273 /**
1274  * Destroy the camera component
1275  *
1276  * @param state Pointer to state control struct
1277  *
1278  */
1279 static void destroy_camera_component(RASPIVID_STATE *state)
1280 {
1281    if (state->camera_component)
1282    {
1283       mmal_component_destroy(state->camera_component);
1284       state->camera_component = NULL;
1285    }
1286 }
1287
1288 gboolean raspi_capture_request_i_frame(RASPIVID_STATE *state)
1289 {
1290    MMAL_PORT_T *encoder_output = NULL;
1291    MMAL_STATUS_T status;
1292    MMAL_PARAMETER_BOOLEAN_T param = {{  MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME, sizeof(param)}, 1};
1293
1294    if (state->encoder_component)
1295      return TRUE;
1296
1297    encoder_output = state->encoder_component->output[0];
1298    status = mmal_port_parameter_set(encoder_output, &param.hdr);
1299    if (status != MMAL_SUCCESS)
1300    {
1301       vcos_log_error("Unable to request I-frame");
1302       return FALSE;
1303    }
1304    return TRUE;
1305 }
1306
1307 /**
1308  * Create the encoder component, set up its ports
1309  *
1310  * @param state Pointer to state control struct
1311  *
1312  * @return MMAL_SUCCESS if all OK, something else otherwise
1313  *
1314  */
1315 static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
1316 {
1317    MMAL_COMPONENT_T *encoder = 0;
1318    MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL;
1319    MMAL_STATUS_T status;
1320    RASPIVID_CONFIG *config = &state->config;
1321
1322    gboolean encoded_format =
1323      (config->encoding == MMAL_ENCODING_H264 ||
1324       config->encoding == MMAL_ENCODING_MJPEG ||
1325       config->encoding == MMAL_ENCODING_JPEG);
1326
1327    if (!encoded_format)
1328      return MMAL_SUCCESS;
1329
1330    if (config->encoding == MMAL_ENCODING_JPEG)
1331      status = mmal_component_create(MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER, &encoder);
1332    else
1333      status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, &encoder);
1334
1335    if (status != MMAL_SUCCESS) {
1336      vcos_log_error("Unable to create video encoder component");
1337      goto error;
1338    }
1339
1340    if (!encoder->input_num || !encoder->output_num)
1341    {
1342       status = MMAL_ENOSYS;
1343       vcos_log_error("Video encoder doesn't have input/output ports");
1344       goto error;
1345    }
1346
1347    encoder_input = encoder->input[0];
1348    encoder_output = encoder->output[0];
1349
1350    // We want same format on input and output
1351    mmal_format_copy(encoder_output->format, encoder_input->format);
1352
1353    // Configure desired encoding
1354    encoder_output->format->encoding = config->encoding;
1355
1356    encoder_output->format->bitrate = config->bitrate;
1357
1358    if (config->encoding == MMAL_ENCODING_H264)
1359      encoder_output->buffer_size = encoder_output->buffer_size_recommended;
1360    else
1361      encoder_output->buffer_size = 256<<10;
1362
1363    if (encoder_output->buffer_size < encoder_output->buffer_size_min)
1364       encoder_output->buffer_size = encoder_output->buffer_size_min;
1365
1366    encoder_output->buffer_num = encoder_output->buffer_num_recommended;
1367
1368    if (encoder_output->buffer_num < encoder_output->buffer_num_min)
1369       encoder_output->buffer_num = encoder_output->buffer_num_min;
1370
1371    GST_DEBUG ("encoder wants %d buffers of size %u",
1372        (guint)encoder_output->buffer_num, (guint)encoder_output->buffer_size);
1373
1374    // We need to set the frame rate on output to 0, to ensure it gets
1375    // updated correctly from the input framerate when port connected
1376    encoder_output->format->es->video.frame_rate.num = 0;
1377    encoder_output->format->es->video.frame_rate.den = 1;
1378
1379    // Commit the port changes to the output port
1380    status = mmal_port_format_commit(encoder_output);
1381    if (status != MMAL_SUCCESS) {
1382       vcos_log_error("Unable to set format on video encoder output port");
1383       goto error;
1384    }
1385
1386    // Set the rate control parameter
1387    if (0)
1388    {
1389       MMAL_PARAMETER_VIDEO_RATECONTROL_T param = {{ MMAL_PARAMETER_RATECONTROL, sizeof(param)}, MMAL_VIDEO_RATECONTROL_DEFAULT};
1390       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1391       if (status != MMAL_SUCCESS)
1392       {
1393          vcos_log_error("Unable to set ratecontrol");
1394          goto error;
1395       }
1396
1397    }
1398
1399    if (config->encoding == MMAL_ENCODING_H264 && config->intraperiod != -1)
1400    {
1401       MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, config->intraperiod};
1402       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1403       if (status != MMAL_SUCCESS)
1404       {
1405          vcos_log_error("Unable to set intraperiod");
1406          goto error;
1407       }
1408    }
1409
1410    if (config->encoding == MMAL_ENCODING_H264 && config->quantisationParameter)
1411    {
1412       MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, config->quantisationParameter};
1413       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1414       if (status != MMAL_SUCCESS)
1415       {
1416          vcos_log_error("Unable to set initial QP");
1417          goto error;
1418       }
1419
1420       MMAL_PARAMETER_UINT32_T param2 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, sizeof(param)}, config->quantisationParameter};
1421       status = mmal_port_parameter_set(encoder_output, &param2.hdr);
1422       if (status != MMAL_SUCCESS)
1423       {
1424          vcos_log_error("Unable to set min QP");
1425          goto error;
1426       }
1427
1428       MMAL_PARAMETER_UINT32_T param3 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, sizeof(param)}, config->quantisationParameter};
1429       status = mmal_port_parameter_set(encoder_output, &param3.hdr);
1430       if (status != MMAL_SUCCESS)
1431       {
1432          vcos_log_error("Unable to set max QP");
1433          goto error;
1434       }
1435    }
1436
1437    if (config->encoding == MMAL_ENCODING_H264)
1438    {
1439       MMAL_PARAMETER_VIDEO_PROFILE_T  param;
1440       param.hdr.id = MMAL_PARAMETER_PROFILE;
1441       param.hdr.size = sizeof(param);
1442
1443       param.profile[0].profile = config->profile;
1444       param.profile[0].level = MMAL_VIDEO_LEVEL_H264_4; // This is the only value supported
1445
1446       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1447       if (status != MMAL_SUCCESS)
1448       {
1449          vcos_log_error("Unable to set H264 profile");
1450          goto error;
1451       }
1452    }
1453
1454    if (config->encoding != MMAL_ENCODING_JPEG)
1455    {
1456      if (mmal_port_parameter_set_boolean(encoder_input, MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, config->immutableInput) != MMAL_SUCCESS)
1457      {
1458         vcos_log_error("Unable to set immutable input flag");
1459         // Continue rather than abort..
1460      }
1461
1462      //set INLINE HEADER flag to generate SPS and PPS for every IDR if requested
1463      if (mmal_port_parameter_set_boolean(encoder_output, MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, config->bInlineHeaders) != MMAL_SUCCESS)
1464      {
1465         vcos_log_error("failed to set INLINE HEADER FLAG parameters");
1466         // Continue rather than abort..
1467      }
1468   }
1469
1470   if (config->encoding == MMAL_ENCODING_H264)
1471   {
1472      //set INLINE VECTORS flag to request motion vector estimates
1473      if (mmal_port_parameter_set_boolean(encoder_output, MMAL_PARAMETER_VIDEO_ENCODE_INLINE_VECTORS, config->inlineMotionVectors) != MMAL_SUCCESS)
1474      {
1475         vcos_log_error("failed to set INLINE VECTORS parameters");
1476         // Continue rather than abort..
1477      }
1478
1479      // Adaptive intra refresh settings
1480      if (config->intra_refresh_type != -1)
1481      {
1482         MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T  param;
1483
1484         /* Need to memset, apparently mmal_port_parameter_get()
1485          * doesn't retrieve all parameters, causing random failures
1486          * when we set it
1487          */
1488         memset (&param, 0, sizeof (MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T));
1489
1490         param.hdr.id = MMAL_PARAMETER_VIDEO_INTRA_REFRESH;
1491         param.hdr.size = sizeof(param);
1492
1493         // Get first so we don't overwrite anything unexpectedly
1494         status = mmal_port_parameter_get(encoder_output, &param.hdr);
1495
1496         param.refresh_mode = config->intra_refresh_type;
1497
1498         //if (state->intra_refresh_type == MMAL_VIDEO_INTRA_REFRESH_CYCLIC_MROWS)
1499         //   param.cir_mbs = 10;
1500
1501         status = mmal_port_parameter_set(encoder_output, &param.hdr);
1502         if (status != MMAL_SUCCESS)
1503         {
1504          vcos_log_error("Unable to set H264 intra-refresh values");
1505            goto error;
1506         }
1507      }
1508    }
1509
1510    if (config->encoding == MMAL_ENCODING_JPEG)
1511    {
1512       status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_Q_FACTOR, config->jpegQuality);
1513       if (status != MMAL_SUCCESS) {
1514          vcos_log_error("Unable to set JPEG quality");
1515          // Continue after warning
1516       }
1517
1518 #ifdef MMAL_PARAMETER_JPEG_RESTART_INTERVAL
1519       status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_RESTART_INTERVAL, config->jpegRestartInterval);
1520       if (status != MMAL_SUCCESS) {
1521          vcos_log_error("Unable to set JPEG restart interval");
1522          // Continue after warning
1523       }
1524 #endif
1525    }
1526
1527    //  Enable component
1528    status = mmal_component_enable(encoder);
1529
1530    if (status != MMAL_SUCCESS)
1531    {
1532       vcos_log_error("Unable to enable video encoder component");
1533       goto error;
1534    }
1535
1536    state->encoder_component = encoder;
1537
1538    if (config->verbose)
1539       fprintf(stderr, "Encoder component done\n");
1540
1541    return status;
1542
1543    error:
1544    if (encoder)
1545       mmal_component_destroy(encoder);
1546
1547    state->encoder_component = NULL;
1548
1549    return status;
1550 }
1551
1552 /**
1553  * Destroy the encoder component
1554  *
1555  * @param state Pointer to state control struct
1556  *
1557  */
1558 static void destroy_encoder_component(RASPIVID_STATE *state)
1559 {
1560   /* Empty the buffer header q */
1561    if (state->encoded_buffer_q) {
1562       while (mmal_queue_length(state->encoded_buffer_q)) {
1563         MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->encoded_buffer_q);
1564         mmal_buffer_header_release(buffer);
1565       }
1566    }
1567
1568    // Get rid of any port buffers first
1569    if (state->encoder_pool)
1570    {
1571       mmal_port_pool_destroy(state->encoder_output_port, state->encoder_pool);
1572       state->encoder_pool = NULL;
1573    }
1574
1575    if (state->encoder_component) {
1576
1577       mmal_component_destroy(state->encoder_component);
1578       state->encoder_component = NULL;
1579    }
1580 }
1581
1582 /**
1583  * Connect two specific ports together
1584  *
1585  * @param output_port Pointer the output port
1586  * @param input_port Pointer the input port
1587  * @param Pointer to a mmal connection pointer, reassigned if function successful
1588  * @return Returns a MMAL_STATUS_T giving result of operation
1589  *
1590  */
1591 static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection)
1592 {
1593    MMAL_STATUS_T status;
1594
1595    status =  mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT);
1596
1597    if (status == MMAL_SUCCESS)
1598    {
1599       status =  mmal_connection_enable(*connection);
1600       if (status != MMAL_SUCCESS)
1601          mmal_connection_destroy(*connection);
1602    }
1603
1604    return status;
1605 }
1606
1607 /**
1608  * Checks if specified port is valid and enabled, then disables it
1609  *
1610  * @param port  Pointer the port
1611  *
1612  */
1613 static void check_disable_port(MMAL_PORT_T *port)
1614 {
1615    if (port && port->is_enabled)
1616       mmal_port_disable(port);
1617 }
1618
1619 void raspicapture_init()
1620 {
1621    bcm_host_init();
1622
1623    // Register our application with the logging system
1624    vcos_log_register("RaspiVid", VCOS_LOG_CATEGORY);
1625 }
1626
1627 RASPIVID_STATE *
1628 raspi_capture_setup(RASPIVID_CONFIG *config)
1629 {
1630   // Our main data storage vessel..
1631   RASPIVID_STATE *state;
1632
1633   MMAL_STATUS_T status = MMAL_SUCCESS;
1634
1635   /* Default everything to zero */
1636   state = calloc(1, sizeof(RASPIVID_STATE));
1637
1638   /* Apply passed in config */
1639   state->config = *config;
1640
1641   /* Initialize timestamping */
1642   state->base_time = state->last_second = -1;
1643
1644   /* So far, all we can do is create the camera component. Actual
1645    * config and connection of encoders etc happens in _start()
1646    */
1647   // OK, we have a nice set of parameters. Now set up our components
1648   // We have three components. Camera, Preview and encoder.
1649
1650   if ((status = create_camera_component(state)) != MMAL_SUCCESS)
1651   {
1652      vcos_log_error("%s: Failed to create camera component", __func__);
1653      return NULL;
1654   }
1655
1656   if ((status = raspipreview_create(&state->preview_state, &config->preview_parameters)) != MMAL_SUCCESS)
1657   {
1658      vcos_log_error("%s: Failed to create preview component", __func__);
1659      destroy_camera_component(state);
1660      return NULL;
1661   }
1662
1663   state->encoded_buffer_q = mmal_queue_create();
1664
1665   return state;
1666 }
1667
1668 gboolean
1669 raspi_capture_start(RASPIVID_STATE *state)
1670 {
1671   MMAL_STATUS_T status = MMAL_SUCCESS;
1672   RASPIVID_CONFIG *config = &state->config;
1673
1674   MMAL_PORT_T *camera_preview_port = NULL;
1675   MMAL_PORT_T *preview_input_port = NULL;
1676   MMAL_PORT_T *encoder_input_port = NULL;
1677
1678   MMAL_POOL_T *pool;
1679
1680   if ((status = create_encoder_component(state)) != MMAL_SUCCESS) {
1681     vcos_log_error("%s: Failed to create encode component", __func__);
1682     return FALSE;
1683   }
1684
1685   if (config->verbose)
1686   {
1687      dump_state(state);
1688   }
1689
1690   state->camera_video_port   = state->camera_component->output[MMAL_CAMERA_VIDEO_PORT];
1691   state->camera_still_port   = state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
1692   camera_preview_port = state->camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
1693   preview_input_port  = state->preview_state.preview_component->input[0];
1694
1695   if (state->encoder_component) {
1696     encoder_input_port  = state->encoder_component->input[0];
1697     state->encoder_output_port = state->encoder_component->output[0];
1698   } else {
1699     state->encoder_output_port = state->camera_video_port;
1700   }
1701
1702   if ((status = raspi_capture_set_format_and_start(state)) != MMAL_SUCCESS) {
1703      return FALSE;
1704   }
1705
1706   GST_DEBUG ("Creating pool of %d buffers of size %d",
1707       state->encoder_output_port->buffer_num, state->encoder_output_port->buffer_size);
1708   /* Create pool of buffer headers for the output port to consume */
1709   pool = mmal_port_pool_create(state->encoder_output_port,
1710              state->encoder_output_port->buffer_num, state->encoder_output_port->buffer_size);
1711   if (!pool)
1712   {
1713     vcos_log_error("Failed to create buffer header pool for encoder output port %s",
1714          state->encoder_output_port->name);
1715     return FALSE;
1716   }
1717   state->encoder_pool = pool;
1718
1719   if (state->config.verbose)
1720      fprintf(stderr, "Starting component connection stage\n");
1721
1722   if (config->preview_parameters.wantPreview )
1723   {
1724      if (config->verbose)
1725      {
1726         fprintf(stderr, "Connecting camera preview port to preview input port\n");
1727         fprintf(stderr, "Starting video preview\n");
1728      }
1729
1730      // Connect camera to preview
1731      status = connect_ports(camera_preview_port, preview_input_port, &state->preview_connection);
1732      if (status != MMAL_SUCCESS)
1733      {
1734         vcos_log_error("%s: Failed to connect camera to preview", __func__);
1735         return FALSE;
1736      }
1737   }
1738
1739   if (state->encoder_component) {
1740     if (config->verbose)
1741        fprintf(stderr, "Connecting camera video port to encoder input port\n");
1742
1743     // Now connect the camera to the encoder
1744     status = connect_ports(state->camera_video_port, encoder_input_port, &state->encoder_connection);
1745     if (status != MMAL_SUCCESS)
1746     {
1747       if (config->preview_parameters.wantPreview )
1748         mmal_connection_destroy(state->preview_connection);
1749       vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__);
1750       return FALSE;
1751     }
1752   }
1753
1754   // Set up our userdata - this is passed though to the callback where we need the information.
1755   state->callback_data.state = state;
1756   state->callback_data.abort = 0;
1757
1758   state->encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&state->callback_data;
1759
1760   if (config->verbose)
1761      fprintf(stderr, "Enabling encoder output port\n");
1762
1763   // Enable the encoder output port and tell it its callback function
1764   status = mmal_port_enable(state->encoder_output_port, encoder_buffer_callback);
1765   if (status != MMAL_SUCCESS)
1766   {
1767      vcos_log_error("Failed to setup encoder output");
1768      goto error;
1769   }
1770
1771   if (config->demoMode)
1772   {
1773      // Run for the user specific time..
1774      int num_iterations = config->timeout / config->demoInterval;
1775      int i;
1776
1777      if (config->verbose)
1778         fprintf(stderr, "Running in demo mode\n");
1779
1780      for (i=0;config->timeout == 0 || i<num_iterations;i++)
1781      {
1782         raspicamcontrol_cycle_test(state->camera_component);
1783         vcos_sleep(state->config.demoInterval);
1784      }
1785   }
1786
1787   if (config->verbose)
1788     fprintf(stderr, "Starting video capture\n");
1789
1790   if (mmal_port_parameter_set_boolean(state->camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
1791   {
1792      goto error;
1793   }
1794
1795   // Send all the buffers to the encoder output port
1796   {
1797      int num = mmal_queue_length(state->encoder_pool->queue);
1798      int q;
1799      for (q=0;q<num;q++)
1800      {
1801         MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->encoder_pool->queue);
1802
1803         if (!buffer)
1804            vcos_log_error("Unable to get a required buffer %d from pool queue", q);
1805
1806         if (mmal_port_send_buffer(state->encoder_output_port, buffer)!= MMAL_SUCCESS)
1807            vcos_log_error("Unable to send a buffer to encoder output port (%d)", q);
1808
1809      }
1810   }
1811
1812   // Now wait until we need to stop. Whilst waiting we do need to check to see if we have aborted (for example
1813   // out of storage space)
1814   // Going to check every ABORT_INTERVAL milliseconds
1815
1816 #if 0
1817   for (wait = 0; config->timeout == 0 || wait < config->timeout; wait+= ABORT_INTERVAL)
1818   {
1819      vcos_sleep(ABORT_INTERVAL);
1820      if (state->callback_data.abort)
1821         break;
1822   }
1823
1824   if (config->verbose)
1825      fprintf(stderr, "Finished capture\n");
1826 #endif
1827
1828   return (status == MMAL_SUCCESS);
1829
1830 error:
1831   raspi_capture_stop(state);
1832
1833   if (status != MMAL_SUCCESS) {
1834     mmal_status_to_int(status);
1835     raspicamcontrol_check_configuration(128);
1836   }
1837
1838   return FALSE;
1839 }
1840
1841 void
1842 raspi_capture_stop(RASPIVID_STATE *state)
1843 {
1844    RASPIVID_CONFIG *config = &state->config;
1845
1846   if (config->verbose)
1847      fprintf(stderr, "Closing down\n");
1848
1849   if (config->preview_parameters.wantPreview )
1850      mmal_connection_destroy(state->preview_connection);
1851
1852   // Disable all our ports that are not handled by connections
1853   check_disable_port(state->camera_still_port);
1854   check_disable_port(state->encoder_output_port);
1855
1856   if (state->encoder_component) {
1857      mmal_connection_destroy(state->encoder_connection);
1858      mmal_component_disable(state->encoder_component);
1859      destroy_encoder_component(state);
1860   }
1861 }
1862
1863 void
1864 raspi_capture_free(RASPIVID_STATE *state)
1865 {
1866    RASPIVID_CONFIG *config = &state->config;
1867
1868   // Can now close our file. Note disabling ports may flush buffers which causes
1869   // problems if we have already closed the file!
1870   if (state->output_file && state->output_file != stdout)
1871      fclose(state->output_file);
1872
1873   /* Disable components */
1874   if (state->encoder_component)
1875      mmal_component_disable(state->encoder_component);
1876
1877   if (state->preview_state.preview_component)
1878      mmal_component_disable(state->preview_state.preview_component);
1879
1880   if (state->camera_component)
1881      mmal_component_disable(state->camera_component);
1882
1883   destroy_encoder_component(state);
1884   raspipreview_destroy(&state->preview_state);
1885   destroy_camera_component(state);
1886
1887   if (state->encoded_buffer_q) {
1888     mmal_queue_destroy(state->encoded_buffer_q);
1889     state->encoded_buffer_q = NULL;
1890   }
1891
1892   if (config->verbose)
1893      fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
1894
1895   free(state);
1896 }
1897
1898 void
1899 raspi_capture_update_config (RASPIVID_STATE *state, RASPIVID_CONFIG *config, gboolean dynamic)
1900 {
1901   MMAL_STATUS_T status;
1902   RASPICAM_CAMERA_PARAMETERS *params = &config->camera_parameters;
1903   MMAL_COMPONENT_T *camera = state->camera_component;
1904
1905   /* Store the new config */
1906   state->config = *config;
1907   if (!dynamic)
1908     return;
1909
1910   if (state->encoder_component && config->change_flags & PROP_CHANGE_ENCODING) {
1911     /* BITRATE or QUANT or KEY Interval, intra refresh */
1912     MMAL_COMPONENT_T *encoder = state->encoder_component;
1913     MMAL_PORT_T *encoder_output = encoder->output[0];
1914
1915     status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_VIDEO_BIT_RATE, config->bitrate);
1916     if (status != MMAL_SUCCESS)
1917       vcos_log_warn("Unable to change bitrate dynamically");
1918
1919     {
1920       MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, config->intraperiod};
1921       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1922       if (status != MMAL_SUCCESS)
1923         vcos_log_warn("Unable to change intraperiod dynamically");
1924     }
1925
1926 #if 0 /* not dynamically change-able */
1927     {
1928       MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, config->quantisationParameter};
1929       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1930       if (status != MMAL_SUCCESS)
1931         vcos_log_warn("Unable to change Initial Quantisation Parameter dynamically");
1932
1933       MMAL_PARAMETER_UINT32_T param2 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, sizeof(param)}, config->quantisationParameter};
1934       status = mmal_port_parameter_set(encoder_output, &param2.hdr);
1935       if (status != MMAL_SUCCESS)
1936         vcos_log_warn("Unable to change Minimum Quantisation Parameter dynamically");
1937
1938       MMAL_PARAMETER_UINT32_T param3 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, sizeof(param)}, config->quantisationParameter};
1939       status = mmal_port_parameter_set(encoder_output, &param3.hdr);
1940       if (status != MMAL_SUCCESS)
1941         vcos_log_warn("Unable to change Maximum Quantisation Parameter dynamically");
1942     }
1943
1944     {
1945       // Adaptive intra refresh settings
1946       MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T  param;
1947       param.hdr.id = MMAL_PARAMETER_VIDEO_INTRA_REFRESH;
1948       param.hdr.size = sizeof(param);
1949
1950       // Get first so we don't overwrite anything unexpectedly
1951       status = mmal_port_parameter_get(encoder_output, &param.hdr);
1952       if (state != MMAL_SUCCESS) {
1953         /* Need to memset, apparently mmal_port_parameter_get()
1954          * doesn't retrieve all parameters, causing random failures
1955          * when we set it. On older firmware the get fails.
1956          */
1957         memset (&param, 0, sizeof (MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T));
1958       }
1959       param.refresh_mode = config->intra_refresh_type;
1960
1961       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1962       if (status != MMAL_SUCCESS)
1963          vcos_log_warn("Unable to set H264 intra-refresh values dynamically");
1964     }
1965 #endif
1966   }
1967   if (config->change_flags & PROP_CHANGE_PREVIEW) {
1968     /* Preview settings or fullscreen */
1969     status = raspipreview_update_config (&state->preview_state,
1970         &config->preview_parameters);
1971     if (status != MMAL_SUCCESS)
1972       vcos_log_warn("Unable to change preview config dynamically");
1973   }
1974   if (config->change_flags & PROP_CHANGE_COLOURBALANCE) {
1975     raspicamcontrol_set_saturation(camera, params->saturation);
1976     raspicamcontrol_set_sharpness(camera, params->sharpness);
1977     raspicamcontrol_set_contrast(camera, params->contrast);
1978     raspicamcontrol_set_brightness(camera, params->brightness);
1979   }
1980   if (config->change_flags & PROP_CHANGE_SENSOR_SETTINGS) {
1981     /* ISO, EXPOSURE, SHUTTER, DRC, Sensor Mode */
1982     raspicamcontrol_set_ISO(camera, params->ISO);
1983     raspicamcontrol_set_exposure_compensation(camera, params->exposureCompensation);
1984     raspicamcontrol_set_exposure_mode(camera, params->exposureMode);
1985     raspicamcontrol_set_metering_mode(camera, params->exposureMeterMode);
1986     raspicamcontrol_set_shutter_speed(camera, params->shutter_speed);
1987     raspicamcontrol_set_DRC(camera, params->drc_level);
1988
1989     /* Can we change sensor mode on the fly? Disable if not */
1990     status = mmal_port_parameter_set_uint32(camera->control,
1991        MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, config->sensor_mode);
1992     if (status != MMAL_SUCCESS)
1993       vcos_log_warn("Unable to change sensor mode dynamically");
1994   }
1995   if (config->change_flags & PROP_CHANGE_VIDEO_STABILISATION) {
1996     raspicamcontrol_set_video_stabilisation(camera, params->videoStabilisation);
1997   }
1998   if (config->change_flags & PROP_CHANGE_AWB) {
1999     raspicamcontrol_set_awb_mode(camera, params->awbMode);
2000     raspicamcontrol_set_awb_gains(camera, params->awb_gains_r, params->awb_gains_b);
2001   }
2002   if (config->change_flags & PROP_CHANGE_IMAGE_COLOUR_EFFECT) {
2003     raspicamcontrol_set_imageFX(camera, params->imageEffect);
2004     raspicamcontrol_set_colourFX(camera, &params->colourEffects);
2005   }
2006   if (config->change_flags & PROP_CHANGE_ORIENTATION) {
2007     raspicamcontrol_set_rotation(camera, params->rotation);
2008     raspicamcontrol_set_flips(camera, params->hflip, params->vflip);
2009   }
2010   if (config->change_flags & PROP_CHANGE_ROI) {
2011     raspicamcontrol_set_ROI(camera, params->roi);
2012   }
2013   if (config->change_flags & PROP_CHANGE_ANNOTATION)
2014     update_annotation_data(state);
2015 }