c50ef9957e8dbcb2ad47aeb342fc30a1728a2e7b
[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    // Get rid of any port buffers first
1565    if (state->encoder_pool)
1566    {
1567       mmal_port_pool_destroy(state->encoder_output_port, state->encoder_pool);
1568       state->encoder_pool = NULL;
1569    }
1570
1571    if (state->encoder_component) {
1572
1573       mmal_component_destroy(state->encoder_component);
1574       state->encoder_component = NULL;
1575    }
1576 }
1577
1578 /**
1579  * Connect two specific ports together
1580  *
1581  * @param output_port Pointer the output port
1582  * @param input_port Pointer the input port
1583  * @param Pointer to a mmal connection pointer, reassigned if function successful
1584  * @return Returns a MMAL_STATUS_T giving result of operation
1585  *
1586  */
1587 static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection)
1588 {
1589    MMAL_STATUS_T status;
1590
1591    status =  mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT);
1592
1593    if (status == MMAL_SUCCESS)
1594    {
1595       status =  mmal_connection_enable(*connection);
1596       if (status != MMAL_SUCCESS)
1597          mmal_connection_destroy(*connection);
1598    }
1599
1600    return status;
1601 }
1602
1603 /**
1604  * Checks if specified port is valid and enabled, then disables it
1605  *
1606  * @param port  Pointer the port
1607  *
1608  */
1609 static void check_disable_port(MMAL_PORT_T *port)
1610 {
1611    if (port && port->is_enabled)
1612       mmal_port_disable(port);
1613 }
1614
1615 void raspicapture_init()
1616 {
1617    bcm_host_init();
1618
1619    // Register our application with the logging system
1620    vcos_log_register("RaspiVid", VCOS_LOG_CATEGORY);
1621 }
1622
1623 RASPIVID_STATE *
1624 raspi_capture_setup(RASPIVID_CONFIG *config)
1625 {
1626   // Our main data storage vessel..
1627   RASPIVID_STATE *state;
1628
1629   MMAL_STATUS_T status = MMAL_SUCCESS;
1630
1631   /* Default everything to zero */
1632   state = calloc(1, sizeof(RASPIVID_STATE));
1633
1634   /* Apply passed in config */
1635   state->config = *config;
1636
1637   /* Initialize timestamping */
1638   state->base_time = state->last_second = -1;
1639
1640   /* So far, all we can do is create the camera component. Actual
1641    * config and connection of encoders etc happens in _start()
1642    */
1643   // OK, we have a nice set of parameters. Now set up our components
1644   // We have three components. Camera, Preview and encoder.
1645
1646   if ((status = create_camera_component(state)) != MMAL_SUCCESS)
1647   {
1648      vcos_log_error("%s: Failed to create camera component", __func__);
1649      return NULL;
1650   }
1651
1652   if ((status = raspipreview_create(&state->preview_state, &config->preview_parameters)) != MMAL_SUCCESS)
1653   {
1654      vcos_log_error("%s: Failed to create preview component", __func__);
1655      destroy_camera_component(state);
1656      return NULL;
1657   }
1658
1659   state->encoded_buffer_q = mmal_queue_create();
1660
1661   return state;
1662 }
1663
1664 gboolean
1665 raspi_capture_start(RASPIVID_STATE *state)
1666 {
1667   MMAL_STATUS_T status = MMAL_SUCCESS;
1668   RASPIVID_CONFIG *config = &state->config;
1669
1670   MMAL_PORT_T *camera_preview_port = NULL;
1671   MMAL_PORT_T *preview_input_port = NULL;
1672   MMAL_PORT_T *encoder_input_port = NULL;
1673
1674   MMAL_POOL_T *pool;
1675
1676   if ((status = create_encoder_component(state)) != MMAL_SUCCESS) {
1677     vcos_log_error("%s: Failed to create encode component", __func__);
1678     return FALSE;
1679   }
1680
1681   if (config->verbose)
1682   {
1683      dump_state(state);
1684   }
1685
1686   state->camera_video_port   = state->camera_component->output[MMAL_CAMERA_VIDEO_PORT];
1687   state->camera_still_port   = state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
1688   camera_preview_port = state->camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
1689   preview_input_port  = state->preview_state.preview_component->input[0];
1690
1691   if (state->encoder_component) {
1692     encoder_input_port  = state->encoder_component->input[0];
1693     state->encoder_output_port = state->encoder_component->output[0];
1694   } else {
1695     state->encoder_output_port = state->camera_video_port;
1696   }
1697
1698   if ((status = raspi_capture_set_format_and_start(state)) != MMAL_SUCCESS) {
1699      return FALSE;
1700   }
1701
1702   GST_DEBUG ("Creating pool of %d buffers of size %d",
1703       state->encoder_output_port->buffer_num, state->encoder_output_port->buffer_size);
1704   /* Create pool of buffer headers for the output port to consume */
1705   pool = mmal_port_pool_create(state->encoder_output_port,
1706              state->encoder_output_port->buffer_num, state->encoder_output_port->buffer_size);
1707   if (!pool)
1708   {
1709     vcos_log_error("Failed to create buffer header pool for encoder output port %s",
1710          state->encoder_output_port->name);
1711     return FALSE;
1712   }
1713   state->encoder_pool = pool;
1714
1715   if (state->config.verbose)
1716      fprintf(stderr, "Starting component connection stage\n");
1717
1718   if (config->preview_parameters.wantPreview )
1719   {
1720      if (config->verbose)
1721      {
1722         fprintf(stderr, "Connecting camera preview port to preview input port\n");
1723         fprintf(stderr, "Starting video preview\n");
1724      }
1725
1726      // Connect camera to preview
1727      status = connect_ports(camera_preview_port, preview_input_port, &state->preview_connection);
1728      if (status != MMAL_SUCCESS)
1729      {
1730         vcos_log_error("%s: Failed to connect camera to preview", __func__);
1731         return FALSE;
1732      }
1733   }
1734
1735   if (state->encoder_component) {
1736     if (config->verbose)
1737        fprintf(stderr, "Connecting camera video port to encoder input port\n");
1738
1739     // Now connect the camera to the encoder
1740     status = connect_ports(state->camera_video_port, encoder_input_port, &state->encoder_connection);
1741     if (status != MMAL_SUCCESS)
1742     {
1743       if (config->preview_parameters.wantPreview )
1744         mmal_connection_destroy(state->preview_connection);
1745       vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__);
1746       return FALSE;
1747     }
1748   }
1749
1750   // Set up our userdata - this is passed though to the callback where we need the information.
1751   state->callback_data.state = state;
1752   state->callback_data.abort = 0;
1753
1754   state->encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&state->callback_data;
1755
1756   if (config->verbose)
1757      fprintf(stderr, "Enabling encoder output port\n");
1758
1759   // Enable the encoder output port and tell it its callback function
1760   status = mmal_port_enable(state->encoder_output_port, encoder_buffer_callback);
1761   if (status != MMAL_SUCCESS)
1762   {
1763      vcos_log_error("Failed to setup encoder output");
1764      goto error;
1765   }
1766
1767   if (config->demoMode)
1768   {
1769      // Run for the user specific time..
1770      int num_iterations = config->timeout / config->demoInterval;
1771      int i;
1772
1773      if (config->verbose)
1774         fprintf(stderr, "Running in demo mode\n");
1775
1776      for (i=0;config->timeout == 0 || i<num_iterations;i++)
1777      {
1778         raspicamcontrol_cycle_test(state->camera_component);
1779         vcos_sleep(state->config.demoInterval);
1780      }
1781   }
1782
1783   if (config->verbose)
1784     fprintf(stderr, "Starting video capture\n");
1785
1786   if (mmal_port_parameter_set_boolean(state->camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
1787   {
1788      goto error;
1789   }
1790
1791   // Send all the buffers to the encoder output port
1792   {
1793      int num = mmal_queue_length(state->encoder_pool->queue);
1794      int q;
1795      for (q=0;q<num;q++)
1796      {
1797         MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->encoder_pool->queue);
1798
1799         if (!buffer)
1800            vcos_log_error("Unable to get a required buffer %d from pool queue", q);
1801
1802         if (mmal_port_send_buffer(state->encoder_output_port, buffer)!= MMAL_SUCCESS)
1803            vcos_log_error("Unable to send a buffer to encoder output port (%d)", q);
1804
1805      }
1806   }
1807
1808   // Now wait until we need to stop. Whilst waiting we do need to check to see if we have aborted (for example
1809   // out of storage space)
1810   // Going to check every ABORT_INTERVAL milliseconds
1811
1812 #if 0
1813   for (wait = 0; config->timeout == 0 || wait < config->timeout; wait+= ABORT_INTERVAL)
1814   {
1815      vcos_sleep(ABORT_INTERVAL);
1816      if (state->callback_data.abort)
1817         break;
1818   }
1819
1820   if (config->verbose)
1821      fprintf(stderr, "Finished capture\n");
1822 #endif
1823
1824   return (status == MMAL_SUCCESS);
1825
1826 error:
1827   raspi_capture_stop(state);
1828
1829   if (status != MMAL_SUCCESS) {
1830     mmal_status_to_int(status);
1831     raspicamcontrol_check_configuration(128);
1832   }
1833
1834   return FALSE;
1835 }
1836
1837 void
1838 raspi_capture_stop(RASPIVID_STATE *state)
1839 {
1840    RASPIVID_CONFIG *config = &state->config;
1841
1842   if (config->verbose)
1843      fprintf(stderr, "Closing down\n");
1844
1845   if (config->preview_parameters.wantPreview )
1846      mmal_connection_destroy(state->preview_connection);
1847
1848   // Disable all our ports that are not handled by connections
1849   check_disable_port(state->camera_still_port);
1850   check_disable_port(state->encoder_output_port);
1851
1852   if (state->encoder_component) {
1853      mmal_connection_destroy(state->encoder_connection);
1854      mmal_component_disable(state->encoder_component);
1855      destroy_encoder_component(state);
1856   }
1857 }
1858
1859 void
1860 raspi_capture_free(RASPIVID_STATE *state)
1861 {
1862    RASPIVID_CONFIG *config = &state->config;
1863
1864   // Can now close our file. Note disabling ports may flush buffers which causes
1865   // problems if we have already closed the file!
1866   if (state->output_file && state->output_file != stdout)
1867      fclose(state->output_file);
1868
1869   /* Disable components */
1870   if (state->encoder_component)
1871      mmal_component_disable(state->encoder_component);
1872
1873   if (state->preview_state.preview_component)
1874      mmal_component_disable(state->preview_state.preview_component);
1875
1876   if (state->camera_component)
1877      mmal_component_disable(state->camera_component);
1878
1879   destroy_encoder_component(state);
1880   raspipreview_destroy(&state->preview_state);
1881   destroy_camera_component(state);
1882
1883   if (state->encoded_buffer_q) {
1884     mmal_queue_destroy(state->encoded_buffer_q);
1885     state->encoded_buffer_q = NULL;
1886   }
1887
1888   if (config->verbose)
1889      fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
1890
1891   free(state);
1892 }
1893
1894 void
1895 raspi_capture_update_config (RASPIVID_STATE *state, RASPIVID_CONFIG *config, gboolean dynamic)
1896 {
1897   MMAL_STATUS_T status;
1898   RASPICAM_CAMERA_PARAMETERS *params = &config->camera_parameters;
1899   MMAL_COMPONENT_T *camera = state->camera_component;
1900
1901   /* Store the new config */
1902   state->config = *config;
1903   if (!dynamic)
1904     return;
1905
1906   if (state->encoder_component && config->change_flags & PROP_CHANGE_ENCODING) {
1907     /* BITRATE or QUANT or KEY Interval, intra refresh */
1908     MMAL_COMPONENT_T *encoder = state->encoder_component;
1909     MMAL_PORT_T *encoder_output = encoder->output[0];
1910
1911     status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_VIDEO_BIT_RATE, config->bitrate);
1912     if (status != MMAL_SUCCESS)
1913       vcos_log_warn("Unable to change bitrate dynamically");
1914
1915     {
1916       MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, config->intraperiod};
1917       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1918       if (status != MMAL_SUCCESS)
1919         vcos_log_warn("Unable to change intraperiod dynamically");
1920     }
1921
1922 #if 0 /* not dynamically change-able */
1923     {
1924       MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, config->quantisationParameter};
1925       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1926       if (status != MMAL_SUCCESS)
1927         vcos_log_warn("Unable to change Initial Quantisation Parameter dynamically");
1928
1929       MMAL_PARAMETER_UINT32_T param2 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, sizeof(param)}, config->quantisationParameter};
1930       status = mmal_port_parameter_set(encoder_output, &param2.hdr);
1931       if (status != MMAL_SUCCESS)
1932         vcos_log_warn("Unable to change Minimum Quantisation Parameter dynamically");
1933
1934       MMAL_PARAMETER_UINT32_T param3 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, sizeof(param)}, config->quantisationParameter};
1935       status = mmal_port_parameter_set(encoder_output, &param3.hdr);
1936       if (status != MMAL_SUCCESS)
1937         vcos_log_warn("Unable to change Maximum Quantisation Parameter dynamically");
1938     }
1939
1940     {
1941       // Adaptive intra refresh settings
1942       MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T  param;
1943       param.hdr.id = MMAL_PARAMETER_VIDEO_INTRA_REFRESH;
1944       param.hdr.size = sizeof(param);
1945
1946       // Get first so we don't overwrite anything unexpectedly
1947       status = mmal_port_parameter_get(encoder_output, &param.hdr);
1948       if (state != MMAL_SUCCESS) {
1949         /* Need to memset, apparently mmal_port_parameter_get()
1950          * doesn't retrieve all parameters, causing random failures
1951          * when we set it. On older firmware the get fails.
1952          */
1953         memset (&param, 0, sizeof (MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T));
1954       }
1955       param.refresh_mode = config->intra_refresh_type;
1956
1957       status = mmal_port_parameter_set(encoder_output, &param.hdr);
1958       if (status != MMAL_SUCCESS)
1959          vcos_log_warn("Unable to set H264 intra-refresh values dynamically");
1960     }
1961 #endif
1962   }
1963   if (config->change_flags & PROP_CHANGE_PREVIEW) {
1964     /* Preview settings or fullscreen */
1965     status = raspipreview_update_config (&state->preview_state,
1966         &config->preview_parameters);
1967     if (status != MMAL_SUCCESS)
1968       vcos_log_warn("Unable to change preview config dynamically");
1969   }
1970   if (config->change_flags & PROP_CHANGE_COLOURBALANCE) {
1971     raspicamcontrol_set_saturation(camera, params->saturation);
1972     raspicamcontrol_set_sharpness(camera, params->sharpness);
1973     raspicamcontrol_set_contrast(camera, params->contrast);
1974     raspicamcontrol_set_brightness(camera, params->brightness);
1975   }
1976   if (config->change_flags & PROP_CHANGE_SENSOR_SETTINGS) {
1977     /* ISO, EXPOSURE, SHUTTER, DRC, Sensor Mode */
1978     raspicamcontrol_set_ISO(camera, params->ISO);
1979     raspicamcontrol_set_exposure_compensation(camera, params->exposureCompensation);
1980     raspicamcontrol_set_exposure_mode(camera, params->exposureMode);
1981     raspicamcontrol_set_metering_mode(camera, params->exposureMeterMode);
1982     raspicamcontrol_set_shutter_speed(camera, params->shutter_speed);
1983     raspicamcontrol_set_DRC(camera, params->drc_level);
1984
1985     /* Can we change sensor mode on the fly? Disable if not */
1986     status = mmal_port_parameter_set_uint32(camera->control,
1987        MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, config->sensor_mode);
1988     if (status != MMAL_SUCCESS)
1989       vcos_log_warn("Unable to change sensor mode dynamically");
1990   }
1991   if (config->change_flags & PROP_CHANGE_VIDEO_STABILISATION) {
1992     raspicamcontrol_set_video_stabilisation(camera, params->videoStabilisation);
1993   }
1994   if (config->change_flags & PROP_CHANGE_AWB) {
1995     raspicamcontrol_set_awb_mode(camera, params->awbMode);
1996     raspicamcontrol_set_awb_gains(camera, params->awb_gains_r, params->awb_gains_b);
1997   }
1998   if (config->change_flags & PROP_CHANGE_IMAGE_COLOUR_EFFECT) {
1999     raspicamcontrol_set_imageFX(camera, params->imageEffect);
2000     raspicamcontrol_set_colourFX(camera, &params->colourEffects);
2001   }
2002   if (config->change_flags & PROP_CHANGE_ORIENTATION) {
2003     raspicamcontrol_set_rotation(camera, params->rotation);
2004     raspicamcontrol_set_flips(camera, params->hflip, params->vflip);
2005   }
2006   if (config->change_flags & PROP_CHANGE_ROI) {
2007     raspicamcontrol_set_ROI(camera, params->roi);
2008   }
2009   if (config->change_flags & PROP_CHANGE_ANNOTATION)
2010     update_annotation_data(state);
2011 }