3 * Copyright (c) 2013 Jan Schmidt <jan@centricular.com>
5 Copyright (c) 2013, Broadcom Europe Ltd
6 Copyright (c) 2013, James Hughes
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
11 * Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 * Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 * Neither the name of the copyright holder nor the
17 names of its contributors may be used to endorse or promote products
18 derived from this software without specific prior written permission.
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
24 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Command line program to capture a still frame and encode it to file.
35 * Also optionally display a preview/viewfinder of current camera input.
38 * \Author: James Hughes
42 * 3 components are created; camera, preview and JPG encoder.
43 * Camera component has three ports, preview, video and stills.
44 * This program connects preview and stills to the preview and jpg
45 * encoder. Using mmal we don't need to worry about buffers between these
46 * components, but we do need to handle buffers from the encoder, which
47 * are simply written straight to the file in the requisite buffer callback.
49 * We use the RaspiCamControl code to handle the specific camera settings.
52 // We use some GNU extensions (asprintf, basename)
63 #define VERSION_STRING "v1.3.2"
66 #include "interface/vcos/vcos.h"
68 #include "interface/mmal/mmal.h"
69 #include "interface/mmal/mmal_logging.h"
70 #include "interface/mmal/mmal_buffer.h"
71 #include "interface/mmal/util/mmal_util.h"
72 #include "interface/mmal/util/mmal_util_params.h"
73 #include "interface/mmal/util/mmal_default_components.h"
74 #include "interface/mmal/util/mmal_connection.h"
77 #include "RaspiCamControl.h"
78 #include "RaspiPreview.h"
81 #include <semaphore.h>
83 /// Camera number to use - we only have one camera, indexed from 0.
84 #define CAMERA_NUMBER 0
86 // Standard port setting for the camera component
87 #define MMAL_CAMERA_PREVIEW_PORT 0
88 #define MMAL_CAMERA_VIDEO_PORT 1
89 #define MMAL_CAMERA_CAPTURE_PORT 2
92 // Stills format information
93 #define STILLS_FRAME_RATE_NUM 15
94 #define STILLS_FRAME_RATE_DEN 1
96 /// Video render needs at least 2 buffers.
97 #define VIDEO_OUTPUT_BUFFERS_NUM 3
99 #define MAX_USER_EXIF_TAGS 32
100 #define MAX_EXIF_PAYLOAD_LENGTH 128
102 int mmal_status_to_int(MMAL_STATUS_T status);
104 /** Structure containing all state information for the current run
108 int timeout; /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds
109 int width; /// Requested width of image
110 int height; /// requested height of image
111 int quality; /// JPEG quality setting (1-100)
112 int wantRAW; /// Flag for whether the JPEG metadata also contains the RAW bayer image
113 char *filename; /// filename of output file
114 char *linkname; /// filename of output file
115 MMAL_PARAM_THUMBNAIL_CONFIG_T thumbnailConfig;
116 int verbose; /// !0 if want detailed run information
117 int demoMode; /// Run app in demo mode
118 int demoInterval; /// Interval between camera settings changes
119 MMAL_FOURCC_T encoding; /// Encoding to use for the output file.
120 const char *exifTags[MAX_USER_EXIF_TAGS]; /// Array of pointers to tags supplied from the command line
121 int numExifTags; /// Number of supplied tags
122 int timelapse; /// Delay between each picture in timelapse mode. If 0, disable timelapse
123 int fullResPreview; /// If set, the camera preview port runs at capture resolution. Reduces fps.
125 RASPIPREVIEW_PARAMETERS preview_parameters; /// Preview setup parameters
126 RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters
128 MMAL_COMPONENT_T *camera_component; /// Pointer to the camera component
129 MMAL_COMPONENT_T *encoder_component; /// Pointer to the encoder component
130 MMAL_COMPONENT_T *null_sink_component; /// Pointer to the null sink component
131 MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera to preview
132 MMAL_CONNECTION_T *encoder_connection; /// Pointer to the connection from camera to encoder
134 MMAL_POOL_T *encoder_pool; /// Pointer to the pool of buffers used by encoder output port
138 /** Struct used to pass information in encoder port userdata to callback
142 FILE *file_handle; /// File handle to write buffer data to.
143 VCOS_SEMAPHORE_T complete_semaphore; /// semaphore which is posted when we reach end of frame (indicates end of capture or fault)
144 RASPISTILL_STATE *pstate; /// pointer to our state in case required in callback
147 static void display_valid_parameters(char *app_name);
148 static void store_exif_tag(RASPISTILL_STATE *state, const char *exif_tag);
150 /// Comamnd ID's and Structure defining our command line options
151 #define CommandHelp 0
152 #define CommandWidth 1
153 #define CommandHeight 2
154 #define CommandQuality 3
156 #define CommandOutput 5
157 #define CommandVerbose 6
158 #define CommandTimeout 7
159 #define CommandThumbnail 8
160 #define CommandDemoMode 9
161 #define CommandEncoding 10
162 #define CommandExifTag 11
163 #define CommandTimelapse 12
164 #define CommandFullResPreview 13
165 #define CommandLink 14
167 static COMMAND_LIST cmdline_commands[] =
169 { CommandHelp, "-help", "?", "This help information", 0 },
170 { CommandWidth, "-width", "w", "Set image width <size>", 1 },
171 { CommandHeight, "-height", "h", "Set image height <size>", 1 },
172 { CommandQuality, "-quality", "q", "Set jpeg quality <0 to 100>", 1 },
173 { CommandRaw, "-raw", "r", "Add raw bayer data to jpeg metadata", 0 },
174 { CommandOutput, "-output", "o", "Output filename <filename> (to write to stdout, use '-o -'). If not specified, no file is saved", 1 },
175 { CommandLink, "-latest", "l", "Link latest complete image to filename <filename>", 1},
176 { CommandVerbose, "-verbose", "v", "Output verbose information during run", 0 },
177 { CommandTimeout, "-timeout", "t", "Time (in ms) before takes picture and shuts down (if not specified, set to 5s)", 1 },
178 { CommandThumbnail,"-thumb", "th", "Set thumbnail parameters (x:y:quality)", 1},
179 { CommandDemoMode,"-demo", "d", "Run a demo mode (cycle through range of camera options, no capture)", 0},
180 { CommandEncoding,"-encoding", "e", "Encoding to use for output file (jpg, bmp, gif, png)", 1},
181 { CommandExifTag, "-exif", "x", "EXIF tag to apply to captures (format as 'key=value')", 1},
182 { CommandTimelapse,"-timelapse", "tl", "Timelapse mode. Takes a picture every <t>ms", 1},
183 { CommandFullResPreview,"-fullpreview", "fp", "Run the preview using the still capture resolution (may reduce preview fps)", 0},
186 static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
191 MMAL_FOURCC_T encoding;
194 {"jpg", MMAL_ENCODING_JPEG},
195 {"bmp", MMAL_ENCODING_BMP},
196 {"gif", MMAL_ENCODING_GIF},
197 {"png", MMAL_ENCODING_PNG}
200 static int encoding_xref_size = sizeof(encoding_xref) / sizeof(encoding_xref[0]);
204 * Assign a default set of parameters to the state passed in
206 * @param state Pointer to state structure to assign defaults to
208 static void default_status(RASPISTILL_STATE *state)
216 state->timeout = 5000; // 5s delay before take image
218 state->height = 1944;
221 state->filename = NULL;
222 state->linkname = NULL;
224 state->thumbnailConfig.enable = 1;
225 state->thumbnailConfig.width = 64;
226 state->thumbnailConfig.height = 48;
227 state->thumbnailConfig.quality = 35;
229 state->demoInterval = 250; // ms
230 state->camera_component = NULL;
231 state->encoder_component = NULL;
232 state->preview_connection = NULL;
233 state->encoder_connection = NULL;
234 state->encoder_pool = NULL;
235 state->encoding = MMAL_ENCODING_JPEG;
236 state->numExifTags = 0;
237 state->timelapse = 0;
238 state->fullResPreview = 0;
240 // Setup preview window defaults
241 raspipreview_set_defaults(&state->preview_parameters);
243 // Set up the camera_parameters to default
244 raspicamcontrol_set_defaults(&state->camera_parameters);
248 * Dump image state parameters to stderr. Used for debugging
250 * @param state Pointer to state structure to assign defaults to
252 static void dump_status(RASPISTILL_STATE *state)
262 fprintf(stderr, "Width %d, Height %d, quality %d, filename %s\n", state->width,
263 state->height, state->quality, state->filename);
264 fprintf(stderr, "Time delay %d, Raw %s\n", state->timeout,
265 state->wantRAW ? "yes" : "no");
266 fprintf(stderr, "Thumbnail enabled %s, width %d, height %d, quality %d\n",
267 state->thumbnailConfig.enable ? "Yes":"No", state->thumbnailConfig.width,
268 state->thumbnailConfig.height, state->thumbnailConfig.quality);
269 fprintf(stderr, "Link to latest frame enabled ");
272 fprintf(stderr, " yes, -> %s\n", state->linkname);
276 fprintf(stderr, " no\n");
278 fprintf(stderr, "Full resolution preview %s\n\n", state->fullResPreview ? "Yes": "No");
280 if (state->numExifTags)
282 fprintf(stderr, "User supplied EXIF tags :\n");
284 for (i=0;i<state->numExifTags;i++)
286 fprintf(stderr, "%s", state->exifTags[i]);
287 if (i != state->numExifTags-1)
288 fprintf(stderr, ",");
290 fprintf(stderr, "\n\n");
293 raspipreview_dump_parameters(&state->preview_parameters);
294 //raspicamcontrol_dump_parameters(&state->camera_parameters);
298 * Parse the incoming command line and put resulting parameters in to the state
300 * @param argc Number of arguments in command line
301 * @param argv Array of pointers to strings from command line
302 * @param state Pointer to state structure to assign any discovered parameters to
303 * @return non-0 if failed for some reason, 0 otherwise
305 static int parse_cmdline(int argc, const char **argv, RASPISTILL_STATE *state)
307 // Parse the command line arguments.
308 // We are looking for --<something> or -<abreviation of something>
313 for (i = 1; i < argc && valid; i++)
315 int command_id, num_parameters;
320 if (argv[i][0] != '-')
326 // Assume parameter is valid until proven otherwise
329 command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, &argv[i][1], &num_parameters);
331 // If we found a command but are missing a parameter, continue (and we will drop out of the loop)
332 if (command_id != -1 && num_parameters > 0 && (i + 1 >= argc) )
335 // We are now dealing with a command line option
339 display_valid_parameters(basename(argv[0]));
340 // exit straight away if help requested
343 case CommandWidth: // Width > 0
344 if (sscanf(argv[i + 1], "%u", &state->width) != 1)
350 case CommandHeight: // Height > 0
351 if (sscanf(argv[i + 1], "%u", &state->height) != 1)
357 case CommandQuality: // Quality = 1-100
358 if (sscanf(argv[i + 1], "%u", &state->quality) == 1)
360 if (state->quality > 100)
362 fprintf(stderr, "Setting max quality = 100\n");
363 state->quality = 100;
372 case CommandRaw: // Add raw bayer data in metadata
376 case CommandOutput: // output filename
378 int len = strlen(argv[i + 1]);
381 state->filename = malloc(len + 10); // leave enough space for any timelapse generated changes to filename
382 vcos_assert(state->filename);
384 strncpy(state->filename, argv[i + 1], len);
394 int len = strlen(argv[i+1]);
397 state->linkname = malloc(len + 10);
398 vcos_assert(state->linkname);
400 strncpy(state->linkname, argv[i + 1], len);
408 case CommandVerbose: // display lots of data during run
412 case CommandTimeout: // Time to run viewfinder for before taking picture, in seconds
414 if (sscanf(argv[i + 1], "%u", &state->timeout) == 1)
416 // TODO : What limits do we need for timeout?
423 case CommandThumbnail : // thumbnail parameters - needs string "x:y:quality"
424 sscanf(argv[i + 1], "%d:%d:%d", &state->thumbnailConfig.width,&state->thumbnailConfig.height,
425 &state->thumbnailConfig.quality);
429 case CommandDemoMode: // Run in demo mode - no capture
431 // Demo mode might have a timing parameter
432 // so check if a) we have another parameter, b) its not the start of the next option
433 if (i + 1 < argc && argv[i+1][0] != '-')
435 if (sscanf(argv[i + 1], "%u", &state->demoInterval) == 1)
437 // TODO : What limits do we need for timeout?
452 case CommandEncoding :
454 int len = strlen(argv[i + 1]);
460 for (j=0;j<encoding_xref_size;j++)
462 if (strcmp(encoding_xref[j].format, argv[i+1]) == 0)
464 state->encoding = encoding_xref[j].encoding;
475 store_exif_tag(state, argv[i+1]);
479 case CommandTimelapse:
480 if (sscanf(argv[i + 1], "%u", &state->timelapse) != 1)
486 case CommandFullResPreview:
487 state->fullResPreview = 1;
492 // Try parsing for any image specific parameters
493 // result indicates how many parameters were used up, 0,1,2
494 // but we adjust by -1 as we have used one already
495 const char *second_arg = (i + 1 < argc) ? argv[i + 1] : NULL;
496 int parms_used = raspicamcontrol_parse_cmdline(&state->camera_parameters, &argv[i][1], second_arg);
498 // Still unused, try preview options
500 parms_used = raspipreview_parse_cmdline(&state->preview_parameters, &argv[i][1], second_arg);
502 // If no parms were used, this must be a bad parameters
515 fprintf(stderr, "Invalid command line option (%s)\n", argv[i]);
523 * Display usage information for the application to stdout
525 * @param app_name String to display as the application name
527 static void display_valid_parameters(char *app_name)
529 fprintf(stderr, "Runs camera for specific time, and take JPG capture at end if requested\n\n");
530 fprintf(stderr, "usage: %s [options]\n\n", app_name);
532 fprintf(stderr, "Image parameter commands\n\n");
534 raspicli_display_help(cmdline_commands, cmdline_commands_size);
536 // Help for preview options
537 raspipreview_display_help();
539 // Now display any help information from the camcontrol code
540 raspicamcontrol_display_help();
542 fprintf(stderr, "\n");
548 * buffer header callback function for camera control
550 * No actions taken in current version
552 * @param port Pointer to port from which callback originated
553 * @param buffer mmal buffer header pointer
555 static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
557 if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED)
562 vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd);
565 mmal_buffer_header_release(buffer);
569 * buffer header callback function for encoder
571 * Callback will dump buffer data to the specific file
573 * @param port Pointer to port from which callback originated
574 * @param buffer mmal buffer header pointer
576 static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
580 // We pass our file handle and other stuff in via the userdata field.
582 PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata;
586 int bytes_written = buffer->length;
588 if (buffer->length && pData->file_handle)
590 mmal_buffer_header_mem_lock(buffer);
592 bytes_written = fwrite(buffer->data, 1, buffer->length, pData->file_handle);
594 mmal_buffer_header_mem_unlock(buffer);
597 // We need to check we wrote what we wanted - it's possible we have run out of storage.
598 if (bytes_written != buffer->length)
600 vcos_log_error("Unable to write buffer to file - aborting");
604 // Now flag if we have completed
605 if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED))
610 vcos_log_error("Received a encoder buffer callback with no state");
613 // release buffer back to the pool
614 mmal_buffer_header_release(buffer);
616 // and send one back to the port (if still open)
617 if (port->is_enabled)
619 MMAL_STATUS_T status = MMAL_SUCCESS;
620 MMAL_BUFFER_HEADER_T *new_buffer;
622 new_buffer = mmal_queue_get(pData->pstate->encoder_pool->queue);
626 status = mmal_port_send_buffer(port, new_buffer);
628 if (!new_buffer || status != MMAL_SUCCESS)
629 vcos_log_error("Unable to return a buffer to the encoder port");
633 vcos_semaphore_post(&(pData->complete_semaphore));
639 * Create the camera component, set up its ports
641 * @param state Pointer to state control struct. camera_component member set to the created camera_component if successfull.
643 * @return MMAL_SUCCESS if all OK, something else otherwise
646 static MMAL_STATUS_T create_camera_component(RASPISTILL_STATE *state)
648 MMAL_COMPONENT_T *camera = 0;
649 MMAL_ES_FORMAT_T *format;
650 MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL;
651 MMAL_STATUS_T status;
653 /* Create the component */
654 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
656 if (status != MMAL_SUCCESS)
658 vcos_log_error("Failed to create camera component");
662 if (!camera->output_num)
664 status = MMAL_ENOSYS;
665 vcos_log_error("Camera doesn't have output ports");
669 preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT];
670 video_port = camera->output[MMAL_CAMERA_VIDEO_PORT];
671 still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT];
673 // Enable the camera, and tell it its control callback function
674 status = mmal_port_enable(camera->control, camera_control_callback);
676 if (status != MMAL_SUCCESS)
678 vcos_log_error("Unable to enable control port : error %d", status);
682 // set up the camera configuration
684 MMAL_PARAMETER_CAMERA_CONFIG_T cam_config =
686 { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) },
687 .max_stills_w = state->width,
688 .max_stills_h = state->height,
690 .one_shot_stills = 1,
691 .max_preview_video_w = state->preview_parameters.previewWindow.width,
692 .max_preview_video_h = state->preview_parameters.previewWindow.height,
693 .num_preview_video_frames = 3,
694 .stills_capture_circular_buffer_height = 0,
695 .fast_preview_resume = 0,
696 .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC
699 if (state->fullResPreview)
701 cam_config.max_preview_video_w = state->width;
702 cam_config.max_preview_video_h = state->height;
705 mmal_port_parameter_set(camera->control, &cam_config.hdr);
708 raspicamcontrol_set_all_parameters(camera, &state->camera_parameters);
710 // Now set up the port formats
712 format = preview_port->format;
714 format->encoding = MMAL_ENCODING_OPAQUE;
715 format->encoding_variant = MMAL_ENCODING_I420;
717 if (state->fullResPreview)
719 // In this mode we are forcing the preview to be generated from the full capture resolution.
720 // This runs at a max of 15fps with the OV5647 sensor.
721 format->es->video.width = state->width;
722 format->es->video.height = state->height;
723 format->es->video.crop.x = 0;
724 format->es->video.crop.y = 0;
725 format->es->video.crop.width = state->width;
726 format->es->video.crop.height = state->height;
727 format->es->video.frame_rate.num = FULL_RES_PREVIEW_FRAME_RATE_NUM;
728 format->es->video.frame_rate.den = FULL_RES_PREVIEW_FRAME_RATE_DEN;
732 // use our normal preview mode - probably 1080p30
733 format->es->video.width = state->preview_parameters.previewWindow.width;
734 format->es->video.height = state->preview_parameters.previewWindow.height;
735 format->es->video.crop.x = 0;
736 format->es->video.crop.y = 0;
737 format->es->video.crop.width = state->preview_parameters.previewWindow.width;
738 format->es->video.crop.height = state->preview_parameters.previewWindow.height;
739 format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM;
740 format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN;
743 status = mmal_port_format_commit(preview_port);
745 if (status != MMAL_SUCCESS)
747 vcos_log_error("camera viewfinder format couldn't be set");
751 // Set the same format on the video port (which we dont use here)
752 mmal_format_full_copy(video_port->format, format);
753 status = mmal_port_format_commit(video_port);
755 if (status != MMAL_SUCCESS)
757 vcos_log_error("camera video format couldn't be set");
761 // Ensure there are enough buffers to avoid dropping frames
762 if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
763 video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
765 format = still_port->format;
767 // Set our stills format on the stills (for encoder) port
768 format->encoding = MMAL_ENCODING_OPAQUE;
769 format->es->video.width = state->width;
770 format->es->video.height = state->height;
771 format->es->video.crop.x = 0;
772 format->es->video.crop.y = 0;
773 format->es->video.crop.width = state->width;
774 format->es->video.crop.height = state->height;
775 format->es->video.frame_rate.num = STILLS_FRAME_RATE_NUM;
776 format->es->video.frame_rate.den = STILLS_FRAME_RATE_DEN;
779 status = mmal_port_format_commit(still_port);
781 if (status != MMAL_SUCCESS)
783 vcos_log_error("camera still format couldn't be set");
787 /* Ensure there are enough buffers to avoid dropping frames */
788 if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
789 still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
791 /* Enable component */
792 status = mmal_component_enable(camera);
794 if (status != MMAL_SUCCESS)
796 vcos_log_error("camera component couldn't be enabled");
800 state->camera_component = camera;
803 fprintf(stderr, "Camera component done\n");
810 mmal_component_destroy(camera);
816 * Destroy the camera component
818 * @param state Pointer to state control struct
821 static void destroy_camera_component(RASPISTILL_STATE *state)
823 if (state->camera_component)
825 mmal_component_destroy(state->camera_component);
826 state->camera_component = NULL;
833 * Create the encoder component, set up its ports
835 * @param state Pointer to state control struct. encoder_component member set to the created camera_component if successfull.
837 * @return a MMAL_STATUS, MMAL_SUCCESS if all OK, something else otherwise
839 static MMAL_STATUS_T create_encoder_component(RASPISTILL_STATE *state)
841 MMAL_COMPONENT_T *encoder = 0;
842 MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL;
843 MMAL_STATUS_T status;
846 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER, &encoder);
848 if (status != MMAL_SUCCESS)
850 vcos_log_error("Unable to create JPEG encoder component");
854 if (!encoder->input_num || !encoder->output_num)
856 status = MMAL_ENOSYS;
857 vcos_log_error("JPEG encoder doesn't have input/output ports");
861 encoder_input = encoder->input[0];
862 encoder_output = encoder->output[0];
864 // We want same format on input and output
865 mmal_format_copy(encoder_output->format, encoder_input->format);
867 // Specify out output format
868 encoder_output->format->encoding = state->encoding;
870 encoder_output->buffer_size = encoder_output->buffer_size_recommended;
872 if (encoder_output->buffer_size < encoder_output->buffer_size_min)
873 encoder_output->buffer_size = encoder_output->buffer_size_min;
875 encoder_output->buffer_num = encoder_output->buffer_num_recommended;
877 if (encoder_output->buffer_num < encoder_output->buffer_num_min)
878 encoder_output->buffer_num = encoder_output->buffer_num_min;
880 // Commit the port changes to the output port
881 status = mmal_port_format_commit(encoder_output);
883 if (status != MMAL_SUCCESS)
885 vcos_log_error("Unable to set format on video encoder output port");
889 // Set the JPEG quality level
890 status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_Q_FACTOR, state->quality);
892 if (status != MMAL_SUCCESS)
894 vcos_log_error("Unable to set JPEG quality");
898 // Set up any required thumbnail
900 MMAL_PARAMETER_THUMBNAIL_CONFIG_T param_thumb = {{MMAL_PARAMETER_THUMBNAIL_CONFIGURATION, sizeof(MMAL_PARAMETER_THUMBNAIL_CONFIG_T)}, 0, 0, 0, 0};
902 if ( state->thumbnailConfig.width > 0 && state->thumbnailConfig.height > 0 )
904 // Have a valid thumbnail defined
905 param_thumb.enable = 1;
906 param_thumb.width = state->thumbnailConfig.width;
907 param_thumb.height = state->thumbnailConfig.height;
908 param_thumb.quality = state->thumbnailConfig.quality;
910 status = mmal_port_parameter_set(encoder->control, ¶m_thumb.hdr);
914 status = mmal_component_enable(encoder);
916 if (status != MMAL_SUCCESS)
918 vcos_log_error("Unable to enable video encoder component");
922 /* Create pool of buffer headers for the output port to consume */
923 pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size);
927 vcos_log_error("Failed to create buffer header pool for encoder output port %s", encoder_output->name);
930 state->encoder_pool = pool;
931 state->encoder_component = encoder;
934 fprintf(stderr, "Encoder component done\n");
941 mmal_component_destroy(encoder);
947 * Destroy the encoder component
949 * @param state Pointer to state control struct
952 static void destroy_encoder_component(RASPISTILL_STATE *state)
954 // Get rid of any port buffers first
955 if (state->encoder_pool)
957 mmal_port_pool_destroy(state->encoder_component->output[0], state->encoder_pool);
960 if (state->encoder_component)
962 mmal_component_destroy(state->encoder_component);
963 state->encoder_component = NULL;
969 * Add an exif tag to the capture
971 * @param state Pointer to state control struct
972 * @param exif_tag String containing a "key=value" pair.
973 * @return Returns a MMAL_STATUS_T giving result of operation
975 static MMAL_STATUS_T add_exif_tag(RASPISTILL_STATE *state, const char *exif_tag)
977 MMAL_STATUS_T status;
978 MMAL_PARAMETER_EXIF_T *exif_param = (MMAL_PARAMETER_EXIF_T*)calloc(sizeof(MMAL_PARAMETER_EXIF_T) + MAX_EXIF_PAYLOAD_LENGTH, 1);
981 vcos_assert(state->encoder_component);
983 // Check to see if the tag is present or is indeed a key=value pair.
984 if (!exif_tag || strchr(exif_tag, '=') == NULL || strlen(exif_tag) > MAX_EXIF_PAYLOAD_LENGTH-1)
987 exif_param->hdr.id = MMAL_PARAMETER_EXIF;
989 strncpy((char*)exif_param->data, exif_tag, MAX_EXIF_PAYLOAD_LENGTH-1);
991 exif_param->hdr.size = sizeof(MMAL_PARAMETER_EXIF_T) + strlen((char*)exif_param->data);
993 status = mmal_port_parameter_set(state->encoder_component->output[0], &exif_param->hdr);
1001 * Add a basic set of EXIF tags to the capture
1004 * @param state Pointer to state control struct
1007 static void add_exif_tags(RASPISTILL_STATE *state)
1010 struct tm *timeinfo;
1015 add_exif_tag(state, "IFD0.Model=RP_OV5647");
1016 add_exif_tag(state, "IFD0.Make=RaspberryPi");
1019 timeinfo = localtime(&rawtime);
1021 snprintf(time_buf, sizeof(time_buf),
1022 "%04d:%02d:%02d %02d:%02d:%02d",
1023 timeinfo->tm_year+1900,
1030 snprintf(exif_buf, sizeof(exif_buf), "EXIF.DateTimeDigitized=%s", time_buf);
1031 add_exif_tag(state, exif_buf);
1033 snprintf(exif_buf, sizeof(exif_buf), "EXIF.DateTimeOriginal=%s", time_buf);
1034 add_exif_tag(state, exif_buf);
1036 snprintf(exif_buf, sizeof(exif_buf), "IFD0.DateTime=%s", time_buf);
1037 add_exif_tag(state, exif_buf);
1039 // Now send any user supplied tags
1041 for (i=0;i<state->numExifTags && i < MAX_USER_EXIF_TAGS;i++)
1043 if (state->exifTags[i])
1045 add_exif_tag(state, state->exifTags[i]);
1051 * Stores an EXIF tag in the state, incrementing various pointers as necessary.
1052 * Any tags stored in this way will be added to the image file when add_exif_tags
1055 * Will not store if run out of storage space
1057 * @param state Pointer to state control struct
1058 * @param exif_tag EXIF tag string
1061 static void store_exif_tag(RASPISTILL_STATE *state, const char *exif_tag)
1063 if (state->numExifTags < MAX_USER_EXIF_TAGS)
1065 state->exifTags[state->numExifTags] = exif_tag;
1066 state->numExifTags++;
1071 * Connect two specific ports together
1073 * @param output_port Pointer the output port
1074 * @param input_port Pointer the input port
1075 * @param Pointer to a mmal connection pointer, reassigned if function successful
1076 * @return Returns a MMAL_STATUS_T giving result of operation
1079 static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection)
1081 MMAL_STATUS_T status;
1083 status = mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT);
1085 if (status == MMAL_SUCCESS)
1087 status = mmal_connection_enable(*connection);
1088 if (status != MMAL_SUCCESS)
1089 mmal_connection_destroy(*connection);
1097 * Allocates and generates a filename based on the
1098 * user-supplied pattern and the frame number.
1099 * On successful return, finalName and tempName point to malloc()ed strings
1100 * which must be freed externally. (On failure, returns nulls that
1101 * don't need free()ing.)
1103 * @param finalName pointer receives an
1104 * @param pattern sprintf pattern with %d to be replaced by frame
1105 * @param frame for timelapse, the frame number
1106 * @return Returns a MMAL_STATUS_T giving result of operation
1109 MMAL_STATUS_T create_filenames(char** finalName, char** tempName, char * pattern, int frame)
1113 if (0 > asprintf(finalName, pattern, frame) ||
1114 0 > asprintf(tempName, "%s~", *finalName))
1116 if (*finalName != NULL)
1120 return MMAL_ENOMEM; // It may be some other error, but it is not worth getting it right
1122 return MMAL_SUCCESS;
1126 * Checks if specified port is valid and enabled, then disables it
1128 * @param port Pointer the port
1131 static void check_disable_port(MMAL_PORT_T *port)
1133 if (port && port->is_enabled)
1134 mmal_port_disable(port);
1138 * Handler for sigint signals
1140 * @param signal_number ID of incoming signal.
1143 static void signal_handler(int signal_number)
1145 // Going to abort on all signals
1146 vcos_log_error("Aborting program\n");
1148 // Need to close any open stuff...
1156 int main(int argc, const char **argv)
1158 // Our main data storage vessel..
1159 RASPISTILL_STATE state;
1160 int exit_code = EX_OK;
1162 MMAL_STATUS_T status = MMAL_SUCCESS;
1163 MMAL_PORT_T *camera_preview_port = NULL;
1164 MMAL_PORT_T *camera_video_port = NULL;
1165 MMAL_PORT_T *camera_still_port = NULL;
1166 MMAL_PORT_T *preview_input_port = NULL;
1167 MMAL_PORT_T *encoder_input_port = NULL;
1168 MMAL_PORT_T *encoder_output_port = NULL;
1172 // Register our application with the logging system
1173 vcos_log_register("RaspiStill", VCOS_LOG_CATEGORY);
1175 signal(SIGINT, signal_handler);
1177 default_status(&state);
1179 // Do we have any parameters
1182 fprintf(stderr, "\%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING);
1184 display_valid_parameters(basename(argv[0]));
1188 // Parse the command line and put options in to our status structure
1189 if (parse_cmdline(argc, argv, &state))
1196 fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING);
1198 dump_status(&state);
1201 // OK, we have a nice set of parameters. Now set up our components
1202 // We have three components. Camera, Preview and encoder.
1203 // Camera and encoder are different in stills/video, but preview
1204 // is the same so handed off to a separate module
1206 if ((status = create_camera_component(&state)) != MMAL_SUCCESS)
1208 vcos_log_error("%s: Failed to create camera component", __func__);
1209 exit_code = EX_SOFTWARE;
1211 else if ((status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS)
1213 vcos_log_error("%s: Failed to create preview component", __func__);
1214 destroy_camera_component(&state);
1215 exit_code = EX_SOFTWARE;
1217 else if ((status = create_encoder_component(&state)) != MMAL_SUCCESS)
1219 vcos_log_error("%s: Failed to create encode component", __func__);
1220 raspipreview_destroy(&state.preview_parameters);
1221 destroy_camera_component(&state);
1222 exit_code = EX_SOFTWARE;
1226 PORT_USERDATA callback_data;
1229 fprintf(stderr, "Starting component connection stage\n");
1231 camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
1232 camera_video_port = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT];
1233 camera_still_port = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
1234 encoder_input_port = state.encoder_component->input[0];
1235 encoder_output_port = state.encoder_component->output[0];
1237 // Note we are lucky that the preview and null sink components use the same input port
1238 // so we can simple do this without conditionals
1239 preview_input_port = state.preview_parameters.preview_component->input[0];
1241 // Connect camera to preview (which might be a null_sink if no preview required)
1242 status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection);
1244 if (status == MMAL_SUCCESS)
1246 VCOS_STATUS_T vcos_status;
1249 fprintf(stderr, "Connecting camera stills port to encoder input port\n");
1251 // Now connect the camera to the encoder
1252 status = connect_ports(camera_still_port, encoder_input_port, &state.encoder_connection);
1254 if (status != MMAL_SUCCESS)
1256 vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__);
1260 // Set up our userdata - this is passed though to the callback where we need the information.
1261 // Null until we open our filename
1262 callback_data.file_handle = NULL;
1263 callback_data.pstate = &state;
1264 vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0);
1266 vcos_assert(vcos_status == VCOS_SUCCESS);
1268 if (status != MMAL_SUCCESS)
1270 vcos_log_error("Failed to setup encoder output");
1276 // Run for the user specific time..
1277 int num_iterations = state.timeout / state.demoInterval;
1279 for (i=0;i<num_iterations;i++)
1281 raspicamcontrol_cycle_test(state.camera_component);
1282 vcos_sleep(state.demoInterval);
1287 int num_iterations = state.timelapse ? state.timeout / state.timelapse : 1;
1289 FILE *output_file = NULL;
1290 char *use_filename = NULL; // Temporary filename while image being written
1291 char *final_filename = NULL; // Name that gets file once complete
1292 int64_t next_frame_ms = vcos_getmicrosecs64()/1000;
1294 // If in timelapse mode, and timeout set to zero (or less), then take frames forever
1295 for (frame = 1; (num_iterations <= 0) || (frame<=num_iterations); frame++)
1297 if (state.timelapse)
1299 int64_t this_delay_ms = next_frame_ms - vcos_getmicrosecs64()/1000;
1300 if (this_delay_ms < 0)
1301 { // We are already past the next exposure time
1302 if (-this_delay_ms < -state.timelapse/2)
1303 { // Less than a half frame late, take a frame and hope to catch up next time
1304 next_frame_ms += state.timelapse;
1305 vcos_log_error("Frame %d is %d ms late", frame, (int)(-this_delay_ms));
1309 int nskip = 1 + (-this_delay_ms)/state.timelapse;
1310 vcos_log_error("Skipping frame %d to restart at frame %d", frame, frame+nskip);
1312 this_delay_ms += nskip * state.timelapse;
1313 vcos_sleep(this_delay_ms);
1314 next_frame_ms += (nskip + 1) * state.timelapse;
1319 vcos_sleep(this_delay_ms);
1320 next_frame_ms += state.timelapse;
1324 vcos_sleep(state.timeout);
1329 if (state.filename[0] == '-')
1331 output_file = stdout;
1333 // Ensure we don't upset the output stream with diagnostics/info
1338 vcos_assert(use_filename == NULL && final_filename == NULL);
1339 status = create_filenames(&final_filename, &use_filename, state.filename, frame);
1340 if (status != MMAL_SUCCESS)
1342 vcos_log_error("Unable to create filenames");
1347 fprintf(stderr, "Opening output file %s\n", final_filename);
1348 // Technically it is opening the temp~ filename which will be ranamed to the final filename
1350 output_file = fopen(use_filename, "wb");
1354 // Notify user, carry on but discarding encoded output buffers
1355 vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, use_filename);
1358 // asprintf used in timelapse mode allocates its own memory which we need to free
1361 callback_data.file_handle = output_file;
1364 // We only capture if a filename was specified and it opened
1369 // Must do this before the encoder output port is enabled since
1370 // once enabled no further exif data is accepted
1371 add_exif_tags(&state);
1373 // Same with raw, apparently need to set it for each capture, whilst port
1377 if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_ENABLE_RAW_CAPTURE, 1) != MMAL_SUCCESS)
1379 vcos_log_error("RAW was requested, but failed to enable");
1383 // Enable the encoder output port
1384 encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data;
1387 fprintf(stderr, "Enabling encoder output port\n");
1389 // Enable the encoder output port and tell it its callback function
1390 status = mmal_port_enable(encoder_output_port, encoder_buffer_callback);
1392 // Send all the buffers to the encoder output port
1393 num = mmal_queue_length(state.encoder_pool->queue);
1397 MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.encoder_pool->queue);
1400 vcos_log_error("Unable to get a required buffer %d from pool queue", q);
1402 if (mmal_port_send_buffer(encoder_output_port, buffer)!= MMAL_SUCCESS)
1403 vcos_log_error("Unable to send a buffer to encoder output port (%d)", q);
1407 fprintf(stderr, "Starting capture %d\n", frame);
1409 if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
1411 vcos_log_error("%s: Failed to start capture", __func__);
1415 // Wait for capture to complete
1416 // For some reason using vcos_semaphore_wait_timeout sometimes returns immediately with bad parameter error
1417 // even though it appears to be all correct, so reverting to untimed one until figure out why its erratic
1418 vcos_semaphore_wait(&callback_data.complete_semaphore);
1420 fprintf(stderr, "Finished capture %d\n", frame);
1423 // Ensure we don't die if get callback with no open file
1424 callback_data.file_handle = NULL;
1426 if (output_file != stdout)
1428 fclose(output_file);
1429 vcos_assert(use_filename != NULL && final_filename != NULL);
1430 if (0 != rename(use_filename, final_filename))
1432 vcos_log_error("Could not rename temp file to: %s; %s",
1433 final_filename,strerror(errno));
1439 status = create_filenames(&final_link, &use_link, state.linkname, frame);
1441 // Create hard link if possible, symlink otherwise
1442 if (status != MMAL_SUCCESS
1443 || (0 != link(final_filename, use_link)
1444 && 0 != symlink(final_filename, use_link))
1445 || 0 != rename(use_link, final_link))
1447 vcos_log_error("Could not link as filename: %s; %s",
1448 state.linkname,strerror(errno));
1450 if (use_link) free(use_link);
1451 if (final_link) free(final_link);
1454 // Disable encoder output port
1455 status = mmal_port_disable(encoder_output_port);
1461 use_filename = NULL;
1465 free(final_filename);
1466 final_filename = NULL;
1468 } // end for (frame)
1470 vcos_semaphore_delete(&callback_data.complete_semaphore);
1475 mmal_status_to_int(status);
1476 vcos_log_error("%s: Failed to connect camera to preview", __func__);
1481 mmal_status_to_int(status);
1484 fprintf(stderr, "Closing down\n");
1486 // Disable all our ports that are not handled by connections
1487 check_disable_port(camera_video_port);
1488 check_disable_port(encoder_output_port);
1490 mmal_connection_destroy(state.preview_connection);
1492 mmal_connection_destroy(state.encoder_connection);
1494 /* Disable components */
1495 if (state.encoder_component)
1496 mmal_component_disable(state.encoder_component);
1498 if (state.preview_parameters.preview_component)
1499 mmal_component_disable(state.preview_parameters.preview_component);
1501 if (state.camera_component)
1502 mmal_component_disable(state.camera_component);
1504 destroy_encoder_component(&state);
1505 raspipreview_destroy(&state.preview_parameters);
1506 destroy_camera_component(&state);
1509 fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
1512 if (status != MMAL_SUCCESS)
1513 raspicamcontrol_check_configuration(128);