rpicamsrc: fix indentation
[platform/upstream/gstreamer.git] / sys / rpicamsrc / RaspiStill.c
1 /* *INDENT-OFF* */
2 /*
3  * Copyright (c) 2013 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 RaspiStill.c
34  * Command line program to capture a still frame and encode it to file.
35  * Also optionally display a preview/viewfinder of current camera input.
36  *
37  * \date 31 Jan 2013
38  * \Author: James Hughes
39  *
40  * Description
41  *
42  * 3 components are created; camera, preview and JPG encoder.
43  * Camera component has three ports, preview, video and stills.
44  * This program connects preview and stills to the preview and jpg
45  * encoder. Using mmal we don't need to worry about buffers between these
46  * components, but we do need to handle buffers from the encoder, which
47  * are simply written straight to the file in the requisite buffer callback.
48  *
49  * We use the RaspiCamControl code to handle the specific camera settings.
50  */
51
52 // We use some GNU extensions (asprintf, basename)
53 #define _GNU_SOURCE
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <memory.h>
59 #include <unistd.h>
60 #include <errno.h>
61 #include <sysexits.h>
62
63 #define VERSION_STRING "v1.3.2"
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
77 #include "RaspiCamControl.h"
78 #include "RaspiPreview.h"
79 #include "RaspiCLI.h"
80
81 #include <semaphore.h>
82
83 /// Camera number to use - we only have one camera, indexed from 0.
84 #define CAMERA_NUMBER 0
85
86 // Standard port setting for the camera component
87 #define MMAL_CAMERA_PREVIEW_PORT 0
88 #define MMAL_CAMERA_VIDEO_PORT 1
89 #define MMAL_CAMERA_CAPTURE_PORT 2
90
91
92 // Stills format information
93 #define STILLS_FRAME_RATE_NUM 15
94 #define STILLS_FRAME_RATE_DEN 1
95
96 /// Video render needs at least 2 buffers.
97 #define VIDEO_OUTPUT_BUFFERS_NUM 3
98
99 #define MAX_USER_EXIF_TAGS      32
100 #define MAX_EXIF_PAYLOAD_LENGTH 128
101
102 int mmal_status_to_int(MMAL_STATUS_T status);
103
104 /** Structure containing all state information for the current run
105  */
106 typedef struct
107 {
108    int timeout;                        /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds
109    int width;                          /// Requested width of image
110    int height;                         /// requested height of image
111    int quality;                        /// JPEG quality setting (1-100)
112    int wantRAW;                        /// Flag for whether the JPEG metadata also contains the RAW bayer image
113    char *filename;                     /// filename of output file
114    char *linkname;                     /// filename of output file
115    MMAL_PARAM_THUMBNAIL_CONFIG_T thumbnailConfig;
116    int verbose;                        /// !0 if want detailed run information
117    int demoMode;                       /// Run app in demo mode
118    int demoInterval;                   /// Interval between camera settings changes
119    MMAL_FOURCC_T encoding;             /// Encoding to use for the output file.
120    const char *exifTags[MAX_USER_EXIF_TAGS]; /// Array of pointers to tags supplied from the command line
121    int numExifTags;                    /// Number of supplied tags
122    int timelapse;                      /// Delay between each picture in timelapse mode. If 0, disable timelapse
123    int fullResPreview;                 /// If set, the camera preview port runs at capture resolution. Reduces fps.
124
125    RASPIPREVIEW_PARAMETERS preview_parameters;    /// Preview setup parameters
126    RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters
127
128    MMAL_COMPONENT_T *camera_component;    /// Pointer to the camera component
129    MMAL_COMPONENT_T *encoder_component;   /// Pointer to the encoder component
130    MMAL_COMPONENT_T *null_sink_component; /// Pointer to the null sink component
131    MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera to preview
132    MMAL_CONNECTION_T *encoder_connection; /// Pointer to the connection from camera to encoder
133
134    MMAL_POOL_T *encoder_pool; /// Pointer to the pool of buffers used by encoder output port
135
136 } RASPISTILL_STATE;
137
138 /** Struct used to pass information in encoder port userdata to callback
139  */
140 typedef struct
141 {
142    FILE *file_handle;                   /// File handle to write buffer data to.
143    VCOS_SEMAPHORE_T complete_semaphore; /// semaphore which is posted when we reach end of frame (indicates end of capture or fault)
144    RASPISTILL_STATE *pstate;            /// pointer to our state in case required in callback
145 } PORT_USERDATA;
146
147 static void display_valid_parameters(char *app_name);
148 static void store_exif_tag(RASPISTILL_STATE *state, const char *exif_tag);
149
150 /// Comamnd ID's and Structure defining our command line options
151 #define CommandHelp         0
152 #define CommandWidth        1
153 #define CommandHeight       2
154 #define CommandQuality      3
155 #define CommandRaw          4
156 #define CommandOutput       5
157 #define CommandVerbose      6
158 #define CommandTimeout      7
159 #define CommandThumbnail    8
160 #define CommandDemoMode     9
161 #define CommandEncoding     10
162 #define CommandExifTag      11
163 #define CommandTimelapse    12
164 #define CommandFullResPreview 13
165 #define CommandLink         14
166
167 static COMMAND_LIST cmdline_commands[] =
168 {
169    { CommandHelp,    "-help",       "?",  "This help information", 0 },
170    { CommandWidth,   "-width",      "w",  "Set image width <size>", 1 },
171    { CommandHeight,  "-height",     "h",  "Set image height <size>", 1 },
172    { CommandQuality, "-quality",    "q",  "Set jpeg quality <0 to 100>", 1 },
173    { CommandRaw,     "-raw",        "r",  "Add raw bayer data to jpeg metadata", 0 },
174    { CommandOutput,  "-output",     "o",  "Output filename <filename> (to write to stdout, use '-o -'). If not specified, no file is saved", 1 },
175    { CommandLink,    "-latest",     "l",  "Link latest complete image to filename <filename>", 1},
176    { CommandVerbose, "-verbose",    "v",  "Output verbose information during run", 0 },
177    { CommandTimeout, "-timeout",    "t",  "Time (in ms) before takes picture and shuts down (if not specified, set to 5s)", 1 },
178    { CommandThumbnail,"-thumb",     "th", "Set thumbnail parameters (x:y:quality)", 1},
179    { CommandDemoMode,"-demo",       "d",  "Run a demo mode (cycle through range of camera options, no capture)", 0},
180    { CommandEncoding,"-encoding",   "e",  "Encoding to use for output file (jpg, bmp, gif, png)", 1},
181    { CommandExifTag, "-exif",       "x",  "EXIF tag to apply to captures (format as 'key=value')", 1},
182    { CommandTimelapse,"-timelapse", "tl", "Timelapse mode. Takes a picture every <t>ms", 1},
183    { CommandFullResPreview,"-fullpreview", "fp", "Run the preview using the still capture resolution (may reduce preview fps)", 0},
184 };
185
186 static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
187
188 static struct
189 {
190    char *format;
191    MMAL_FOURCC_T encoding;
192 } encoding_xref[] =
193 {
194    {"jpg", MMAL_ENCODING_JPEG},
195    {"bmp", MMAL_ENCODING_BMP},
196    {"gif", MMAL_ENCODING_GIF},
197    {"png", MMAL_ENCODING_PNG}
198 };
199
200 static int encoding_xref_size = sizeof(encoding_xref) / sizeof(encoding_xref[0]);
201
202
203 /**
204  * Assign a default set of parameters to the state passed in
205  *
206  * @param state Pointer to state structure to assign defaults to
207  */
208 static void default_status(RASPISTILL_STATE *state)
209 {
210    if (!state)
211    {
212       vcos_assert(0);
213       return;
214    }
215
216    state->timeout = 5000; // 5s delay before take image
217    state->width = 2592;
218    state->height = 1944;
219    state->quality = 85;
220    state->wantRAW = 0;
221    state->filename = NULL;
222    state->linkname = NULL;
223    state->verbose = 0;
224    state->thumbnailConfig.enable = 1;
225    state->thumbnailConfig.width = 64;
226    state->thumbnailConfig.height = 48;
227    state->thumbnailConfig.quality = 35;
228    state->demoMode = 0;
229    state->demoInterval = 250; // ms
230    state->camera_component = NULL;
231    state->encoder_component = NULL;
232    state->preview_connection = NULL;
233    state->encoder_connection = NULL;
234    state->encoder_pool = NULL;
235    state->encoding = MMAL_ENCODING_JPEG;
236    state->numExifTags = 0;
237    state->timelapse = 0;
238    state->fullResPreview = 0;
239
240    // Setup preview window defaults
241    raspipreview_set_defaults(&state->preview_parameters);
242
243    // Set up the camera_parameters to default
244    raspicamcontrol_set_defaults(&state->camera_parameters);
245 }
246
247 /**
248  * Dump image state parameters to stderr. Used for debugging
249  *
250  * @param state Pointer to state structure to assign defaults to
251  */
252 static void dump_status(RASPISTILL_STATE *state)
253 {
254    int i;
255
256    if (!state)
257    {
258       vcos_assert(0);
259       return;
260    }
261
262    fprintf(stderr, "Width %d, Height %d, quality %d, filename %s\n", state->width,
263          state->height, state->quality, state->filename);
264    fprintf(stderr, "Time delay %d, Raw %s\n", state->timeout,
265          state->wantRAW ? "yes" : "no");
266    fprintf(stderr, "Thumbnail enabled %s, width %d, height %d, quality %d\n",
267          state->thumbnailConfig.enable ? "Yes":"No", state->thumbnailConfig.width,
268          state->thumbnailConfig.height, state->thumbnailConfig.quality);
269    fprintf(stderr, "Link to latest frame enabled ");
270    if (state->linkname)
271    {
272       fprintf(stderr, " yes, -> %s\n", state->linkname);
273    }
274    else
275    {
276       fprintf(stderr, " no\n");
277    }
278    fprintf(stderr, "Full resolution preview %s\n\n", state->fullResPreview ? "Yes": "No");
279
280    if (state->numExifTags)
281    {
282       fprintf(stderr, "User supplied EXIF tags :\n");
283
284       for (i=0;i<state->numExifTags;i++)
285       {
286          fprintf(stderr, "%s", state->exifTags[i]);
287          if (i != state->numExifTags-1)
288             fprintf(stderr, ",");
289       }
290       fprintf(stderr, "\n\n");
291    }
292
293    raspipreview_dump_parameters(&state->preview_parameters);
294    //raspicamcontrol_dump_parameters(&state->camera_parameters);
295 }
296
297 /**
298  * Parse the incoming command line and put resulting parameters in to the state
299  *
300  * @param argc Number of arguments in command line
301  * @param argv Array of pointers to strings from command line
302  * @param state Pointer to state structure to assign any discovered parameters to
303  * @return non-0 if failed for some reason, 0 otherwise
304  */
305 static int parse_cmdline(int argc, const char **argv, RASPISTILL_STATE *state)
306 {
307    // Parse the command line arguments.
308    // We are looking for --<something> or -<abreviation of something>
309
310    int valid = 1;
311    int i;
312
313    for (i = 1; i < argc && valid; i++)
314    {
315       int command_id, num_parameters;
316
317       if (!argv[i])
318          continue;
319
320       if (argv[i][0] != '-')
321       {
322          valid = 0;
323          continue;
324       }
325
326       // Assume parameter is valid until proven otherwise
327       valid = 1;
328
329       command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, &argv[i][1], &num_parameters);
330
331       // If we found a command but are missing a parameter, continue (and we will drop out of the loop)
332       if (command_id != -1 && num_parameters > 0 && (i + 1 >= argc) )
333          continue;
334
335       //  We are now dealing with a command line option
336       switch (command_id)
337       {
338       case CommandHelp:
339          display_valid_parameters(basename(argv[0]));
340          // exit straight away if help requested
341          return -1;
342
343       case CommandWidth: // Width > 0
344          if (sscanf(argv[i + 1], "%u", &state->width) != 1)
345             valid = 0;
346          else
347             i++;
348          break;
349
350       case CommandHeight: // Height > 0
351          if (sscanf(argv[i + 1], "%u", &state->height) != 1)
352             valid = 0;
353          else
354             i++;
355          break;
356
357       case CommandQuality: // Quality = 1-100
358          if (sscanf(argv[i + 1], "%u", &state->quality) == 1)
359          {
360             if (state->quality > 100)
361             {
362                fprintf(stderr, "Setting max quality = 100\n");
363                state->quality = 100;
364             }
365             i++;
366          }
367          else
368             valid = 0;
369
370          break;
371
372       case CommandRaw: // Add raw bayer data in metadata
373          state->wantRAW = 1;
374          break;
375
376       case CommandOutput:  // output filename
377       {
378          int len = strlen(argv[i + 1]);
379          if (len)
380          {
381             state->filename = malloc(len + 10); // leave enough space for any timelapse generated changes to filename
382             vcos_assert(state->filename);
383             if (state->filename)
384                strncpy(state->filename, argv[i + 1], len);
385             i++;
386          }
387          else
388             valid = 0;
389          break;
390       }
391
392       case CommandLink :
393       {
394          int len = strlen(argv[i+1]);
395          if (len)
396          {
397             state->linkname = malloc(len + 10);
398             vcos_assert(state->linkname);
399             if (state->linkname)
400                strncpy(state->linkname, argv[i + 1], len);
401             i++;
402          }
403          else
404             valid = 0;
405          break;
406
407       }
408       case CommandVerbose: // display lots of data during run
409          state->verbose = 1;
410          break;
411
412       case CommandTimeout: // Time to run viewfinder for before taking picture, in seconds
413       {
414          if (sscanf(argv[i + 1], "%u", &state->timeout) == 1)
415          {
416             // TODO : What limits do we need for timeout?
417             i++;
418          }
419          else
420             valid = 0;
421          break;
422       }
423       case CommandThumbnail : // thumbnail parameters - needs string "x:y:quality"
424          sscanf(argv[i + 1], "%d:%d:%d", &state->thumbnailConfig.width,&state->thumbnailConfig.height,
425                   &state->thumbnailConfig.quality);
426          i++;
427          break;
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                state->demoMode = 1;
439                i++;
440             }
441             else
442                valid = 0;
443          }
444          else
445          {
446             state->demoMode = 1;
447          }
448
449          break;
450       }
451
452       case CommandEncoding :
453       {
454          int len = strlen(argv[i + 1]);
455          valid = 0;
456
457          if (len)
458          {
459             int j;
460             for (j=0;j<encoding_xref_size;j++)
461             {
462                if (strcmp(encoding_xref[j].format, argv[i+1]) == 0)
463                {
464                   state->encoding = encoding_xref[j].encoding;
465                   valid = 1;
466                   i++;
467                   break;
468                }
469             }
470          }
471          break;
472       }
473
474       case CommandExifTag:
475          store_exif_tag(state, argv[i+1]);
476          i++;
477          break;
478
479       case CommandTimelapse:
480          if (sscanf(argv[i + 1], "%u", &state->timelapse) != 1)
481             valid = 0;
482          else
483             i++;
484          break;
485
486       case CommandFullResPreview:
487          state->fullResPreview = 1;
488          break;
489
490       default:
491       {
492          // Try parsing for any image specific parameters
493          // result indicates how many parameters were used up, 0,1,2
494          // but we adjust by -1 as we have used one already
495          const char *second_arg = (i + 1 < argc) ? argv[i + 1] : NULL;
496          int parms_used = raspicamcontrol_parse_cmdline(&state->camera_parameters, &argv[i][1], second_arg);
497
498          // Still unused, try preview options
499          if (!parms_used)
500             parms_used = raspipreview_parse_cmdline(&state->preview_parameters, &argv[i][1], second_arg);
501
502          // If no parms were used, this must be a bad parameters
503          if (!parms_used)
504             valid = 0;
505          else
506             i += parms_used - 1;
507
508          break;
509       }
510       }
511    }
512
513    if (!valid)
514    {
515       fprintf(stderr, "Invalid command line option (%s)\n", argv[i]);
516       return 1;
517    }
518
519    return 0;
520 }
521
522 /**
523  * Display usage information for the application to stdout
524  *
525  * @param app_name String to display as the application name
526  */
527 static void display_valid_parameters(char *app_name)
528 {
529    fprintf(stderr, "Runs camera for specific time, and take JPG capture at end if requested\n\n");
530    fprintf(stderr, "usage: %s [options]\n\n", app_name);
531
532    fprintf(stderr, "Image parameter commands\n\n");
533
534    raspicli_display_help(cmdline_commands, cmdline_commands_size);
535
536    // Help for preview options
537    raspipreview_display_help();
538
539    // Now display any help information from the camcontrol code
540    raspicamcontrol_display_help();
541
542    fprintf(stderr, "\n");
543
544    return;
545 }
546
547 /**
548  *  buffer header callback function for camera control
549  *
550  *  No actions taken in current version
551  *
552  * @param port Pointer to port from which callback originated
553  * @param buffer mmal buffer header pointer
554  */
555 static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
556 {
557    if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED)
558    {
559    }
560    else
561    {
562       vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd);
563    }
564
565    mmal_buffer_header_release(buffer);
566 }
567
568 /**
569  *  buffer header callback function for encoder
570  *
571  *  Callback will dump buffer data to the specific file
572  *
573  * @param port Pointer to port from which callback originated
574  * @param buffer mmal buffer header pointer
575  */
576 static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
577 {
578    int complete = 0;
579
580    // We pass our file handle and other stuff in via the userdata field.
581
582    PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata;
583
584    if (pData)
585    {
586       int bytes_written = buffer->length;
587
588       if (buffer->length && pData->file_handle)
589       {
590          mmal_buffer_header_mem_lock(buffer);
591
592          bytes_written = fwrite(buffer->data, 1, buffer->length, pData->file_handle);
593
594          mmal_buffer_header_mem_unlock(buffer);
595       }
596
597       // We need to check we wrote what we wanted - it's possible we have run out of storage.
598       if (bytes_written != buffer->length)
599       {
600          vcos_log_error("Unable to write buffer to file - aborting");
601          complete = 1;
602       }
603
604       // Now flag if we have completed
605       if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED))
606          complete = 1;
607    }
608    else
609    {
610       vcos_log_error("Received a encoder buffer callback with no state");
611    }
612
613    // release buffer back to the pool
614    mmal_buffer_header_release(buffer);
615
616    // and send one back to the port (if still open)
617    if (port->is_enabled)
618    {
619       MMAL_STATUS_T status = MMAL_SUCCESS;
620       MMAL_BUFFER_HEADER_T *new_buffer;
621
622       new_buffer = mmal_queue_get(pData->pstate->encoder_pool->queue);
623
624       if (new_buffer)
625       {
626          status = mmal_port_send_buffer(port, new_buffer);
627       }
628       if (!new_buffer || status != MMAL_SUCCESS)
629          vcos_log_error("Unable to return a buffer to the encoder port");
630    }
631
632    if (complete)
633       vcos_semaphore_post(&(pData->complete_semaphore));
634
635 }
636
637
638 /**
639  * Create the camera component, set up its ports
640  *
641  * @param state Pointer to state control struct. camera_component member set to the created camera_component if successfull.
642  *
643  * @return MMAL_SUCCESS if all OK, something else otherwise
644  *
645  */
646 static MMAL_STATUS_T create_camera_component(RASPISTILL_STATE *state)
647 {
648    MMAL_COMPONENT_T *camera = 0;
649    MMAL_ES_FORMAT_T *format;
650    MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL;
651    MMAL_STATUS_T status;
652
653    /* Create the component */
654    status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
655
656    if (status != MMAL_SUCCESS)
657    {
658       vcos_log_error("Failed to create camera component");
659       goto error;
660    }
661
662    if (!camera->output_num)
663    {
664       status = MMAL_ENOSYS;
665       vcos_log_error("Camera doesn't have output ports");
666       goto error;
667    }
668
669    preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT];
670    video_port = camera->output[MMAL_CAMERA_VIDEO_PORT];
671    still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT];
672
673    // Enable the camera, and tell it its control callback function
674    status = mmal_port_enable(camera->control, camera_control_callback);
675
676    if (status != MMAL_SUCCESS)
677    {
678       vcos_log_error("Unable to enable control port : error %d", status);
679       goto error;
680    }
681
682    //  set up the camera configuration
683    {
684       MMAL_PARAMETER_CAMERA_CONFIG_T cam_config =
685       {
686          { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) },
687          .max_stills_w = state->width,
688          .max_stills_h = state->height,
689          .stills_yuv422 = 0,
690          .one_shot_stills = 1,
691          .max_preview_video_w = state->preview_parameters.previewWindow.width,
692          .max_preview_video_h = state->preview_parameters.previewWindow.height,
693          .num_preview_video_frames = 3,
694          .stills_capture_circular_buffer_height = 0,
695          .fast_preview_resume = 0,
696          .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC
697       };
698
699       if (state->fullResPreview)
700       {
701          cam_config.max_preview_video_w = state->width;
702          cam_config.max_preview_video_h = state->height;
703       }
704
705       mmal_port_parameter_set(camera->control, &cam_config.hdr);
706    }
707
708    raspicamcontrol_set_all_parameters(camera, &state->camera_parameters);
709
710    // Now set up the port formats
711
712    format = preview_port->format;
713
714    format->encoding = MMAL_ENCODING_OPAQUE;
715    format->encoding_variant = MMAL_ENCODING_I420;
716
717    if (state->fullResPreview)
718    {
719       // In this mode we are forcing the preview to be generated from the full capture resolution.
720       // This runs at a max of 15fps with the OV5647 sensor.
721       format->es->video.width = state->width;
722       format->es->video.height = state->height;
723       format->es->video.crop.x = 0;
724       format->es->video.crop.y = 0;
725       format->es->video.crop.width = state->width;
726       format->es->video.crop.height = state->height;
727       format->es->video.frame_rate.num = FULL_RES_PREVIEW_FRAME_RATE_NUM;
728       format->es->video.frame_rate.den = FULL_RES_PREVIEW_FRAME_RATE_DEN;
729    }
730    else
731    {
732       // use our normal preview mode - probably 1080p30
733       format->es->video.width = state->preview_parameters.previewWindow.width;
734       format->es->video.height = state->preview_parameters.previewWindow.height;
735       format->es->video.crop.x = 0;
736       format->es->video.crop.y = 0;
737       format->es->video.crop.width = state->preview_parameters.previewWindow.width;
738       format->es->video.crop.height = state->preview_parameters.previewWindow.height;
739       format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM;
740       format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN;
741    }
742
743    status = mmal_port_format_commit(preview_port);
744
745    if (status != MMAL_SUCCESS)
746    {
747       vcos_log_error("camera viewfinder format couldn't be set");
748       goto error;
749    }
750
751    // Set the same format on the video  port (which we dont use here)
752    mmal_format_full_copy(video_port->format, format);
753    status = mmal_port_format_commit(video_port);
754
755    if (status  != MMAL_SUCCESS)
756    {
757       vcos_log_error("camera video format couldn't be set");
758       goto error;
759    }
760
761    // Ensure there are enough buffers to avoid dropping frames
762    if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
763       video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
764
765    format = still_port->format;
766
767    // Set our stills format on the stills (for encoder) port
768    format->encoding = MMAL_ENCODING_OPAQUE;
769    format->es->video.width = state->width;
770    format->es->video.height = state->height;
771    format->es->video.crop.x = 0;
772    format->es->video.crop.y = 0;
773    format->es->video.crop.width = state->width;
774    format->es->video.crop.height = state->height;
775    format->es->video.frame_rate.num = STILLS_FRAME_RATE_NUM;
776    format->es->video.frame_rate.den = STILLS_FRAME_RATE_DEN;
777
778
779    status = mmal_port_format_commit(still_port);
780
781    if (status != MMAL_SUCCESS)
782    {
783       vcos_log_error("camera still format couldn't be set");
784       goto error;
785    }
786
787    /* Ensure there are enough buffers to avoid dropping frames */
788    if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
789       still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
790
791    /* Enable component */
792    status = mmal_component_enable(camera);
793
794    if (status != MMAL_SUCCESS)
795    {
796       vcos_log_error("camera component couldn't be enabled");
797       goto error;
798    }
799
800    state->camera_component = camera;
801
802    if (state->verbose)
803       fprintf(stderr, "Camera component done\n");
804
805    return status;
806
807 error:
808
809    if (camera)
810       mmal_component_destroy(camera);
811
812    return status;
813 }
814
815 /**
816  * Destroy the camera component
817  *
818  * @param state Pointer to state control struct
819  *
820  */
821 static void destroy_camera_component(RASPISTILL_STATE *state)
822 {
823    if (state->camera_component)
824    {
825       mmal_component_destroy(state->camera_component);
826       state->camera_component = NULL;
827    }
828 }
829
830
831
832 /**
833  * Create the encoder component, set up its ports
834  *
835  * @param state Pointer to state control struct. encoder_component member set to the created camera_component if successfull.
836  *
837  * @return a MMAL_STATUS, MMAL_SUCCESS if all OK, something else otherwise
838  */
839 static MMAL_STATUS_T create_encoder_component(RASPISTILL_STATE *state)
840 {
841    MMAL_COMPONENT_T *encoder = 0;
842    MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL;
843    MMAL_STATUS_T status;
844    MMAL_POOL_T *pool;
845
846    status = mmal_component_create(MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER, &encoder);
847
848    if (status != MMAL_SUCCESS)
849    {
850       vcos_log_error("Unable to create JPEG encoder component");
851       goto error;
852    }
853
854    if (!encoder->input_num || !encoder->output_num)
855    {
856       status = MMAL_ENOSYS;
857       vcos_log_error("JPEG encoder doesn't have input/output ports");
858       goto error;
859    }
860
861    encoder_input = encoder->input[0];
862    encoder_output = encoder->output[0];
863
864    // We want same format on input and output
865    mmal_format_copy(encoder_output->format, encoder_input->format);
866
867    // Specify out output format
868    encoder_output->format->encoding = state->encoding;
869
870    encoder_output->buffer_size = encoder_output->buffer_size_recommended;
871
872    if (encoder_output->buffer_size < encoder_output->buffer_size_min)
873       encoder_output->buffer_size = encoder_output->buffer_size_min;
874
875    encoder_output->buffer_num = encoder_output->buffer_num_recommended;
876
877    if (encoder_output->buffer_num < encoder_output->buffer_num_min)
878       encoder_output->buffer_num = encoder_output->buffer_num_min;
879
880    // Commit the port changes to the output port
881    status = mmal_port_format_commit(encoder_output);
882
883    if (status != MMAL_SUCCESS)
884    {
885       vcos_log_error("Unable to set format on video encoder output port");
886       goto error;
887    }
888
889    // Set the JPEG quality level
890    status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_Q_FACTOR, state->quality);
891
892    if (status != MMAL_SUCCESS)
893    {
894       vcos_log_error("Unable to set JPEG quality");
895       goto error;
896    }
897
898    // Set up any required thumbnail
899    {
900       MMAL_PARAMETER_THUMBNAIL_CONFIG_T param_thumb = {{MMAL_PARAMETER_THUMBNAIL_CONFIGURATION, sizeof(MMAL_PARAMETER_THUMBNAIL_CONFIG_T)}, 0, 0, 0, 0};
901
902       if ( state->thumbnailConfig.width > 0 && state->thumbnailConfig.height > 0 )
903       {
904          // Have a valid thumbnail defined
905          param_thumb.enable = 1;
906          param_thumb.width = state->thumbnailConfig.width;
907          param_thumb.height = state->thumbnailConfig.height;
908          param_thumb.quality = state->thumbnailConfig.quality;
909       }
910       status = mmal_port_parameter_set(encoder->control, &param_thumb.hdr);
911    }
912
913    //  Enable component
914    status = mmal_component_enable(encoder);
915
916    if (status  != MMAL_SUCCESS)
917    {
918       vcos_log_error("Unable to enable video encoder component");
919       goto error;
920    }
921
922    /* Create pool of buffer headers for the output port to consume */
923    pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size);
924
925    if (!pool)
926    {
927       vcos_log_error("Failed to create buffer header pool for encoder output port %s", encoder_output->name);
928    }
929
930    state->encoder_pool = pool;
931    state->encoder_component = encoder;
932
933    if (state->verbose)
934       fprintf(stderr, "Encoder component done\n");
935
936    return status;
937
938    error:
939
940    if (encoder)
941       mmal_component_destroy(encoder);
942
943    return status;
944 }
945
946 /**
947  * Destroy the encoder component
948  *
949  * @param state Pointer to state control struct
950  *
951  */
952 static void destroy_encoder_component(RASPISTILL_STATE *state)
953 {
954    // Get rid of any port buffers first
955    if (state->encoder_pool)
956    {
957       mmal_port_pool_destroy(state->encoder_component->output[0], state->encoder_pool);
958    }
959
960    if (state->encoder_component)
961    {
962       mmal_component_destroy(state->encoder_component);
963       state->encoder_component = NULL;
964    }
965 }
966
967
968 /**
969  * Add an exif tag to the capture
970  *
971  * @param state Pointer to state control struct
972  * @param exif_tag String containing a "key=value" pair.
973  * @return  Returns a MMAL_STATUS_T giving result of operation
974  */
975 static MMAL_STATUS_T add_exif_tag(RASPISTILL_STATE *state, const char *exif_tag)
976 {
977    MMAL_STATUS_T status;
978    MMAL_PARAMETER_EXIF_T *exif_param = (MMAL_PARAMETER_EXIF_T*)calloc(sizeof(MMAL_PARAMETER_EXIF_T) + MAX_EXIF_PAYLOAD_LENGTH, 1);
979
980    vcos_assert(state);
981    vcos_assert(state->encoder_component);
982
983    // Check to see if the tag is present or is indeed a key=value pair.
984    if (!exif_tag || strchr(exif_tag, '=') == NULL || strlen(exif_tag) > MAX_EXIF_PAYLOAD_LENGTH-1)
985       return MMAL_EINVAL;
986
987    exif_param->hdr.id = MMAL_PARAMETER_EXIF;
988
989    strncpy((char*)exif_param->data, exif_tag, MAX_EXIF_PAYLOAD_LENGTH-1);
990
991    exif_param->hdr.size = sizeof(MMAL_PARAMETER_EXIF_T) + strlen((char*)exif_param->data);
992
993    status = mmal_port_parameter_set(state->encoder_component->output[0], &exif_param->hdr);
994
995    free(exif_param);
996
997    return status;
998 }
999
1000 /**
1001  * Add a basic set of EXIF tags to the capture
1002  * Make, Time etc
1003  *
1004  * @param state Pointer to state control struct
1005  *
1006  */
1007 static void add_exif_tags(RASPISTILL_STATE *state)
1008 {
1009    time_t rawtime;
1010    struct tm *timeinfo;
1011    char time_buf[32];
1012    char exif_buf[128];
1013    int i;
1014
1015    add_exif_tag(state, "IFD0.Model=RP_OV5647");
1016    add_exif_tag(state, "IFD0.Make=RaspberryPi");
1017
1018    time(&rawtime);
1019    timeinfo = localtime(&rawtime);
1020
1021    snprintf(time_buf, sizeof(time_buf),
1022             "%04d:%02d:%02d %02d:%02d:%02d",
1023             timeinfo->tm_year+1900,
1024             timeinfo->tm_mon+1,
1025             timeinfo->tm_mday,
1026             timeinfo->tm_hour,
1027             timeinfo->tm_min,
1028             timeinfo->tm_sec);
1029
1030    snprintf(exif_buf, sizeof(exif_buf), "EXIF.DateTimeDigitized=%s", time_buf);
1031    add_exif_tag(state, exif_buf);
1032
1033    snprintf(exif_buf, sizeof(exif_buf), "EXIF.DateTimeOriginal=%s", time_buf);
1034    add_exif_tag(state, exif_buf);
1035
1036    snprintf(exif_buf, sizeof(exif_buf), "IFD0.DateTime=%s", time_buf);
1037    add_exif_tag(state, exif_buf);
1038
1039    // Now send any user supplied tags
1040
1041    for (i=0;i<state->numExifTags && i < MAX_USER_EXIF_TAGS;i++)
1042    {
1043       if (state->exifTags[i])
1044       {
1045          add_exif_tag(state, state->exifTags[i]);
1046       }
1047    }
1048 }
1049
1050 /**
1051  * Stores an EXIF tag in the state, incrementing various pointers as necessary.
1052  * Any tags stored in this way will be added to the image file when add_exif_tags
1053  * is called
1054  *
1055  * Will not store if run out of storage space
1056  *
1057  * @param state Pointer to state control struct
1058  * @param exif_tag EXIF tag string
1059  *
1060  */
1061 static void store_exif_tag(RASPISTILL_STATE *state, const char *exif_tag)
1062 {
1063    if (state->numExifTags < MAX_USER_EXIF_TAGS)
1064    {
1065       state->exifTags[state->numExifTags] = exif_tag;
1066       state->numExifTags++;
1067    }
1068 }
1069
1070 /**
1071  * Connect two specific ports together
1072  *
1073  * @param output_port Pointer the output port
1074  * @param input_port Pointer the input port
1075  * @param Pointer to a mmal connection pointer, reassigned if function successful
1076  * @return Returns a MMAL_STATUS_T giving result of operation
1077  *
1078  */
1079 static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection)
1080 {
1081    MMAL_STATUS_T status;
1082
1083    status =  mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT);
1084
1085    if (status == MMAL_SUCCESS)
1086    {
1087       status =  mmal_connection_enable(*connection);
1088       if (status != MMAL_SUCCESS)
1089          mmal_connection_destroy(*connection);
1090    }
1091
1092    return status;
1093 }
1094
1095
1096 /**
1097  * Allocates and generates a filename based on the
1098  * user-supplied pattern and the frame number.
1099  * On successful return, finalName and tempName point to malloc()ed strings
1100  * which must be freed externally.  (On failure, returns nulls that
1101  * don't need free()ing.)
1102  *
1103  * @param finalName pointer receives an
1104  * @param pattern sprintf pattern with %d to be replaced by frame
1105  * @param frame for timelapse, the frame number
1106  * @return Returns a MMAL_STATUS_T giving result of operation
1107 */
1108
1109 MMAL_STATUS_T create_filenames(char** finalName, char** tempName, char * pattern, int frame)
1110 {
1111    *finalName = NULL;
1112    *tempName = NULL;
1113    if (0 > asprintf(finalName, pattern, frame) ||
1114        0 > asprintf(tempName, "%s~", *finalName))
1115    {
1116       if (*finalName != NULL)
1117       {
1118          free(*finalName);
1119       }
1120       return MMAL_ENOMEM;    // It may be some other error, but it is not worth getting it right
1121    }
1122    return MMAL_SUCCESS;
1123 }
1124
1125 /**
1126  * Checks if specified port is valid and enabled, then disables it
1127  *
1128  * @param port  Pointer the port
1129  *
1130  */
1131 static void check_disable_port(MMAL_PORT_T *port)
1132 {
1133    if (port && port->is_enabled)
1134       mmal_port_disable(port);
1135 }
1136
1137 /**
1138  * Handler for sigint signals
1139  *
1140  * @param signal_number ID of incoming signal.
1141  *
1142  */
1143 static void signal_handler(int signal_number)
1144 {
1145    // Going to abort on all signals
1146    vcos_log_error("Aborting program\n");
1147
1148    // Need to close any open stuff...
1149
1150    exit(130);
1151 }
1152
1153 /**
1154  * main
1155  */
1156 int main(int argc, const char **argv)
1157 {
1158    // Our main data storage vessel..
1159    RASPISTILL_STATE state;
1160    int exit_code = EX_OK;
1161
1162    MMAL_STATUS_T status = MMAL_SUCCESS;
1163    MMAL_PORT_T *camera_preview_port = NULL;
1164    MMAL_PORT_T *camera_video_port = NULL;
1165    MMAL_PORT_T *camera_still_port = NULL;
1166    MMAL_PORT_T *preview_input_port = NULL;
1167    MMAL_PORT_T *encoder_input_port = NULL;
1168    MMAL_PORT_T *encoder_output_port = NULL;
1169
1170    bcm_host_init();
1171
1172    // Register our application with the logging system
1173    vcos_log_register("RaspiStill", VCOS_LOG_CATEGORY);
1174
1175    signal(SIGINT, signal_handler);
1176
1177    default_status(&state);
1178
1179    // Do we have any parameters
1180    if (argc == 1)
1181    {
1182       fprintf(stderr, "\%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING);
1183
1184       display_valid_parameters(basename(argv[0]));
1185       exit(EX_USAGE);
1186    }
1187
1188    // Parse the command line and put options in to our status structure
1189    if (parse_cmdline(argc, argv, &state))
1190    {
1191       exit(EX_USAGE);
1192    }
1193
1194    if (state.verbose)
1195    {
1196       fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING);
1197
1198       dump_status(&state);
1199    }
1200
1201    // OK, we have a nice set of parameters. Now set up our components
1202    // We have three components. Camera, Preview and encoder.
1203    // Camera and encoder are different in stills/video, but preview
1204    // is the same so handed off to a separate module
1205
1206    if ((status = create_camera_component(&state)) != MMAL_SUCCESS)
1207    {
1208       vcos_log_error("%s: Failed to create camera component", __func__);
1209       exit_code = EX_SOFTWARE;
1210    }
1211    else if ((status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS)
1212    {
1213       vcos_log_error("%s: Failed to create preview component", __func__);
1214       destroy_camera_component(&state);
1215       exit_code = EX_SOFTWARE;
1216    }
1217    else if ((status = create_encoder_component(&state)) != MMAL_SUCCESS)
1218    {
1219       vcos_log_error("%s: Failed to create encode component", __func__);
1220       raspipreview_destroy(&state.preview_parameters);
1221       destroy_camera_component(&state);
1222       exit_code = EX_SOFTWARE;
1223    }
1224    else
1225    {
1226       PORT_USERDATA callback_data;
1227
1228       if (state.verbose)
1229          fprintf(stderr, "Starting component connection stage\n");
1230
1231       camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
1232       camera_video_port   = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT];
1233       camera_still_port   = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
1234       encoder_input_port  = state.encoder_component->input[0];
1235       encoder_output_port = state.encoder_component->output[0];
1236
1237       // Note we are lucky that the preview and null sink components use the same input port
1238       // so we can simple do this without conditionals
1239       preview_input_port  = state.preview_parameters.preview_component->input[0];
1240
1241       // Connect camera to preview (which might be a null_sink if no preview required)
1242       status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection);
1243
1244       if (status == MMAL_SUCCESS)
1245       {
1246          VCOS_STATUS_T vcos_status;
1247
1248          if (state.verbose)
1249             fprintf(stderr, "Connecting camera stills port to encoder input port\n");
1250
1251          // Now connect the camera to the encoder
1252          status = connect_ports(camera_still_port, encoder_input_port, &state.encoder_connection);
1253
1254          if (status != MMAL_SUCCESS)
1255          {
1256             vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__);
1257             goto error;
1258          }
1259
1260          // Set up our userdata - this is passed though to the callback where we need the information.
1261          // Null until we open our filename
1262          callback_data.file_handle = NULL;
1263          callback_data.pstate = &state;
1264          vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0);
1265
1266          vcos_assert(vcos_status == VCOS_SUCCESS);
1267
1268          if (status != MMAL_SUCCESS)
1269          {
1270             vcos_log_error("Failed to setup encoder output");
1271             goto error;
1272          }
1273
1274          if (state.demoMode)
1275          {
1276             // Run for the user specific time..
1277             int num_iterations = state.timeout / state.demoInterval;
1278             int i;
1279             for (i=0;i<num_iterations;i++)
1280             {
1281                raspicamcontrol_cycle_test(state.camera_component);
1282                vcos_sleep(state.demoInterval);
1283             }
1284          }
1285          else
1286          {
1287             int num_iterations =  state.timelapse ? state.timeout / state.timelapse : 1;
1288             int frame;
1289             FILE *output_file = NULL;
1290             char *use_filename = NULL;      // Temporary filename while image being written
1291             char *final_filename = NULL;    // Name that gets file once complete
1292             int64_t next_frame_ms = vcos_getmicrosecs64()/1000;
1293
1294             // If in timelapse mode, and timeout set to zero (or less), then take frames forever
1295             for (frame = 1; (num_iterations <= 0) || (frame<=num_iterations); frame++)
1296             {
1297                if (state.timelapse)
1298                {
1299                   int64_t this_delay_ms = next_frame_ms - vcos_getmicrosecs64()/1000;
1300                   if (this_delay_ms < 0)
1301                   {   // We are already past the next exposure time
1302                      if (-this_delay_ms < -state.timelapse/2)
1303                      { // Less than a half frame late, take a frame and hope to catch up next time
1304                         next_frame_ms += state.timelapse;
1305                         vcos_log_error("Frame %d is %d ms late", frame, (int)(-this_delay_ms));
1306                       }
1307                       else
1308                       {
1309                          int nskip = 1 + (-this_delay_ms)/state.timelapse;
1310                          vcos_log_error("Skipping frame %d to restart at frame %d", frame, frame+nskip);
1311                          frame += nskip;
1312                          this_delay_ms += nskip * state.timelapse;
1313                          vcos_sleep(this_delay_ms);
1314                          next_frame_ms += (nskip + 1) * state.timelapse;
1315                       }
1316                   }
1317                   else
1318                   {
1319                      vcos_sleep(this_delay_ms);
1320                      next_frame_ms += state.timelapse;
1321                   }
1322                }
1323                else
1324                   vcos_sleep(state.timeout);
1325
1326                // Open the file
1327                if (state.filename)
1328                {
1329                   if (state.filename[0] == '-')
1330                   {
1331                      output_file = stdout;
1332
1333                      // Ensure we don't upset the output stream with diagnostics/info
1334                      state.verbose = 0;
1335                   }
1336                   else
1337                   {
1338                      vcos_assert(use_filename == NULL && final_filename == NULL);
1339                      status = create_filenames(&final_filename, &use_filename, state.filename, frame);
1340                      if (status  != MMAL_SUCCESS)
1341                      {
1342                         vcos_log_error("Unable to create filenames");
1343                         goto error;
1344                      }
1345
1346                      if (state.verbose)
1347                         fprintf(stderr, "Opening output file %s\n", final_filename);
1348                         // Technically it is opening the temp~ filename which will be ranamed to the final filename
1349
1350                      output_file = fopen(use_filename, "wb");
1351
1352                      if (!output_file)
1353                      {
1354                         // Notify user, carry on but discarding encoded output buffers
1355                         vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, use_filename);
1356                      }
1357
1358                      // asprintf used in timelapse mode allocates its own memory which we need to free
1359                   }
1360
1361                   callback_data.file_handle = output_file;
1362                }
1363
1364                // We only capture if a filename was specified and it opened
1365                if (output_file)
1366                {
1367                   int num, q;
1368
1369                   // Must do this before the encoder output port is enabled since
1370                   // once enabled no further exif data is accepted
1371                   add_exif_tags(&state);
1372
1373                   // Same with raw, apparently need to set it for each capture, whilst port
1374                   // is not enabled
1375                   if (state.wantRAW)
1376                   {
1377                      if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_ENABLE_RAW_CAPTURE, 1) != MMAL_SUCCESS)
1378                      {
1379                         vcos_log_error("RAW was requested, but failed to enable");
1380                      }
1381                   }
1382
1383                   // Enable the encoder output port
1384                   encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data;
1385
1386                   if (state.verbose)
1387                      fprintf(stderr, "Enabling encoder output port\n");
1388
1389                   // Enable the encoder output port and tell it its callback function
1390                   status = mmal_port_enable(encoder_output_port, encoder_buffer_callback);
1391
1392                   // Send all the buffers to the encoder output port
1393                   num = mmal_queue_length(state.encoder_pool->queue);
1394
1395                   for (q=0;q<num;q++)
1396                   {
1397                      MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.encoder_pool->queue);
1398
1399                      if (!buffer)
1400                         vcos_log_error("Unable to get a required buffer %d from pool queue", q);
1401
1402                      if (mmal_port_send_buffer(encoder_output_port, buffer)!= MMAL_SUCCESS)
1403                         vcos_log_error("Unable to send a buffer to encoder output port (%d)", q);
1404                   }
1405
1406                   if (state.verbose)
1407                      fprintf(stderr, "Starting capture %d\n", frame);
1408
1409                   if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
1410                   {
1411                      vcos_log_error("%s: Failed to start capture", __func__);
1412                   }
1413                   else
1414                   {
1415                      // Wait for capture to complete
1416                      // For some reason using vcos_semaphore_wait_timeout sometimes returns immediately with bad parameter error
1417                      // even though it appears to be all correct, so reverting to untimed one until figure out why its erratic
1418                      vcos_semaphore_wait(&callback_data.complete_semaphore);
1419                      if (state.verbose)
1420                         fprintf(stderr, "Finished capture %d\n", frame);
1421                   }
1422
1423                   // Ensure we don't die if get callback with no open file
1424                   callback_data.file_handle = NULL;
1425
1426                   if (output_file != stdout)
1427                   {
1428                      fclose(output_file);
1429                      vcos_assert(use_filename != NULL && final_filename != NULL);
1430                      if (0 != rename(use_filename, final_filename))
1431                      {
1432                         vcos_log_error("Could not rename temp file to: %s; %s",
1433                                           final_filename,strerror(errno));
1434                      }
1435                      if (state.linkname)
1436                      {
1437                         char *use_link;
1438                         char *final_link;
1439                         status = create_filenames(&final_link, &use_link, state.linkname, frame);
1440
1441                         // Create hard link if possible, symlink otherwise
1442                         if (status != MMAL_SUCCESS
1443                             || (0 != link(final_filename, use_link)
1444                                 &&  0 != symlink(final_filename, use_link))
1445                             || 0 != rename(use_link, final_link))
1446                         {
1447                            vcos_log_error("Could not link as filename: %s; %s",
1448                                           state.linkname,strerror(errno));
1449                         }
1450                         if (use_link) free(use_link);
1451                         if (final_link) free(final_link);
1452                      }
1453                    }
1454                   // Disable encoder output port
1455                   status = mmal_port_disable(encoder_output_port);
1456                }
1457
1458                if (use_filename)
1459                {
1460                   free(use_filename);
1461                   use_filename = NULL;
1462                }
1463                if (final_filename)
1464                {
1465                   free(final_filename);
1466                   final_filename = NULL;
1467                }
1468             } // end for (frame)
1469
1470             vcos_semaphore_delete(&callback_data.complete_semaphore);
1471          }
1472       }
1473       else
1474       {
1475          mmal_status_to_int(status);
1476          vcos_log_error("%s: Failed to connect camera to preview", __func__);
1477       }
1478
1479 error:
1480
1481       mmal_status_to_int(status);
1482
1483       if (state.verbose)
1484          fprintf(stderr, "Closing down\n");
1485
1486       // Disable all our ports that are not handled by connections
1487       check_disable_port(camera_video_port);
1488       check_disable_port(encoder_output_port);
1489
1490       mmal_connection_destroy(state.preview_connection);
1491
1492       mmal_connection_destroy(state.encoder_connection);
1493
1494       /* Disable components */
1495       if (state.encoder_component)
1496          mmal_component_disable(state.encoder_component);
1497
1498       if (state.preview_parameters.preview_component)
1499          mmal_component_disable(state.preview_parameters.preview_component);
1500
1501       if (state.camera_component)
1502          mmal_component_disable(state.camera_component);
1503
1504       destroy_encoder_component(&state);
1505       raspipreview_destroy(&state.preview_parameters);
1506       destroy_camera_component(&state);
1507
1508       if (state.verbose)
1509          fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
1510    }
1511
1512    if (status != MMAL_SUCCESS)
1513       raspicamcontrol_check_configuration(128);
1514
1515    return exit_code;
1516 }
1517 /* *INDENT-ON* */