1 /*
2 Copyright (c) 2018, Raspberry Pi (Trading) Ltd.
3 Copyright (c) 2013, Broadcom Europe Ltd.
4 Copyright (c) 2013, James Hughes
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9     * Redistributions of source code must retain the above copyright
10       notice, this list of conditions and the following disclaimer.
11     * Redistributions in binary form must reproduce the above copyright
12       notice, this list of conditions and the following disclaimer in the
13       documentation and/or other materials provided with the distribution.
14     * Neither the name of the copyright holder nor the
15       names of its contributors may be used to endorse or promote products
16       derived from this software without specific prior written permission.
17 
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 
30 /**
31  * \file RaspiStill.c
32  * Command line program to capture a still frame and encode it to file.
33  * Also optionally display a preview/viewfinder of current camera input.
34  *
35  * Description
36  *
37  * 3 components are created; camera, preview and JPG encoder.
38  * Camera component has three ports, preview, video and stills.
39  * This program connects preview and stills to the preview and jpg
40  * encoder. Using mmal we don't need to worry about buffers between these
41  * components, but we do need to handle buffers from the encoder, which
42  * are simply written straight to the file in the requisite buffer callback.
43  *
44  * We use the RaspiCamControl code to handle the specific camera settings.
45  */
46 
47 // We use some GNU extensions (asprintf, basename)
48 #ifndef _GNU_SOURCE
49 #define _GNU_SOURCE
50 #endif
51 
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <ctype.h>
55 #include <string.h>
56 #include <memory.h>
57 #include <unistd.h>
58 #include <errno.h>
59 #include <sysexits.h>
60 
61 #include "bcm_host.h"
62 #include "interface/vcos/vcos.h"
63 
64 #include "interface/mmal/mmal.h"
65 #include "interface/mmal/mmal_logging.h"
66 #include "interface/mmal/mmal_buffer.h"
67 #include "interface/mmal/util/mmal_util.h"
68 #include "interface/mmal/util/mmal_util_params.h"
69 #include "interface/mmal/util/mmal_default_components.h"
70 #include "interface/mmal/util/mmal_connection.h"
71 #include "interface/mmal/mmal_parameters_camera.h"
72 
73 #include "RaspiCommonSettings.h"
74 #include "RaspiCamControl.h"
75 #include "RaspiPreview.h"
76 #include "RaspiCLI.h"
77 #include "RaspiTex.h"
78 #include "RaspiHelpers.h"
79 
80 // TODO
81 //#include "libgps_loader.h"
82 
83 #include "RaspiGPS.h"
84 
85 #include <semaphore.h>
86 #include <math.h>
87 #include <pthread.h>
88 #include <time.h>
89 
90 // Standard port setting for the camera component
91 #define MMAL_CAMERA_PREVIEW_PORT 0
92 #define MMAL_CAMERA_VIDEO_PORT 1
93 #define MMAL_CAMERA_CAPTURE_PORT 2
94 
95 // Stills format information
96 // 0 implies variable
97 #define STILLS_FRAME_RATE_NUM 0
98 #define STILLS_FRAME_RATE_DEN 1
99 
100 /// Video render needs at least 2 buffers.
101 #define VIDEO_OUTPUT_BUFFERS_NUM 3
102 
103 #define MAX_USER_EXIF_TAGS      32
104 #define MAX_EXIF_PAYLOAD_LENGTH 128
105 
106 /// Frame advance method
107 enum
108 {
109    FRAME_NEXT_SINGLE,
110    FRAME_NEXT_TIMELAPSE,
111    FRAME_NEXT_KEYPRESS,
112    FRAME_NEXT_FOREVER,
113    FRAME_NEXT_GPIO,
114    FRAME_NEXT_SIGNAL,
115    FRAME_NEXT_IMMEDIATELY
116 };
117 
118 /// Amount of time before first image taken to allow settling of
119 /// exposure etc. in milliseconds.
120 #define CAMERA_SETTLE_TIME       1000
121 
122 /** Structure containing all state information for the current run
123  */
124 typedef struct
125 {
126    RASPICOMMONSETTINGS_PARAMETERS common_settings;     /// Common settings
127    int timeout;                        /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds
128    int quality;                        /// JPEG quality setting (1-100)
129    int wantRAW;                        /// Flag for whether the JPEG metadata also contains the RAW bayer image
130    char *linkname;                     /// filename of output file
131    int frameStart;                     /// First number of frame output counter
132    MMAL_PARAM_THUMBNAIL_CONFIG_T thumbnailConfig;
133    int demoMode;                       /// Run app in demo mode
134    int demoInterval;                   /// Interval between camera settings changes
135    MMAL_FOURCC_T encoding;             /// Encoding to use for the output file.
136    const char *exifTags[MAX_USER_EXIF_TAGS]; /// Array of pointers to tags supplied from the command line
137    int numExifTags;                    /// Number of supplied tags
138    int enableExifTags;                 /// Enable/Disable EXIF tags in output
139    int timelapse;                      /// Delay between each picture in timelapse mode. If 0, disable timelapse
140    int fullResPreview;                 /// If set, the camera preview port runs at capture resolution. Reduces fps.
141    int frameNextMethod;                /// Which method to use to advance to next frame
142    int useGL;                          /// Render preview using OpenGL
143    int glCapture;                      /// Save the GL frame-buffer instead of camera output
144    int burstCaptureMode;               /// Enable burst mode
145    int datetime;                       /// Use DateTime instead of frame#
146    int timestamp;                      /// Use timestamp instead of frame#
147    int restart_interval;               /// JPEG restart interval. 0 for none.
148 
149    RASPIPREVIEW_PARAMETERS preview_parameters;    /// Preview setup parameters
150    RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters
151 
152    MMAL_COMPONENT_T *camera_component;    /// Pointer to the camera component
153    MMAL_COMPONENT_T *encoder_component;   /// Pointer to the encoder component
154    MMAL_COMPONENT_T *null_sink_component; /// Pointer to the null sink component
155    MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera to preview
156    MMAL_CONNECTION_T *encoder_connection; /// Pointer to the connection from camera to encoder
157 
158    MMAL_POOL_T *encoder_pool; /// Pointer to the pool of buffers used by encoder output port
159 
160    RASPITEX_STATE raspitex_state; /// GL renderer state and parameters
161 
162 } RASPISTILL_STATE;
163 
164 /** Struct used to pass information in encoder port userdata to callback
165  */
166 typedef struct
167 {
168    FILE *file_handle;                   /// File handle to write buffer data to.
169    VCOS_SEMAPHORE_T complete_semaphore; /// semaphore which is posted when we reach end of frame (indicates end of capture or fault)
170    RASPISTILL_STATE *pstate;            /// pointer to our state in case required in callback
171 } PORT_USERDATA;
172 
173 static void store_exif_tag(RASPISTILL_STATE *state, const char *exif_tag);
174 
175 /// Command ID's and Structure defining our command line options
176 enum
177 {
178    CommandQuality,
179    CommandRaw,
180    CommandTimeout,
181    CommandThumbnail,
182    CommandDemoMode,
183    CommandEncoding,
184    CommandExifTag,
185    CommandTimelapse,
186    CommandFullResPreview,
187    CommandLink,
188    CommandKeypress,
189    CommandSignal,
190    CommandGL,
191    CommandGLCapture,
192    CommandBurstMode,
193    CommandDateTime,
194    CommandTimeStamp,
195    CommandFrameStart,
196    CommandRestartInterval,
197 };
198 
199 static COMMAND_LIST cmdline_commands[] =
200 {
201    { CommandQuality, "-quality",    "q",  "Set jpeg quality <0 to 100>", 1 },
202    { CommandRaw,     "-raw",        "r",  "Add raw bayer data to jpeg metadata", 0 },
203    { CommandLink,    "-latest",     "l",  "Link latest complete image to filename <filename>", 1},
204    { CommandTimeout, "-timeout",    "t",  "Time (in ms) before takes picture and shuts down (if not specified, set to 5s)", 1 },
205    { CommandThumbnail,"-thumb",     "th", "Set thumbnail parameters (x:y:quality) or none", 1},
206    { CommandDemoMode,"-demo",       "d",  "Run a demo mode (cycle through range of camera options, no capture)", 0},
207    { CommandEncoding,"-encoding",   "e",  "Encoding to use for output file (jpg, bmp, gif, png)", 1},
208    { CommandExifTag, "-exif",       "x",  "EXIF tag to apply to captures (format as 'key=value') or none", 1},
209    { CommandTimelapse,"-timelapse", "tl", "Timelapse mode. Takes a picture every <t>ms. %d == frame number (Try: -o img_%04d.jpg)", 1},
210    { CommandFullResPreview,"-fullpreview","fp", "Run the preview using the still capture resolution (may reduce preview fps)", 0},
211    { CommandKeypress,"-keypress",   "k",  "Wait between captures for a ENTER, X then ENTER to exit", 0},
212    { CommandSignal,  "-signal",     "s",  "Wait between captures for a SIGUSR1 or SIGUSR2 from another process", 0},
213    { CommandGL,      "-gl",         "g",  "Draw preview to texture instead of using video render component", 0},
214    { CommandGLCapture, "-glcapture","gc", "Capture the GL frame-buffer instead of the camera image", 0},
215    { CommandBurstMode, "-burst",    "bm", "Enable 'burst capture mode'", 0},
216    { CommandDateTime,  "-datetime",  "dt", "Replace output pattern (%d) with DateTime (MonthDayHourMinSec)", 0},
217    { CommandTimeStamp, "-timestamp", "ts", "Replace output pattern (%d) with unix timestamp (seconds since 1970)", 0},
218    { CommandFrameStart,"-framestart","fs",  "Starting frame number in output pattern(%d)", 1},
219    { CommandRestartInterval, "-restart","rs","JPEG Restart interval (default of 0 for none)", 1},
220 };
221 
222 static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
223 
224 static struct
225 {
226    char *format;
227    MMAL_FOURCC_T encoding;
228 } encoding_xref[] =
229 {
230    {"jpg", MMAL_ENCODING_JPEG},
231    {"bmp", MMAL_ENCODING_BMP},
232    {"gif", MMAL_ENCODING_GIF},
233    {"png", MMAL_ENCODING_PNG},
234    {"ppm", MMAL_ENCODING_PPM},
235    {"tga", MMAL_ENCODING_TGA}
236 };
237 
238 static int encoding_xref_size = sizeof(encoding_xref) / sizeof(encoding_xref[0]);
239 
240 static struct
241 {
242    char *description;
243    int nextFrameMethod;
244 } next_frame_description[] =
245 {
246    {"Single capture",         FRAME_NEXT_SINGLE},
247    {"Capture on timelapse",   FRAME_NEXT_TIMELAPSE},
248    {"Capture on keypress",    FRAME_NEXT_KEYPRESS},
249    {"Run forever",            FRAME_NEXT_FOREVER},
250    {"Capture on GPIO",        FRAME_NEXT_GPIO},
251    {"Capture on signal",      FRAME_NEXT_SIGNAL},
252 };
253 
254 static int next_frame_description_size = sizeof(next_frame_description) / sizeof(next_frame_description[0]);
255 
256 /**
257  * Assign a default set of parameters to the state passed in
258  *
259  * @param state Pointer to state structure to assign defaults to
260  */
default_status(RASPISTILL_STATE * state)261 static void default_status(RASPISTILL_STATE *state)
262 {
263    if (!state)
264    {
265       vcos_assert(0);
266       return;
267    }
268 
269    memset(state, 0, sizeof(*state));
270 
271    raspicommonsettings_set_defaults(&state->common_settings);
272 
273    state->timeout = -1; // replaced with 5000ms later if unset
274    state->quality = 85;
275    state->wantRAW = 0;
276    state->linkname = NULL;
277    state->frameStart = 0;
278    state->thumbnailConfig.enable = 1;
279    state->thumbnailConfig.width = 64;
280    state->thumbnailConfig.height = 48;
281    state->thumbnailConfig.quality = 35;
282    state->demoMode = 0;
283    state->demoInterval = 250; // ms
284    state->camera_component = NULL;
285    state->encoder_component = NULL;
286    state->preview_connection = NULL;
287    state->encoder_connection = NULL;
288    state->encoder_pool = NULL;
289    state->encoding = MMAL_ENCODING_JPEG;
290    state->numExifTags = 0;
291    state->enableExifTags = 1;
292    state->timelapse = 0;
293    state->fullResPreview = 0;
294    state->frameNextMethod = FRAME_NEXT_SINGLE;
295    state->useGL = 0;
296    state->glCapture = 0;
297    state->burstCaptureMode=0;
298    state->datetime = 0;
299    state->timestamp = 0;
300    state->restart_interval = 0;
301 
302    // Setup preview window defaults
303    raspipreview_set_defaults(&state->preview_parameters);
304 
305    // Set up the camera_parameters to default
306    raspicamcontrol_set_defaults(&state->camera_parameters);
307 
308    // Set initial GL preview state
309    raspitex_set_defaults(&state->raspitex_state);
310 }
311 
312 /**
313  * Dump image state parameters to stderr. Used for debugging
314  *
315  * @param state Pointer to state structure to assign defaults to
316  */
dump_status(RASPISTILL_STATE * state)317 static void dump_status(RASPISTILL_STATE *state)
318 {
319    int i;
320 
321    if (!state)
322    {
323       vcos_assert(0);
324       return;
325    }
326 
327    raspicommonsettings_dump_parameters(&state->common_settings);
328 
329    fprintf(stderr, "Quality %d, Raw %s\n", state->quality, state->wantRAW ? "yes" : "no");
330    fprintf(stderr, "Thumbnail enabled %s, width %d, height %d, quality %d\n",
331            state->thumbnailConfig.enable ? "Yes":"No", state->thumbnailConfig.width,
332            state->thumbnailConfig.height, state->thumbnailConfig.quality);
333 
334    fprintf(stderr, "Time delay %d, Timelapse %d\n", state->timeout, state->timelapse);
335    fprintf(stderr, "Link to latest frame enabled ");
336    if (state->linkname)
337    {
338       fprintf(stderr, " yes, -> %s\n", state->linkname);
339    }
340    else
341    {
342       fprintf(stderr, " no\n");
343    }
344    fprintf(stderr, "Full resolution preview %s\n", state->fullResPreview ? "Yes": "No");
345 
346    fprintf(stderr, "Capture method : ");
347    for (i=0; i<next_frame_description_size; i++)
348    {
349       if (state->frameNextMethod == next_frame_description[i].nextFrameMethod)
350          fprintf(stderr, "%s", next_frame_description[i].description);
351    }
352    fprintf(stderr, "\n\n");
353 
354    if (state->enableExifTags)
355    {
356       if (state->numExifTags)
357       {
358          fprintf(stderr, "User supplied EXIF tags :\n");
359 
360          for (i=0; i<state->numExifTags; i++)
361          {
362             fprintf(stderr, "%s", state->exifTags[i]);
363             if (i != state->numExifTags-1)
364                fprintf(stderr, ",");
365          }
366          fprintf(stderr, "\n\n");
367       }
368    }
369    else
370       fprintf(stderr, "EXIF tags disabled\n");
371 
372    raspipreview_dump_parameters(&state->preview_parameters);
373    raspicamcontrol_dump_parameters(&state->camera_parameters);
374 }
375 
376 /**
377  * Display usage information for the application to stdout
378  *
379  * @param app_name String to display as the application name
380  */
application_help_message(char * app_name)381 static void application_help_message(char *app_name)
382 {
383    fprintf(stdout, "Runs camera for specific time, and take JPG capture at end if requested\n\n");
384    fprintf(stdout, "usage: %s [options]\n\n", app_name);
385 
386    fprintf(stdout, "Image parameter commands\n\n");
387 
388    raspicli_display_help(cmdline_commands, cmdline_commands_size);
389 
390    raspitex_display_help();
391 
392    return;
393 }
394 
395 /**
396  * Parse the incoming command line and put resulting parameters in to the state
397  *
398  * @param argc Number of arguments in command line
399  * @param argv Array of pointers to strings from command line
400  * @param state Pointer to state structure to assign any discovered parameters to
401  * @return non-0 if failed for some reason, 0 otherwise
402  */
parse_cmdline(int argc,const char ** argv,RASPISTILL_STATE * state)403 static int parse_cmdline(int argc, const char **argv, RASPISTILL_STATE *state)
404 {
405    // Parse the command line arguments.
406    // We are looking for --<something> or -<abbreviation of something>
407 
408    int valid = 1;
409    int i;
410 
411    for (i = 1; i < argc && valid; i++)
412    {
413       int command_id, num_parameters;
414 
415       if (!argv[i])
416          continue;
417 
418       if (argv[i][0] != '-')
419       {
420          valid = 0;
421          continue;
422       }
423 
424       // Assume parameter is valid until proven otherwise
425       valid = 1;
426 
427       command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, &argv[i][1], &num_parameters);
428 
429       // If we found a command but are missing a parameter, continue (and we will drop out of the loop)
430       if (command_id != -1 && num_parameters > 0 && (i + 1 >= argc) )
431          continue;
432 
433       //  We are now dealing with a command line option
434       switch (command_id)
435       {
436       case CommandQuality: // Quality = 1-100
437          if (sscanf(argv[i + 1], "%u", &state->quality) == 1)
438          {
439             if (state->quality > 100)
440             {
441                fprintf(stderr, "Setting max quality = 100\n");
442                state->quality = 100;
443             }
444             i++;
445          }
446          else
447             valid = 0;
448          break;
449 
450       case CommandRaw: // Add raw bayer data in metadata
451          state->wantRAW = 1;
452          break;
453 
454       case CommandLink :
455       {
456          int len = strlen(argv[i+1]);
457          if (len)
458          {
459             state->linkname = malloc(len + 10);
460             vcos_assert(state->linkname);
461             if (state->linkname)
462                strncpy(state->linkname, argv[i + 1], len+1);
463             i++;
464          }
465          else
466             valid = 0;
467          break;
468 
469       }
470 
471       case CommandFrameStart:  // use a staring value != 0
472       {
473          if (sscanf(argv[i + 1], "%d", &state->frameStart) == 1)
474          {
475             i++;
476          }
477          else
478             valid = 0;
479          break;
480       }
481 
482       case CommandDateTime: // use datetime
483          state->datetime = 1;
484          break;
485 
486       case CommandTimeStamp: // use timestamp
487          state->timestamp = 1;
488          break;
489 
490       case CommandTimeout: // Time to run viewfinder for before taking picture, in seconds
491       {
492          if (sscanf(argv[i + 1], "%d", &state->timeout) == 1)
493          {
494             // Ensure that if previously selected CommandKeypress we don't overwrite it
495             if (state->timeout == 0 && state->frameNextMethod == FRAME_NEXT_SINGLE)
496                state->frameNextMethod = FRAME_NEXT_FOREVER;
497 
498             i++;
499          }
500          else
501             valid = 0;
502          break;
503       }
504 
505       case CommandThumbnail : // thumbnail parameters - needs string "x:y:quality"
506          if ( strcmp( argv[ i + 1 ], "none" ) == 0 )
507          {
508             state->thumbnailConfig.enable = 0;
509          }
510          else
511          {
512             sscanf(argv[i + 1], "%d:%d:%d",
513                    &state->thumbnailConfig.width,
514                    &state->thumbnailConfig.height,
515                    &state->thumbnailConfig.quality);
516          }
517          i++;
518          break;
519 
520       case CommandDemoMode: // Run in demo mode - no capture
521       {
522          // Demo mode might have a timing parameter
523          // so check if a) we have another parameter, b) its not the start of the next option
524          if (i + 1 < argc  && argv[i+1][0] != '-')
525          {
526             if (sscanf(argv[i + 1], "%u", &state->demoInterval) == 1)
527             {
528                // TODO : What limits do we need for timeout?
529                state->demoMode = 1;
530                i++;
531             }
532             else
533                valid = 0;
534          }
535          else
536          {
537             state->demoMode = 1;
538          }
539 
540          break;
541       }
542 
543       case CommandEncoding :
544       {
545          int len = strlen(argv[i + 1]);
546          valid = 0;
547 
548          if (len)
549          {
550             int j;
551             for (j=0; j<encoding_xref_size; j++)
552             {
553                if (strcmp(encoding_xref[j].format, argv[i+1]) == 0)
554                {
555                   state->encoding = encoding_xref[j].encoding;
556                   valid = 1;
557                   i++;
558                   break;
559                }
560             }
561          }
562          break;
563       }
564 
565       case CommandExifTag:
566          if ( strcmp( argv[ i + 1 ], "none" ) == 0 )
567          {
568             state->enableExifTags = 0;
569          }
570          else
571          {
572             store_exif_tag(state, argv[i+1]);
573          }
574          i++;
575          break;
576 
577       case CommandTimelapse:
578          if (sscanf(argv[i + 1], "%u", &state->timelapse) != 1)
579             valid = 0;
580          else
581          {
582             if (state->timelapse)
583                state->frameNextMethod = FRAME_NEXT_TIMELAPSE;
584             else
585                state->frameNextMethod = FRAME_NEXT_IMMEDIATELY;
586 
587             i++;
588          }
589          break;
590 
591       case CommandFullResPreview:
592          state->fullResPreview = 1;
593          break;
594 
595       case CommandKeypress: // Set keypress between capture mode
596          state->frameNextMethod = FRAME_NEXT_KEYPRESS;
597 
598          if (state->timeout == -1)
599             state->timeout = 0;
600 
601          break;
602 
603       case CommandSignal:   // Set SIGUSR1 & SIGUSR2 between capture mode
604          state->frameNextMethod = FRAME_NEXT_SIGNAL;
605          // Reenable the signal
606          signal(SIGUSR1, default_signal_handler);
607          signal(SIGUSR2, default_signal_handler);
608 
609          if (state->timeout == -1)
610             state->timeout = 0;
611 
612          break;
613 
614       case CommandGL:
615          state->useGL = 1;
616          break;
617 
618       case CommandGLCapture:
619          state->glCapture = 1;
620          break;
621 
622       case CommandBurstMode:
623          state->burstCaptureMode=1;
624          break;
625 
626       case CommandRestartInterval:
627       {
628          if (sscanf(argv[i + 1], "%u", &state->restart_interval) == 1)
629          {
630             i++;
631          }
632          else
633             valid = 0;
634          break;
635       }
636 
637       default:
638       {
639          // Try parsing for any image specific parameters
640          // result indicates how many parameters were used up, 0,1,2
641          // but we adjust by -1 as we have used one already
642          const char *second_arg = (i + 1 < argc) ? argv[i + 1] : NULL;
643          int parms_used = raspicamcontrol_parse_cmdline(&state->camera_parameters, &argv[i][1], second_arg);
644 
645          // Still unused, try common settings
646          if (!parms_used)
647             parms_used = raspicommonsettings_parse_cmdline(&state->common_settings, &argv[i][1], second_arg, &application_help_message);
648 
649          // Still unused, try preview settings
650          if (!parms_used)
651             parms_used = raspipreview_parse_cmdline(&state->preview_parameters, &argv[i][1], second_arg);
652 
653          // Still unused, try GL preview options
654          if (!parms_used)
655             parms_used = raspitex_parse_cmdline(&state->raspitex_state, &argv[i][1], second_arg);
656 
657          // If no parms were used, this must be a bad parameters
658          if (!parms_used)
659             valid = 0;
660          else
661             i += parms_used - 1;
662 
663          break;
664       }
665       }
666    }
667 
668    /* GL preview parameters use preview parameters as defaults unless overriden */
669    if (! state->raspitex_state.gl_win_defined)
670    {
671       state->raspitex_state.x       = state->preview_parameters.previewWindow.x;
672       state->raspitex_state.y       = state->preview_parameters.previewWindow.y;
673       state->raspitex_state.width   = state->preview_parameters.previewWindow.width;
674       state->raspitex_state.height  = state->preview_parameters.previewWindow.height;
675    }
676    /* Also pass the preview information through so GL renderer can determine
677     * the real resolution of the multi-media image */
678    state->raspitex_state.preview_x       = state->preview_parameters.previewWindow.x;
679    state->raspitex_state.preview_y       = state->preview_parameters.previewWindow.y;
680    state->raspitex_state.preview_width   = state->preview_parameters.previewWindow.width;
681    state->raspitex_state.preview_height  = state->preview_parameters.previewWindow.height;
682    state->raspitex_state.opacity         = state->preview_parameters.opacity;
683    state->raspitex_state.verbose         = state->common_settings.verbose;
684 
685    if (!valid)
686    {
687       fprintf(stderr, "Invalid command line option (%s)\n", argv[i-1]);
688       return 1;
689    }
690 
691    return 0;
692 }
693 
694 /**
695  *  buffer header callback function for encoder
696  *
697  *  Callback will dump buffer data to the specific file
698  *
699  * @param port Pointer to port from which callback originated
700  * @param buffer mmal buffer header pointer
701  */
encoder_buffer_callback(MMAL_PORT_T * port,MMAL_BUFFER_HEADER_T * buffer)702 static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
703 {
704    int complete = 0;
705 
706    // We pass our file handle and other stuff in via the userdata field.
707 
708    PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata;
709 
710    if (pData)
711    {
712       int bytes_written = buffer->length;
713 
714       if (buffer->length && pData->file_handle)
715       {
716          mmal_buffer_header_mem_lock(buffer);
717 
718          bytes_written = fwrite(buffer->data, 1, buffer->length, pData->file_handle);
719 
720          mmal_buffer_header_mem_unlock(buffer);
721       }
722 
723       // We need to check we wrote what we wanted - it's possible we have run out of storage.
724       if (bytes_written != buffer->length)
725       {
726          vcos_log_error("Unable to write buffer to file - aborting");
727          complete = 1;
728       }
729 
730       // Now flag if we have completed
731       if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED))
732          complete = 1;
733    }
734    else
735    {
736       vcos_log_error("Received a encoder buffer callback with no state");
737    }
738 
739    // release buffer back to the pool
740    mmal_buffer_header_release(buffer);
741 
742    // and send one back to the port (if still open)
743    if (port->is_enabled)
744    {
745       MMAL_STATUS_T status = MMAL_SUCCESS;
746       MMAL_BUFFER_HEADER_T *new_buffer;
747 
748       new_buffer = mmal_queue_get(pData->pstate->encoder_pool->queue);
749 
750       if (new_buffer)
751       {
752          status = mmal_port_send_buffer(port, new_buffer);
753       }
754       if (!new_buffer || status != MMAL_SUCCESS)
755          vcos_log_error("Unable to return a buffer to the encoder port");
756    }
757 
758    if (complete)
759       vcos_semaphore_post(&(pData->complete_semaphore));
760 }
761 
762 /**
763  * Create the camera component, set up its ports
764  *
765  * @param state Pointer to state control struct. camera_component member set to the created camera_component if successful.
766  *
767  * @return MMAL_SUCCESS if all OK, something else otherwise
768  *
769  */
create_camera_component(RASPISTILL_STATE * state)770 static MMAL_STATUS_T create_camera_component(RASPISTILL_STATE *state)
771 {
772    MMAL_COMPONENT_T *camera = 0;
773    MMAL_ES_FORMAT_T *format;
774    MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL;
775    MMAL_STATUS_T status;
776 
777    /* Create the component */
778    status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
779 
780    if (status != MMAL_SUCCESS)
781    {
782       vcos_log_error("Failed to create camera component");
783       goto error;
784    }
785 
786    status = raspicamcontrol_set_stereo_mode(camera->output[0], &state->camera_parameters.stereo_mode);
787    status += raspicamcontrol_set_stereo_mode(camera->output[1], &state->camera_parameters.stereo_mode);
788    status += raspicamcontrol_set_stereo_mode(camera->output[2], &state->camera_parameters.stereo_mode);
789 
790    if (status != MMAL_SUCCESS)
791    {
792       vcos_log_error("Could not set stereo mode : error %d", status);
793       goto error;
794    }
795 
796    MMAL_PARAMETER_INT32_T camera_num =
797    {{MMAL_PARAMETER_CAMERA_NUM, sizeof(camera_num)}, state->common_settings.cameraNum};
798 
799    status = mmal_port_parameter_set(camera->control, &camera_num.hdr);
800 
801    if (status != MMAL_SUCCESS)
802    {
803       vcos_log_error("Could not select camera : error %d", status);
804       goto error;
805    }
806 
807    if (!camera->output_num)
808    {
809       status = MMAL_ENOSYS;
810       vcos_log_error("Camera doesn't have output ports");
811       goto error;
812    }
813 
814    status = mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, state->common_settings.sensor_mode);
815 
816    if (status != MMAL_SUCCESS)
817    {
818       vcos_log_error("Could not set sensor mode : error %d", status);
819       goto error;
820    }
821 
822    preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT];
823    video_port = camera->output[MMAL_CAMERA_VIDEO_PORT];
824    still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT];
825 
826    // Enable the camera, and tell it its control callback function
827    status = mmal_port_enable(camera->control, default_camera_control_callback);
828 
829    if (status != MMAL_SUCCESS)
830    {
831       vcos_log_error("Unable to enable control port : error %d", status);
832       goto error;
833    }
834 
835    //  set up the camera configuration
836    {
837       MMAL_PARAMETER_CAMERA_CONFIG_T cam_config =
838       {
839          { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) },
840          .max_stills_w = state->common_settings.width,
841          .max_stills_h = state->common_settings.height,
842          .stills_yuv422 = 0,
843          .one_shot_stills = 1,
844          .max_preview_video_w = state->preview_parameters.previewWindow.width,
845          .max_preview_video_h = state->preview_parameters.previewWindow.height,
846          .num_preview_video_frames = 3,
847          .stills_capture_circular_buffer_height = 0,
848          .fast_preview_resume = 0,
849          .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC
850       };
851 
852       if (state->fullResPreview)
853       {
854          cam_config.max_preview_video_w = state->common_settings.width;
855          cam_config.max_preview_video_h = state->common_settings.height;
856       }
857 
858       mmal_port_parameter_set(camera->control, &cam_config.hdr);
859    }
860 
861    raspicamcontrol_set_all_parameters(camera, &state->camera_parameters);
862 
863    // Now set up the port formats
864 
865    format = preview_port->format;
866    format->encoding = MMAL_ENCODING_OPAQUE;
867    format->encoding_variant = MMAL_ENCODING_I420;
868 
869    if(state->camera_parameters.shutter_speed > 6000000)
870    {
871       MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
872          { 50, 1000 }, {166, 1000}
873       };
874       mmal_port_parameter_set(preview_port, &fps_range.hdr);
875    }
876    else if(state->camera_parameters.shutter_speed > 1000000)
877    {
878       MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
879          { 166, 1000 }, {999, 1000}
880       };
881       mmal_port_parameter_set(preview_port, &fps_range.hdr);
882    }
883    if (state->fullResPreview)
884    {
885       // In this mode we are forcing the preview to be generated from the full capture resolution.
886       // This runs at a max of 15fps with the OV5647 sensor.
887       format->es->video.width = VCOS_ALIGN_UP(state->common_settings.width, 32);
888       format->es->video.height = VCOS_ALIGN_UP(state->common_settings.height, 16);
889       format->es->video.crop.x = 0;
890       format->es->video.crop.y = 0;
891       format->es->video.crop.width = state->common_settings.width;
892       format->es->video.crop.height = state->common_settings.height;
893       format->es->video.frame_rate.num = FULL_RES_PREVIEW_FRAME_RATE_NUM;
894       format->es->video.frame_rate.den = FULL_RES_PREVIEW_FRAME_RATE_DEN;
895    }
896    else
897    {
898       // Use a full FOV 4:3 mode
899       format->es->video.width = VCOS_ALIGN_UP(state->preview_parameters.previewWindow.width, 32);
900       format->es->video.height = VCOS_ALIGN_UP(state->preview_parameters.previewWindow.height, 16);
901       format->es->video.crop.x = 0;
902       format->es->video.crop.y = 0;
903       format->es->video.crop.width = state->preview_parameters.previewWindow.width;
904       format->es->video.crop.height = state->preview_parameters.previewWindow.height;
905       format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM;
906       format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN;
907    }
908 
909    status = mmal_port_format_commit(preview_port);
910    if (status != MMAL_SUCCESS)
911    {
912       vcos_log_error("camera viewfinder format couldn't be set");
913       goto error;
914    }
915 
916    // Set the same format on the video  port (which we don't use here)
917    mmal_format_full_copy(video_port->format, format);
918    status = mmal_port_format_commit(video_port);
919 
920    if (status  != MMAL_SUCCESS)
921    {
922       vcos_log_error("camera video format couldn't be set");
923       goto error;
924    }
925 
926    // Ensure there are enough buffers to avoid dropping frames
927    if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
928       video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
929 
930    format = still_port->format;
931 
932    if(state->camera_parameters.shutter_speed > 6000000)
933    {
934       MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
935          { 50, 1000 }, {166, 1000}
936       };
937       mmal_port_parameter_set(still_port, &fps_range.hdr);
938    }
939    else if(state->camera_parameters.shutter_speed > 1000000)
940    {
941       MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
942          { 167, 1000 }, {999, 1000}
943       };
944       mmal_port_parameter_set(still_port, &fps_range.hdr);
945    }
946    // Set our stills format on the stills (for encoder) port
947    format->encoding = MMAL_ENCODING_OPAQUE;
948    format->es->video.width = VCOS_ALIGN_UP(state->common_settings.width, 32);
949    format->es->video.height = VCOS_ALIGN_UP(state->common_settings.height, 16);
950    format->es->video.crop.x = 0;
951    format->es->video.crop.y = 0;
952    format->es->video.crop.width = state->common_settings.width;
953    format->es->video.crop.height = state->common_settings.height;
954    format->es->video.frame_rate.num = STILLS_FRAME_RATE_NUM;
955    format->es->video.frame_rate.den = STILLS_FRAME_RATE_DEN;
956 
957    status = mmal_port_format_commit(still_port);
958 
959    if (status != MMAL_SUCCESS)
960    {
961       vcos_log_error("camera still format couldn't be set");
962       goto error;
963    }
964 
965    /* Ensure there are enough buffers to avoid dropping frames */
966    if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
967       still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
968 
969    /* Enable component */
970    status = mmal_component_enable(camera);
971 
972    if (status != MMAL_SUCCESS)
973    {
974       vcos_log_error("camera component couldn't be enabled");
975       goto error;
976    }
977 
978    if (state->useGL)
979    {
980       status = raspitex_configure_preview_port(&state->raspitex_state, preview_port);
981       if (status != MMAL_SUCCESS)
982       {
983          fprintf(stderr, "Failed to configure preview port for GL rendering");
984          goto error;
985       }
986    }
987 
988    state->camera_component = camera;
989 
990    if (state->common_settings.verbose)
991       fprintf(stderr, "Camera component done\n");
992 
993    return status;
994 
995 error:
996 
997    if (camera)
998       mmal_component_destroy(camera);
999 
1000    return status;
1001 }
1002 
1003 /**
1004  * Destroy the camera component
1005  *
1006  * @param state Pointer to state control struct
1007  *
1008  */
destroy_camera_component(RASPISTILL_STATE * state)1009 static void destroy_camera_component(RASPISTILL_STATE *state)
1010 {
1011    if (state->camera_component)
1012    {
1013       mmal_component_destroy(state->camera_component);
1014       state->camera_component = NULL;
1015    }
1016 }
1017 
1018 /**
1019  * Create the encoder component, set up its ports
1020  *
1021  * @param state Pointer to state control struct. encoder_component member set to the created camera_component if successful.
1022  *
1023  * @return a MMAL_STATUS, MMAL_SUCCESS if all OK, something else otherwise
1024  */
create_encoder_component(RASPISTILL_STATE * state)1025 static MMAL_STATUS_T create_encoder_component(RASPISTILL_STATE *state)
1026 {
1027    MMAL_COMPONENT_T *encoder = 0;
1028    MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL;
1029    MMAL_STATUS_T status;
1030    MMAL_POOL_T *pool;
1031 
1032    status = mmal_component_create(MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER, &encoder);
1033 
1034    if (status != MMAL_SUCCESS)
1035    {
1036       vcos_log_error("Unable to create JPEG encoder component");
1037       goto error;
1038    }
1039 
1040    if (!encoder->input_num || !encoder->output_num)
1041    {
1042       status = MMAL_ENOSYS;
1043       vcos_log_error("JPEG encoder doesn't have input/output ports");
1044       goto error;
1045    }
1046 
1047    encoder_input = encoder->input[0];
1048    encoder_output = encoder->output[0];
1049 
1050    // We want same format on input and output
1051    mmal_format_copy(encoder_output->format, encoder_input->format);
1052 
1053    // Specify out output format
1054    encoder_output->format->encoding = state->encoding;
1055 
1056    encoder_output->buffer_size = encoder_output->buffer_size_recommended;
1057 
1058    if (encoder_output->buffer_size < encoder_output->buffer_size_min)
1059       encoder_output->buffer_size = encoder_output->buffer_size_min;
1060 
1061    encoder_output->buffer_num = encoder_output->buffer_num_recommended;
1062 
1063    if (encoder_output->buffer_num < encoder_output->buffer_num_min)
1064       encoder_output->buffer_num = encoder_output->buffer_num_min;
1065 
1066    // Commit the port changes to the output port
1067    status = mmal_port_format_commit(encoder_output);
1068 
1069    if (status != MMAL_SUCCESS)
1070    {
1071       vcos_log_error("Unable to set format on video encoder output port");
1072       goto error;
1073    }
1074 
1075    // Set the JPEG quality level
1076    status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_Q_FACTOR, state->quality);
1077 
1078    if (status != MMAL_SUCCESS)
1079    {
1080       vcos_log_error("Unable to set JPEG quality");
1081       goto error;
1082    }
1083 
1084    // Set the JPEG restart interval
1085    status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_RESTART_INTERVAL, state->restart_interval);
1086 
1087    if (state->restart_interval && status != MMAL_SUCCESS)
1088    {
1089       vcos_log_error("Unable to set JPEG restart interval");
1090       goto error;
1091    }
1092 
1093    // Set up any required thumbnail
1094    {
1095       MMAL_PARAMETER_THUMBNAIL_CONFIG_T param_thumb = {{MMAL_PARAMETER_THUMBNAIL_CONFIGURATION, sizeof(MMAL_PARAMETER_THUMBNAIL_CONFIG_T)}, 0, 0, 0, 0};
1096 
1097       if ( state->thumbnailConfig.enable &&
1098             state->thumbnailConfig.width > 0 && state->thumbnailConfig.height > 0 )
1099       {
1100          // Have a valid thumbnail defined
1101          param_thumb.enable = 1;
1102          param_thumb.width = state->thumbnailConfig.width;
1103          param_thumb.height = state->thumbnailConfig.height;
1104          param_thumb.quality = state->thumbnailConfig.quality;
1105       }
1106       status = mmal_port_parameter_set(encoder->control, &param_thumb.hdr);
1107    }
1108 
1109    //  Enable component
1110    status = mmal_component_enable(encoder);
1111 
1112    if (status  != MMAL_SUCCESS)
1113    {
1114       vcos_log_error("Unable to enable video encoder component");
1115       goto error;
1116    }
1117 
1118    /* Create pool of buffer headers for the output port to consume */
1119    pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size);
1120 
1121    if (!pool)
1122    {
1123       vcos_log_error("Failed to create buffer header pool for encoder output port %s", encoder_output->name);
1124    }
1125 
1126    state->encoder_pool = pool;
1127    state->encoder_component = encoder;
1128 
1129    if (state->common_settings.verbose)
1130       fprintf(stderr, "Encoder component done\n");
1131 
1132    return status;
1133 
1134 error:
1135 
1136    if (encoder)
1137       mmal_component_destroy(encoder);
1138 
1139    return status;
1140 }
1141 
1142 /**
1143  * Destroy the encoder component
1144  *
1145  * @param state Pointer to state control struct
1146  *
1147  */
destroy_encoder_component(RASPISTILL_STATE * state)1148 static void destroy_encoder_component(RASPISTILL_STATE *state)
1149 {
1150    // Get rid of any port buffers first
1151    if (state->encoder_pool)
1152    {
1153       mmal_port_pool_destroy(state->encoder_component->output[0], state->encoder_pool);
1154    }
1155 
1156    if (state->encoder_component)
1157    {
1158       mmal_component_destroy(state->encoder_component);
1159       state->encoder_component = NULL;
1160    }
1161 }
1162 
1163 /**
1164  * Add an exif tag to the capture
1165  *
1166  * @param state Pointer to state control struct
1167  * @param exif_tag String containing a "key=value" pair.
1168  * @return  Returns a MMAL_STATUS_T giving result of operation
1169  */
add_exif_tag(RASPISTILL_STATE * state,const char * exif_tag)1170 static MMAL_STATUS_T add_exif_tag(RASPISTILL_STATE *state, const char *exif_tag)
1171 {
1172    MMAL_STATUS_T status;
1173    MMAL_PARAMETER_EXIF_T *exif_param = (MMAL_PARAMETER_EXIF_T*)calloc(sizeof(MMAL_PARAMETER_EXIF_T) + MAX_EXIF_PAYLOAD_LENGTH, 1);
1174 
1175    vcos_assert(state);
1176    vcos_assert(state->encoder_component);
1177 
1178    // Check to see if the tag is present or is indeed a key=value pair.
1179    if (!exif_tag || strchr(exif_tag, '=') == NULL || strlen(exif_tag) > MAX_EXIF_PAYLOAD_LENGTH-1)
1180       return MMAL_EINVAL;
1181 
1182    exif_param->hdr.id = MMAL_PARAMETER_EXIF;
1183 
1184    strncpy((char*)exif_param->data, exif_tag, MAX_EXIF_PAYLOAD_LENGTH-1);
1185 
1186    exif_param->hdr.size = sizeof(MMAL_PARAMETER_EXIF_T) + strlen((char*)exif_param->data);
1187 
1188    status = mmal_port_parameter_set(state->encoder_component->output[0], &exif_param->hdr);
1189 
1190    free(exif_param);
1191 
1192    return status;
1193 }
1194 
1195 /**
1196  * Add a basic set of EXIF tags to the capture
1197  * Make, Time etc
1198  *
1199  * @param state Pointer to state control struct
1200  *
1201  */
add_exif_tags(RASPISTILL_STATE * state,struct gps_data_t * gpsdata)1202 static void add_exif_tags(RASPISTILL_STATE *state, struct gps_data_t *gpsdata)
1203 {
1204    time_t rawtime;
1205    struct tm *timeinfo;
1206    char model_buf[32];
1207    char time_buf[32];
1208    char exif_buf[128];
1209    int i;
1210 
1211    snprintf(model_buf, 32, "IFD0.Model=RP_%s", state->common_settings.camera_name);
1212    add_exif_tag(state, model_buf);
1213    add_exif_tag(state, "IFD0.Make=RaspberryPi");
1214 
1215    time(&rawtime);
1216    timeinfo = localtime(&rawtime);
1217 
1218    snprintf(time_buf, sizeof(time_buf),
1219             "%04d:%02d:%02d %02d:%02d:%02d",
1220             timeinfo->tm_year+1900,
1221             timeinfo->tm_mon+1,
1222             timeinfo->tm_mday,
1223             timeinfo->tm_hour,
1224             timeinfo->tm_min,
1225             timeinfo->tm_sec);
1226 
1227    snprintf(exif_buf, sizeof(exif_buf), "EXIF.DateTimeDigitized=%s", time_buf);
1228    add_exif_tag(state, exif_buf);
1229 
1230    snprintf(exif_buf, sizeof(exif_buf), "EXIF.DateTimeOriginal=%s", time_buf);
1231    add_exif_tag(state, exif_buf);
1232 
1233    snprintf(exif_buf, sizeof(exif_buf), "IFD0.DateTime=%s", time_buf);
1234    add_exif_tag(state, exif_buf);
1235 
1236    // Add GPS tags
1237    if (state->common_settings.gps)
1238    {
1239       // clear all existing tags first
1240       add_exif_tag(state, "GPS.GPSDateStamp=");
1241       add_exif_tag(state, "GPS.GPSTimeStamp=");
1242       add_exif_tag(state, "GPS.GPSMeasureMode=");
1243       add_exif_tag(state, "GPS.GPSSatellites=");
1244       add_exif_tag(state, "GPS.GPSLatitude=");
1245       add_exif_tag(state, "GPS.GPSLatitudeRef=");
1246       add_exif_tag(state, "GPS.GPSLongitude=");
1247       add_exif_tag(state, "GPS.GPSLongitudeRef=");
1248       add_exif_tag(state, "GPS.GPSAltitude=");
1249       add_exif_tag(state, "GPS.GPSAltitudeRef=");
1250       add_exif_tag(state, "GPS.GPSSpeed=");
1251       add_exif_tag(state, "GPS.GPSSpeedRef=");
1252       add_exif_tag(state, "GPS.GPSTrack=");
1253       add_exif_tag(state, "GPS.GPSTrackRef=");
1254 
1255       if (gpsdata->online)
1256       {
1257          if (state->common_settings.verbose)
1258             fprintf(stderr, "Adding GPS EXIF\n");
1259          if (gpsdata->set & TIME_SET)
1260          {
1261             rawtime = gpsdata->fix.time;
1262             timeinfo = localtime(&rawtime);
1263             strftime(time_buf, sizeof(time_buf), "%Y:%m:%d", timeinfo);
1264             snprintf(exif_buf, sizeof(exif_buf), "GPS.GPSDateStamp=%s", time_buf);
1265             add_exif_tag(state, exif_buf);
1266             strftime(time_buf, sizeof(time_buf), "%H/1,%M/1,%S/1", timeinfo);
1267             snprintf(exif_buf, sizeof(exif_buf), "GPS.GPSTimeStamp=%s", time_buf);
1268             add_exif_tag(state, exif_buf);
1269          }
1270          if (gpsdata->fix.mode >= MODE_2D)
1271          {
1272             snprintf(exif_buf, sizeof(exif_buf), "GPS.GPSMeasureMode=%c",
1273                      (gpsdata->fix.mode >= MODE_3D) ? '3' : '2');
1274             add_exif_tag(state, exif_buf);
1275             if ((gpsdata->satellites_used > 0) && (gpsdata->satellites_visible > 0))
1276             {
1277                snprintf(exif_buf, sizeof(exif_buf), "GPS.GPSSatellites=Used:%d,Visible:%d",
1278                         gpsdata->satellites_used, gpsdata->satellites_visible);
1279                add_exif_tag(state, exif_buf);
1280             }
1281             else if (gpsdata->satellites_used > 0)
1282             {
1283                snprintf(exif_buf, sizeof(exif_buf), "GPS.GPSSatellites=Used:%d",
1284                         gpsdata->satellites_used);
1285                add_exif_tag(state, exif_buf);
1286             }
1287             else if (gpsdata->satellites_visible > 0)
1288             {
1289                snprintf(exif_buf, sizeof(exif_buf), "GPS.GPSSatellites=Visible:%d",
1290                         gpsdata->satellites_visible);
1291                add_exif_tag(state, exif_buf);
1292             }
1293 
1294             if (gpsdata->set & LATLON_SET)
1295             {
1296                if (isnan(gpsdata->fix.latitude) == 0)
1297                {
1298                   if (deg_to_str(fabs(gpsdata->fix.latitude), time_buf, sizeof(time_buf)) == 0)
1299                   {
1300                      snprintf(exif_buf, sizeof(exif_buf), "GPS.GPSLatitude=%s", time_buf);
1301                      add_exif_tag(state, exif_buf);
1302                      snprintf(exif_buf, sizeof(exif_buf), "GPS.GPSLatitudeRef=%c",
1303                               (gpsdata->fix.latitude < 0) ? 'S' : 'N');
1304                      add_exif_tag(state, exif_buf);
1305                   }
1306                }
1307                if (isnan(gpsdata->fix.longitude) == 0)
1308                {
1309                   if (deg_to_str(fabs(gpsdata->fix.longitude), time_buf, sizeof(time_buf)) == 0)
1310                   {
1311                      snprintf(exif_buf, sizeof(exif_buf), "GPS.GPSLongitude=%s", time_buf);
1312                      add_exif_tag(state, exif_buf);
1313                      snprintf(exif_buf, sizeof(exif_buf), "GPS.GPSLongitudeRef=%c",
1314                               (gpsdata->fix.longitude < 0) ? 'W' : 'E');
1315                      add_exif_tag(state, exif_buf);
1316                   }
1317                }
1318             }
1319             if ((gpsdata->set & ALTITUDE_SET) && (gpsdata->fix.mode >= MODE_3D))
1320             {
1321                if (isnan(gpsdata->fix.altitude) == 0)
1322                {
1323                   snprintf(exif_buf, sizeof(exif_buf), "GPS.GPSAltitude=%d/10",
1324                            (int)(gpsdata->fix.altitude*10+0.5));
1325                   add_exif_tag(state, exif_buf);
1326                   add_exif_tag(state, "GPS.GPSAltitudeRef=0");
1327                }
1328             }
1329             if (gpsdata->set & SPEED_SET)
1330             {
1331                if (isnan(gpsdata->fix.speed) == 0)
1332                {
1333                   snprintf(exif_buf, sizeof(exif_buf), "GPS.GPSSpeed=%d/10",
1334                            (int)(gpsdata->fix.speed*MPS_TO_KPH*10+0.5));
1335                   add_exif_tag(state, exif_buf);
1336                   add_exif_tag(state, "GPS.GPSSpeedRef=K");
1337                }
1338             }
1339             if (gpsdata->set & TRACK_SET)
1340             {
1341                if (isnan(gpsdata->fix.track) == 0)
1342                {
1343                   snprintf(exif_buf, sizeof(exif_buf), "GPS.GPSTrack=%d/100",
1344                            (int)(gpsdata->fix.track*100+0.5));
1345                   add_exif_tag(state, exif_buf);
1346                   add_exif_tag(state, "GPS.GPSTrackRef=T");
1347                }
1348             }
1349          }
1350       }
1351    }
1352 
1353    // Now send any user supplied tags
1354 
1355    for (i=0; i<state->numExifTags && i < MAX_USER_EXIF_TAGS; i++)
1356    {
1357       if (state->exifTags[i])
1358       {
1359          add_exif_tag(state, state->exifTags[i]);
1360       }
1361    }
1362 }
1363 
1364 /**
1365  * Stores an EXIF tag in the state, incrementing various pointers as necessary.
1366  * Any tags stored in this way will be added to the image file when add_exif_tags
1367  * is called
1368  *
1369  * Will not store if run out of storage space
1370  *
1371  * @param state Pointer to state control struct
1372  * @param exif_tag EXIF tag string
1373  *
1374  */
store_exif_tag(RASPISTILL_STATE * state,const char * exif_tag)1375 static void store_exif_tag(RASPISTILL_STATE *state, const char *exif_tag)
1376 {
1377    if (state->numExifTags < MAX_USER_EXIF_TAGS)
1378    {
1379       state->exifTags[state->numExifTags] = exif_tag;
1380       state->numExifTags++;
1381    }
1382 }
1383 
1384 /**
1385  * Allocates and generates a filename based on the
1386  * user-supplied pattern and the frame number.
1387  * On successful return, finalName and tempName point to malloc()ed strings
1388  * which must be freed externally.  (On failure, returns nulls that
1389  * don't need free()ing.)
1390  *
1391  * @param finalName pointer receives an
1392  * @param pattern sprintf pattern with %d to be replaced by frame
1393  * @param frame for timelapse, the frame number
1394  * @return Returns a MMAL_STATUS_T giving result of operation
1395 */
1396 
create_filenames(char ** finalName,char ** tempName,char * pattern,int frame)1397 MMAL_STATUS_T create_filenames(char** finalName, char** tempName, char * pattern, int frame)
1398 {
1399    *finalName = NULL;
1400    *tempName = NULL;
1401    if (0 > asprintf(finalName, pattern, frame) ||
1402          0 > asprintf(tempName, "%s~", *finalName))
1403    {
1404       if (*finalName != NULL)
1405       {
1406          free(*finalName);
1407       }
1408       return MMAL_ENOMEM;    // It may be some other error, but it is not worth getting it right
1409    }
1410    return MMAL_SUCCESS;
1411 }
1412 
1413 /**
1414  * Function to wait in various ways (depending on settings) for the next frame
1415  *
1416  * @param state Pointer to the state data
1417  * @param [in][out] frame The last frame number, adjusted to next frame number on output
1418  * @return !0 if to continue, 0 if reached end of run
1419  */
wait_for_next_frame(RASPISTILL_STATE * state,int * frame)1420 static int wait_for_next_frame(RASPISTILL_STATE *state, int *frame)
1421 {
1422    static int64_t complete_time = -1;
1423    int keep_running = 1;
1424 
1425    int64_t current_time =  get_microseconds64()/1000;
1426 
1427    if (complete_time == -1)
1428       complete_time =  current_time + state->timeout;
1429 
1430    // if we have run out of time, flag we need to exit
1431    // If timeout = 0 then always continue
1432    if (current_time >= complete_time && state->timeout != 0)
1433       keep_running = 0;
1434 
1435    switch (state->frameNextMethod)
1436    {
1437    case FRAME_NEXT_SINGLE :
1438       // simple timeout for a single capture
1439       vcos_sleep(state->timeout);
1440       return 0;
1441 
1442    case FRAME_NEXT_FOREVER :
1443    {
1444       *frame+=1;
1445 
1446       // Have a sleep so we don't hog the CPU.
1447       vcos_sleep(10000);
1448 
1449       // Run forever so never indicate end of loop
1450       return 1;
1451    }
1452 
1453    case FRAME_NEXT_TIMELAPSE :
1454    {
1455       static int64_t next_frame_ms = -1;
1456 
1457       // Always need to increment by at least one, may add a skip later
1458       *frame += 1;
1459 
1460       if (next_frame_ms == -1)
1461       {
1462          vcos_sleep(CAMERA_SETTLE_TIME);
1463 
1464          // Update our current time after the sleep
1465          current_time =  get_microseconds64()/1000;
1466 
1467          // Set our initial 'next frame time'
1468          next_frame_ms = current_time + state->timelapse;
1469       }
1470       else
1471       {
1472          int64_t this_delay_ms = next_frame_ms - current_time;
1473 
1474          if (this_delay_ms < 0)
1475          {
1476             // We are already past the next exposure time
1477             if (-this_delay_ms < state->timelapse/2)
1478             {
1479                // Less than a half frame late, take a frame and hope to catch up next time
1480                next_frame_ms += state->timelapse;
1481                vcos_log_error("Frame %d is %d ms late", *frame, (int)(-this_delay_ms));
1482             }
1483             else
1484             {
1485                int nskip = 1 + (-this_delay_ms)/state->timelapse;
1486                vcos_log_error("Skipping frame %d to restart at frame %d", *frame, *frame+nskip);
1487                *frame += nskip;
1488                this_delay_ms += nskip * state->timelapse;
1489                vcos_sleep(this_delay_ms);
1490                next_frame_ms += (nskip + 1) * state->timelapse;
1491             }
1492          }
1493          else
1494          {
1495             vcos_sleep(this_delay_ms);
1496             next_frame_ms += state->timelapse;
1497          }
1498       }
1499 
1500       return keep_running;
1501    }
1502 
1503    case FRAME_NEXT_KEYPRESS :
1504    {
1505       int ch;
1506 
1507       if (state->common_settings.verbose)
1508          fprintf(stderr, "Press Enter to capture, X then ENTER to exit\n");
1509 
1510       ch = getchar();
1511       *frame+=1;
1512       if (ch == 'x' || ch == 'X')
1513          return 0;
1514       else
1515       {
1516          return keep_running;
1517       }
1518    }
1519 
1520    case FRAME_NEXT_IMMEDIATELY :
1521    {
1522       // Not waiting, just go to next frame.
1523       // Actually, we do need a slight delay here otherwise exposure goes
1524       // badly wrong since we never allow it frames to work it out
1525       // This could probably be tuned down.
1526       // First frame has a much longer delay to ensure we get exposure to a steady state
1527       if (*frame == 0)
1528          vcos_sleep(CAMERA_SETTLE_TIME);
1529       else
1530          vcos_sleep(30);
1531 
1532       *frame+=1;
1533 
1534       return keep_running;
1535    }
1536 
1537    case FRAME_NEXT_GPIO :
1538    {
1539       // Intended for GPIO firing of a capture
1540       return 0;
1541    }
1542 
1543    case FRAME_NEXT_SIGNAL :
1544    {
1545       // Need to wait for a SIGUSR1 or SIGUSR2 signal
1546       sigset_t waitset;
1547       int sig;
1548       int result = 0;
1549 
1550       sigemptyset( &waitset );
1551       sigaddset( &waitset, SIGUSR1 );
1552       sigaddset( &waitset, SIGUSR2 );
1553 
1554       // We are multi threaded because we use mmal, so need to use the pthread
1555       // variant of procmask to block until a SIGUSR1 or SIGUSR2 signal appears
1556       pthread_sigmask( SIG_BLOCK, &waitset, NULL );
1557 
1558       if (state->common_settings.verbose)
1559       {
1560          fprintf(stderr, "Waiting for SIGUSR1 to initiate capture and continue or SIGUSR2 to capture and exit\n");
1561       }
1562 
1563       result = sigwait( &waitset, &sig );
1564 
1565       if (result == 0)
1566       {
1567          if (sig == SIGUSR1)
1568          {
1569             if (state->common_settings.verbose)
1570                fprintf(stderr, "Received SIGUSR1\n");
1571          }
1572          else if (sig == SIGUSR2)
1573          {
1574             if (state->common_settings.verbose)
1575                fprintf(stderr, "Received SIGUSR2\n");
1576             keep_running = 0;
1577          }
1578       }
1579       else
1580       {
1581          if (state->common_settings.verbose)
1582             fprintf(stderr, "Bad signal received - error %d\n", errno);
1583       }
1584 
1585       *frame+=1;
1586 
1587       return keep_running;
1588    }
1589    } // end of switch
1590 
1591    // Should have returned by now, but default to timeout
1592    return keep_running;
1593 }
1594 
rename_file(RASPISTILL_STATE * state,FILE * output_file,const char * final_filename,const char * use_filename,int frame)1595 static void rename_file(RASPISTILL_STATE *state, FILE *output_file,
1596                         const char *final_filename, const char *use_filename, int frame)
1597 {
1598    MMAL_STATUS_T status;
1599 
1600    fclose(output_file);
1601    vcos_assert(use_filename != NULL && final_filename != NULL);
1602    if (0 != rename(use_filename, final_filename))
1603    {
1604       vcos_log_error("Could not rename temp file to: %s; %s",
1605                      final_filename,strerror(errno));
1606    }
1607    if (state->linkname)
1608    {
1609       char *use_link;
1610       char *final_link;
1611       status = create_filenames(&final_link, &use_link, state->linkname, frame);
1612 
1613       // Create hard link if possible, symlink otherwise
1614       if (status != MMAL_SUCCESS
1615             || (0 != link(final_filename, use_link)
1616                 &&  0 != symlink(final_filename, use_link))
1617             || 0 != rename(use_link, final_link))
1618       {
1619          vcos_log_error("Could not link as filename: %s; %s",
1620                         state->linkname,strerror(errno));
1621       }
1622       if (use_link) free(use_link);
1623       if (final_link) free(final_link);
1624    }
1625 }
1626 
1627 /**
1628  * main
1629  */
main(int argc,const char ** argv)1630 int main(int argc, const char **argv)
1631 {
1632    // Our main data storage vessel..
1633    RASPISTILL_STATE state;
1634    int exit_code = EX_OK;
1635 
1636    MMAL_STATUS_T status = MMAL_SUCCESS;
1637    MMAL_PORT_T *camera_preview_port = NULL;
1638    MMAL_PORT_T *camera_video_port = NULL;
1639    MMAL_PORT_T *camera_still_port = NULL;
1640    MMAL_PORT_T *preview_input_port = NULL;
1641    MMAL_PORT_T *encoder_input_port = NULL;
1642    MMAL_PORT_T *encoder_output_port = NULL;
1643 
1644    bcm_host_init();
1645 
1646    // Register our application with the logging system
1647    vcos_log_register("RaspiStill", VCOS_LOG_CATEGORY);
1648 
1649    signal(SIGINT, default_signal_handler);
1650 
1651    // Disable USR1 and USR2 for the moment - may be reenabled if go in to signal capture mode
1652    signal(SIGUSR1, SIG_IGN);
1653    signal(SIGUSR2, SIG_IGN);
1654 
1655    set_app_name(argv[0]);
1656 
1657    // Do we have any parameters
1658    if (argc == 1)
1659    {
1660       display_valid_parameters(basename(argv[0]), &application_help_message);
1661       exit(EX_USAGE);
1662    }
1663 
1664    default_status(&state);
1665 
1666    // Parse the command line and put options in to our status structure
1667    if (parse_cmdline(argc, argv, &state))
1668    {
1669       exit(EX_USAGE);
1670    }
1671 
1672    if (state.timeout == -1)
1673       state.timeout = 5000;
1674 
1675    // Setup for sensor specific parameters
1676    get_sensor_defaults(state.common_settings.cameraNum, state.common_settings.camera_name,
1677                        &state.common_settings.width, &state.common_settings.height);
1678 
1679    if (state.common_settings.verbose)
1680    {
1681       print_app_details(stderr);
1682       dump_status(&state);
1683    }
1684 
1685    if (state.common_settings.gps)
1686    {
1687       if (raspi_gps_setup(state.common_settings.verbose))
1688          state.common_settings.gps = false;
1689    }
1690 
1691    if (state.useGL)
1692       raspitex_init(&state.raspitex_state);
1693 
1694    // OK, we have a nice set of parameters. Now set up our components
1695    // We have three components. Camera, Preview and encoder.
1696    // Camera and encoder are different in stills/video, but preview
1697    // is the same so handed off to a separate module
1698 
1699    if ((status = create_camera_component(&state)) != MMAL_SUCCESS)
1700    {
1701       vcos_log_error("%s: Failed to create camera component", __func__);
1702       exit_code = EX_SOFTWARE;
1703    }
1704    else if ((!state.useGL) && (status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS)
1705    {
1706       vcos_log_error("%s: Failed to create preview component", __func__);
1707       destroy_camera_component(&state);
1708       exit_code = EX_SOFTWARE;
1709    }
1710    else if ((status = create_encoder_component(&state)) != MMAL_SUCCESS)
1711    {
1712       vcos_log_error("%s: Failed to create encode component", __func__);
1713       raspipreview_destroy(&state.preview_parameters);
1714       destroy_camera_component(&state);
1715       exit_code = EX_SOFTWARE;
1716    }
1717    else
1718    {
1719       PORT_USERDATA callback_data;
1720 
1721       if (state.common_settings.verbose)
1722          fprintf(stderr, "Starting component connection stage\n");
1723 
1724       camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
1725       camera_video_port   = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT];
1726       camera_still_port   = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
1727       encoder_input_port  = state.encoder_component->input[0];
1728       encoder_output_port = state.encoder_component->output[0];
1729 
1730       if (! state.useGL)
1731       {
1732          if (state.common_settings.verbose)
1733             fprintf(stderr, "Connecting camera preview port to video render.\n");
1734 
1735          // Note we are lucky that the preview and null sink components use the same input port
1736          // so we can simple do this without conditionals
1737          preview_input_port  = state.preview_parameters.preview_component->input[0];
1738 
1739          // Connect camera to preview (which might be a null_sink if no preview required)
1740          status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection);
1741       }
1742 
1743       if (status == MMAL_SUCCESS)
1744       {
1745          VCOS_STATUS_T vcos_status;
1746 
1747          if (state.common_settings.verbose)
1748             fprintf(stderr, "Connecting camera stills port to encoder input port\n");
1749 
1750          // Now connect the camera to the encoder
1751          status = connect_ports(camera_still_port, encoder_input_port, &state.encoder_connection);
1752 
1753          if (status != MMAL_SUCCESS)
1754          {
1755             vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__);
1756             goto error;
1757          }
1758 
1759          // Set up our userdata - this is passed though to the callback where we need the information.
1760          // Null until we open our filename
1761          callback_data.file_handle = NULL;
1762          callback_data.pstate = &state;
1763          vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0);
1764 
1765          vcos_assert(vcos_status == VCOS_SUCCESS);
1766 
1767          /* If GL preview is requested then start the GL threads */
1768          if (state.useGL && (raspitex_start(&state.raspitex_state) != 0))
1769             goto error;
1770 
1771          if (status != MMAL_SUCCESS)
1772          {
1773             vcos_log_error("Failed to setup encoder output");
1774             goto error;
1775          }
1776 
1777          if (state.demoMode)
1778          {
1779             // Run for the user specific time..
1780             int num_iterations = state.timeout / state.demoInterval;
1781             int i;
1782             for (i=0; i<num_iterations; i++)
1783             {
1784                raspicamcontrol_cycle_test(state.camera_component);
1785                vcos_sleep(state.demoInterval);
1786             }
1787          }
1788          else
1789          {
1790             int frame, keep_looping = 1;
1791             FILE *output_file = NULL;
1792             char *use_filename = NULL;      // Temporary filename while image being written
1793             char *final_filename = NULL;    // Name that file gets once writing complete
1794 
1795             frame = state.frameStart - 1;
1796 
1797             while (keep_looping)
1798             {
1799                keep_looping = wait_for_next_frame(&state, &frame);
1800 
1801                if (state.datetime)
1802                {
1803                   time_t rawtime;
1804                   struct tm *timeinfo;
1805 
1806                   time(&rawtime);
1807                   timeinfo = localtime(&rawtime);
1808 
1809                   frame = timeinfo->tm_mon+1;
1810                   frame *= 100;
1811                   frame += timeinfo->tm_mday;
1812                   frame *= 100;
1813                   frame += timeinfo->tm_hour;
1814                   frame *= 100;
1815                   frame += timeinfo->tm_min;
1816                   frame *= 100;
1817                   frame += timeinfo->tm_sec;
1818                }
1819                if (state.timestamp)
1820                {
1821                   frame = (int)time(NULL);
1822                }
1823 
1824                // Open the file
1825                if (state.common_settings.filename)
1826                {
1827                   if (state.common_settings.filename[0] == '-')
1828                   {
1829                      output_file = stdout;
1830                   }
1831                   else
1832                   {
1833                      vcos_assert(use_filename == NULL && final_filename == NULL);
1834                      status = create_filenames(&final_filename, &use_filename, state.common_settings.filename, frame);
1835                      if (status  != MMAL_SUCCESS)
1836                      {
1837                         vcos_log_error("Unable to create filenames");
1838                         goto error;
1839                      }
1840 
1841                      if (state.common_settings.verbose)
1842                         fprintf(stderr, "Opening output file %s\n", final_filename);
1843                      // Technically it is opening the temp~ filename which will be renamed to the final filename
1844 
1845                      output_file = fopen(use_filename, "wb");
1846 
1847                      if (!output_file)
1848                      {
1849                         // Notify user, carry on but discarding encoded output buffers
1850                         vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, use_filename);
1851                      }
1852                   }
1853 
1854                   callback_data.file_handle = output_file;
1855                }
1856 
1857                // We only capture if a filename was specified and it opened
1858                if (state.useGL && state.glCapture && output_file)
1859                {
1860                   /* Save the next GL framebuffer as the next camera still */
1861                   int rc = raspitex_capture(&state.raspitex_state, output_file);
1862                   if (rc != 0)
1863                      vcos_log_error("Failed to capture GL preview");
1864                   rename_file(&state, output_file, final_filename, use_filename, frame);
1865                }
1866                else if (output_file)
1867                {
1868                   int num, q;
1869 
1870                   // Must do this before the encoder output port is enabled since
1871                   // once enabled no further exif data is accepted
1872                   if ( state.enableExifTags )
1873                   {
1874                      struct gps_data_t *gps_data = raspi_gps_lock();
1875                      add_exif_tags(&state, gps_data);
1876                      raspi_gps_unlock();
1877                   }
1878                   else
1879                   {
1880                      mmal_port_parameter_set_boolean(
1881                         state.encoder_component->output[0], MMAL_PARAMETER_EXIF_DISABLE, 1);
1882                   }
1883 
1884                   // Same with raw, apparently need to set it for each capture, whilst port
1885                   // is not enabled
1886                   if (state.wantRAW)
1887                   {
1888                      if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_ENABLE_RAW_CAPTURE, 1) != MMAL_SUCCESS)
1889                      {
1890                         vcos_log_error("RAW was requested, but failed to enable");
1891                      }
1892                   }
1893 
1894                   // There is a possibility that shutter needs to be set each loop.
1895                   if (mmal_status_to_int(mmal_port_parameter_set_uint32(state.camera_component->control, MMAL_PARAMETER_SHUTTER_SPEED, state.camera_parameters.shutter_speed)) != MMAL_SUCCESS)
1896                      vcos_log_error("Unable to set shutter speed");
1897 
1898                   // Enable the encoder output port
1899                   encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data;
1900 
1901                   if (state.common_settings.verbose)
1902                      fprintf(stderr, "Enabling encoder output port\n");
1903 
1904                   // Enable the encoder output port and tell it its callback function
1905                   status = mmal_port_enable(encoder_output_port, encoder_buffer_callback);
1906 
1907                   // Send all the buffers to the encoder output port
1908                   num = mmal_queue_length(state.encoder_pool->queue);
1909 
1910                   for (q=0; q<num; q++)
1911                   {
1912                      MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.encoder_pool->queue);
1913 
1914                      if (!buffer)
1915                         vcos_log_error("Unable to get a required buffer %d from pool queue", q);
1916 
1917                      if (mmal_port_send_buffer(encoder_output_port, buffer)!= MMAL_SUCCESS)
1918                         vcos_log_error("Unable to send a buffer to encoder output port (%d)", q);
1919                   }
1920 
1921                   if (state.burstCaptureMode)
1922                   {
1923                      mmal_port_parameter_set_boolean(state.camera_component->control,  MMAL_PARAMETER_CAMERA_BURST_CAPTURE, 1);
1924                   }
1925 
1926                   if(state.camera_parameters.enable_annotate)
1927                   {
1928                      if ((state.camera_parameters.enable_annotate & ANNOTATE_APP_TEXT) && state.common_settings.gps)
1929                      {
1930                         char *text = raspi_gps_location_string();
1931                         raspicamcontrol_set_annotate(state.camera_component, state.camera_parameters.enable_annotate,
1932                                                      text,
1933                                                      state.camera_parameters.annotate_text_size,
1934                                                      state.camera_parameters.annotate_text_colour,
1935                                                      state.camera_parameters.annotate_bg_colour,
1936                                                      state.camera_parameters.annotate_justify,
1937                                                      state.camera_parameters.annotate_x,
1938                                                      state.camera_parameters.annotate_y
1939                                                     );
1940                         free(text);
1941                      }
1942                      else
1943                         raspicamcontrol_set_annotate(state.camera_component, state.camera_parameters.enable_annotate,
1944                                                      state.camera_parameters.annotate_string,
1945                                                      state.camera_parameters.annotate_text_size,
1946                                                      state.camera_parameters.annotate_text_colour,
1947                                                      state.camera_parameters.annotate_bg_colour,
1948                                                      state.camera_parameters.annotate_justify,
1949                                                      state.camera_parameters.annotate_x,
1950                                                      state.camera_parameters.annotate_y
1951                                                     );
1952                   }
1953 
1954                   if (state.common_settings.verbose)
1955                      fprintf(stderr, "Starting capture %d\n", frame);
1956 
1957                   if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
1958                   {
1959                      vcos_log_error("%s: Failed to start capture", __func__);
1960                   }
1961                   else
1962                   {
1963                      // Wait for capture to complete
1964                      // For some reason using vcos_semaphore_wait_timeout sometimes returns immediately with bad parameter error
1965                      // even though it appears to be all correct, so reverting to untimed one until figure out why its erratic
1966                      vcos_semaphore_wait(&callback_data.complete_semaphore);
1967                      if (state.common_settings.verbose)
1968                         fprintf(stderr, "Finished capture %d\n", frame);
1969                   }
1970 
1971                   // Ensure we don't die if get callback with no open file
1972                   callback_data.file_handle = NULL;
1973 
1974                   if (output_file != stdout)
1975                   {
1976                      rename_file(&state, output_file, final_filename, use_filename, frame);
1977                   }
1978                   else
1979                   {
1980                      fflush(output_file);
1981                   }
1982                   // Disable encoder output port
1983                   status = mmal_port_disable(encoder_output_port);
1984                }
1985 
1986                if (use_filename)
1987                {
1988                   free(use_filename);
1989                   use_filename = NULL;
1990                }
1991                if (final_filename)
1992                {
1993                   free(final_filename);
1994                   final_filename = NULL;
1995                }
1996             } // end for (frame)
1997 
1998             vcos_semaphore_delete(&callback_data.complete_semaphore);
1999          }
2000       }
2001       else
2002       {
2003          mmal_status_to_int(status);
2004          vcos_log_error("%s: Failed to connect camera to preview", __func__);
2005       }
2006 
2007 error:
2008 
2009       mmal_status_to_int(status);
2010 
2011       if (state.common_settings.verbose)
2012          fprintf(stderr, "Closing down\n");
2013 
2014       if (state.useGL)
2015       {
2016          raspitex_stop(&state.raspitex_state);
2017          raspitex_destroy(&state.raspitex_state);
2018       }
2019 
2020       // Disable all our ports that are not handled by connections
2021       check_disable_port(camera_video_port);
2022       check_disable_port(encoder_output_port);
2023 
2024       if (state.preview_connection)
2025          mmal_connection_destroy(state.preview_connection);
2026 
2027       if (state.encoder_connection)
2028          mmal_connection_destroy(state.encoder_connection);
2029 
2030       /* Disable components */
2031       if (state.encoder_component)
2032          mmal_component_disable(state.encoder_component);
2033 
2034       if (state.preview_parameters.preview_component)
2035          mmal_component_disable(state.preview_parameters.preview_component);
2036 
2037       if (state.camera_component)
2038          mmal_component_disable(state.camera_component);
2039 
2040       destroy_encoder_component(&state);
2041       raspipreview_destroy(&state.preview_parameters);
2042       destroy_camera_component(&state);
2043 
2044       if (state.common_settings.verbose)
2045          fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
2046 
2047       if (state.common_settings.gps)
2048          raspi_gps_shutdown(state.common_settings.verbose);
2049    }
2050 
2051    if (status != MMAL_SUCCESS)
2052       raspicamcontrol_check_configuration(128);
2053 
2054    return exit_code;
2055 }
2056 
2057