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, ¶m_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