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