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