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