2 * Copyright (c) 2013-2016 Jan Schmidt <jan@centricular.com>
4 Copyright (c) 2013, Broadcom Europe Ltd
5 Copyright (c) 2013, James Hughes
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 * Neither the name of the copyright holder nor the
16 names of its contributors may be used to endorse or promote products
17 derived from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * \file RaspiCapture.c
34 * Modification of the RaspiVid command line capture program for GStreamer
37 * \date 28th Feb 2013, 11 Oct 2013, 5 Mar 2015
38 * \Author: James Hughes, Jan Schmidt
42 * 3 components are created; camera, preview and video encoder.
43 * Camera component has three ports, preview, video and stills.
44 * This program connects preview and stills to the preview and video
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.
50 * We use the RaspiPreview code to handle the (generic) preview window
53 // We use some GNU extensions (basename, asprintf)
65 #include "interface/vcos/vcos.h"
67 #include "interface/mmal/mmal.h"
68 #include "interface/mmal/mmal_logging.h"
69 #include "interface/mmal/mmal_buffer.h"
70 #include "interface/mmal/util/mmal_util.h"
71 #include "interface/mmal/util/mmal_util_params.h"
72 #include "interface/mmal/util/mmal_default_components.h"
73 #include "interface/mmal/util/mmal_connection.h"
75 #include "RaspiCapture.h"
76 #include "RaspiCamControl.h"
77 #include "RaspiPreview.h"
80 #include <semaphore.h>
82 // Standard port setting for the camera component
83 #define MMAL_CAMERA_PREVIEW_PORT 0
84 #define MMAL_CAMERA_VIDEO_PORT 1
85 #define MMAL_CAMERA_CAPTURE_PORT 2
87 // Video format information
89 #define VIDEO_FRAME_RATE_NUM 30
90 #define VIDEO_FRAME_RATE_DEN 1
92 /// Video render needs at least 2 buffers.
93 #define VIDEO_OUTPUT_BUFFERS_NUM 3
95 // Max bitrate we allow for recording
96 const int MAX_BITRATE = 25000000; // 25Mbits/s
98 /// Interval at which we check for an failure abort during capture
99 const int ABORT_INTERVAL = 100; // ms
102 int mmal_status_to_int(MMAL_STATUS_T status);
104 /** Struct used to pass information in encoder port userdata to callback
108 RASPIVID_STATE *state; /// pointer to our state in case required in callback
109 int abort; /// Set to 1 in callback if an error occurs to attempt to abort the capture
112 struct RASPIVID_STATE_T
114 RASPIVID_CONFIG config;
118 MMAL_COMPONENT_T *camera_component; /// Pointer to the camera component
119 MMAL_COMPONENT_T *encoder_component; /// Pointer to the encoder component
120 MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera to preview
121 MMAL_CONNECTION_T *encoder_connection; /// Pointer to the connection from camera to encoder
123 MMAL_PORT_T *camera_video_port;
124 MMAL_PORT_T *camera_still_port;
125 MMAL_PORT_T *encoder_output_port;
127 MMAL_POOL_T *encoder_pool; /// Pointer to the pool of buffers used by encoder output port
129 PORT_USERDATA callback_data;
131 MMAL_QUEUE_T *encoded_buffer_q;
136 RASPIPREVIEW_STATE preview_state;
140 /// Structure to cross reference H264 profile strings against the MMAL parameter equivalent
141 static XREF_T profile_map[] =
143 {"baseline", MMAL_VIDEO_PROFILE_H264_BASELINE},
144 {"main", MMAL_VIDEO_PROFILE_H264_MAIN},
145 {"high", MMAL_VIDEO_PROFILE_H264_HIGH},
146 // {"constrained", MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE} // Does anyone need this?
149 static int profile_map_size = sizeof(profile_map) / sizeof(profile_map[0]);
152 static XREF_T initial_map[] =
158 static int initial_map_size = sizeof(initial_map) / sizeof(initial_map[0]);
161 static XREF_T intra_refresh_map[] =
163 {"cyclic", MMAL_VIDEO_INTRA_REFRESH_CYCLIC},
164 {"adaptive", MMAL_VIDEO_INTRA_REFRESH_ADAPTIVE},
165 {"both", MMAL_VIDEO_INTRA_REFRESH_BOTH},
166 {"cyclicrows", MMAL_VIDEO_INTRA_REFRESH_CYCLIC_MROWS},
167 // {"random", MMAL_VIDEO_INTRA_REFRESH_PSEUDO_RAND} Cannot use random, crashes the encoder. No idea why.
170 static int intra_refresh_map_size = sizeof(intra_refresh_map) / sizeof(intra_refresh_map[0]);
174 static void display_valid_parameters(char *app_name);
176 /// Command ID's and Structure defining our command line options
177 #define CommandHelp 0
178 #define CommandWidth 1
179 #define CommandHeight 2
180 #define CommandBitrate 3
181 #define CommandOutput 4
182 #define CommandVerbose 5
183 #define CommandTimeout 6
184 #define CommandDemoMode 7
185 #define CommandFramerate 8
186 #define CommandPreviewEnc 9
187 #define CommandIntraPeriod 10
188 #define CommandProfile 11
189 #define CommandTimed 12
190 #define CommandSignal 13
191 #define CommandKeypress 14
192 #define CommandInitialState 15
194 #define CommandInlineHeaders 17
195 #define CommandSegmentFile 18
196 #define CommandSegmentWrap 19
197 #define CommandSegmentStart 20
198 #define CommandSplitWait 21
199 #define CommandCircular 22
200 #define CommandIMV 23
201 #define CommandCamSelect 24
202 #define CommandSettings 25
203 #define CommandSensorMode 26
204 #define CommandIntraRefreshType 27
206 static COMMAND_LIST cmdline_commands[] =
208 { CommandHelp, "-help", "?", "This help information", 0 },
209 { CommandWidth, "-width", "w", "Set image width <size>. Default 1920", 1 },
210 { CommandHeight, "-height", "h", "Set image height <size>. Default 1080", 1 },
211 { CommandBitrate, "-bitrate", "b", "Set bitrate. Use bits per second (e.g. 10MBits/s would be -b 10000000)", 1 },
212 { CommandOutput, "-output", "o", "Output filename <filename> (to write to stdout, use '-o -')", 1 },
213 { CommandVerbose, "-verbose", "v", "Output verbose information during run", 0 },
214 { CommandTimeout, "-timeout", "t", "Time (in ms) to capture for. If not specified, set to 5s. Zero to disable", 1 },
215 { CommandDemoMode, "-demo", "d", "Run a demo mode (cycle through range of camera options, no capture)", 1},
216 { CommandFramerate, "-framerate", "fps","Specify the frames per second to record", 1},
217 { CommandPreviewEnc, "-penc", "e", "Display preview image *after* encoding (shows compression artifacts)", 0},
218 { CommandIntraPeriod, "-intra", "g", "Specify the intra refresh period (key frame rate/GoP size). Zero to produce an initial I-frame and then just P-frames.", 1},
219 { CommandProfile, "-profile", "pf", "Specify H264 profile to use for encoding", 1},
220 { CommandTimed, "-timed", "td", "Cycle between capture and pause. -cycle on,off where on is record time and off is pause time in ms", 0},
221 { CommandSignal, "-signal", "s", "Cycle between capture and pause on Signal", 0},
222 { CommandKeypress, "-keypress", "k", "Cycle between capture and pause on ENTER", 0},
223 { CommandInitialState, "-initial", "i", "Initial state. Use 'record' or 'pause'. Default 'record'", 1},
224 { CommandQP, "-qp", "qp", "Quantisation parameter. Use approximately 10-40. Default 0 (off)", 1},
225 { CommandInlineHeaders, "-inline", "ih", "Insert inline headers (SPS, PPS) to stream", 0},
226 { CommandSegmentFile, "-segment", "sg", "Segment output file in to multiple files at specified interval <ms>", 1},
227 { CommandSegmentWrap, "-wrap", "wr", "In segment mode, wrap any numbered filename back to 1 when reach number", 1},
228 { CommandSegmentStart, "-start", "sn", "In segment mode, start with specified segment number", 1},
229 { CommandSplitWait, "-split", "sp", "In wait mode, create new output file for each start event", 0},
230 { CommandCircular, "-circular", "c", "Run encoded data through circular buffer until triggered then save", 0},
231 { CommandIMV, "-vectors", "x", "Output filename <filename> for inline motion vectors", 1 },
232 { CommandCamSelect, "-camselect", "cs", "Select camera <number>. Default 0", 1 },
233 { CommandSettings, "-settings", "set","Retrieve camera settings and write to stdout", 0},
234 { CommandSensorMode, "-mode", "md", "Force sensor mode. 0=auto. See docs for other modes available", 1},
235 { CommandIntraRefreshType,"-irefresh", "if", "Set intra refresh type", 1},
238 static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
241 static void dump_state(RASPIVID_STATE *state);
244 * Assign a default set of parameters to the state passed in
246 * @param state Pointer to state structure to assign defaults to
248 void raspicapture_default_config(RASPIVID_CONFIG *config)
256 // Default everything to zero
257 memset(config, 0, sizeof(RASPIVID_CONFIG));
259 // Now set anything non-zero
260 config->timeout = 5000; // 5s delay before take image
261 config->width = 1920; // Default to 1080p
262 config->height = 1080;
263 config->bitrate = 17000000; // This is a decent default bitrate for 1080p
264 config->fps_n = VIDEO_FRAME_RATE_NUM;
265 config->fps_d = VIDEO_FRAME_RATE_DEN;
266 config->intraperiod = -1; // Not set
267 config->quantisationParameter = 0;
268 config->demoMode = 0;
269 config->demoInterval = 250; // ms
270 config->immutableInput = 1;
271 config->profile = MMAL_VIDEO_PROFILE_H264_HIGH;
272 config->encoding = MMAL_ENCODING_H264;
274 config->bInlineHeaders = 0;
276 config->inlineMotionVectors = 0;
278 config->cameraNum = 0;
279 config->settings = 0;
280 config->sensor_mode = 0;
282 config->intra_refresh_type = -1;
284 // Setup preview window defaults
285 raspipreview_set_defaults(&config->preview_parameters);
287 // Set up the camera_parameters to default
288 raspicamcontrol_set_defaults(&config->camera_parameters);
294 * Dump image state parameters to printf. Used for debugging
296 * @param state Pointer to state structure to assign defaults to
298 static void dump_state(RASPIVID_STATE *state)
300 RASPIVID_CONFIG *config;
308 config = &state->config;
310 fprintf(stderr, "Width %d, Height %d\n", config->width, config->height);
311 fprintf(stderr, "bitrate %d, framerate %d/%d, time delay %d\n",
312 config->bitrate, config->fps_n, config->fps_d, config->timeout);
313 //fprintf(stderr, "H264 Profile %s\n", raspicli_unmap_xref(config->profile, profile_map, profile_map_size));
315 raspipreview_dump_parameters(&config->preview_parameters);
316 raspicamcontrol_dump_parameters(&config->camera_parameters);
321 * Parse the incoming command line and put resulting parameters in to the state
323 * @param argc Number of arguments in command line
324 * @param argv Array of pointers to strings from command line
325 * @param state Pointer to state structure to assign any discovered parameters to
326 * @return Non-0 if failed for some reason, 0 otherwise
328 static int parse_cmdline(int argc, const char **argv, RASPIVID_STATE *state)
330 // Parse the command line arguments.
331 // We are looking for --<something> or -<abreviation of something>
336 for (i = 1; i < argc && valid; i++)
338 int command_id, num_parameters;
343 if (argv[i][0] != '-')
349 // Assume parameter is valid until proven otherwise
352 command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, &argv[i][1], &num_parameters);
354 // If we found a command but are missing a parameter, continue (and we will drop out of the loop)
355 if (command_id != -1 && num_parameters > 0 && (i + 1 >= argc) )
358 // We are now dealing with a command line option
362 display_valid_parameters(basename(argv[0]));
365 case CommandWidth: // Width > 0
366 if (sscanf(argv[i + 1], "%u", &state->width) != 1)
372 case CommandHeight: // Height > 0
373 if (sscanf(argv[i + 1], "%u", &state->height) != 1)
379 case CommandBitrate: // 1-100
380 if (sscanf(argv[i + 1], "%u", &state->bitrate) == 1)
382 if (state->bitrate > MAX_BITRATE)
384 state->bitrate = MAX_BITRATE;
393 case CommandOutput: // output filename
395 int len = strlen(argv[i + 1]);
398 state->filename = malloc(len + 1);
399 vcos_assert(state->filename);
401 strncpy(state->filename, argv[i + 1], len+1);
409 case CommandVerbose: // display lots of data during run
413 case CommandTimeout: // Time to run viewfinder/capture
415 if (sscanf(argv[i + 1], "%u", &state->timeout) == 1)
417 // Ensure that if previously selected a waitMethod we dont overwrite it
418 if (state->timeout == 0 && state->waitMethod == WAIT_METHOD_NONE)
419 state->waitMethod = WAIT_METHOD_FOREVER;
428 case CommandDemoMode: // Run in demo mode - no capture
430 // Demo mode might have a timing parameter
431 // so check if a) we have another parameter, b) its not the start of the next option
432 if (i + 1 < argc && argv[i+1][0] != '-')
434 if (sscanf(argv[i + 1], "%u", &state->demoInterval) == 1)
436 // TODO : What limits do we need for timeout?
437 if (state->demoInterval == 0)
438 state->demoInterval = 250; // ms
454 case CommandFramerate: // fps to record
456 if (sscanf(argv[i + 1], "%u", &state->framerate) == 1)
458 // TODO : What limits do we need for fps 1 - 30 - 120??
466 case CommandPreviewEnc:
467 state->immutableInput = 0;
470 case CommandIntraPeriod: // key frame rate
472 if (sscanf(argv[i + 1], "%u", &state->intraperiod) == 1)
479 case CommandQP: // quantisation parameter
481 if (sscanf(argv[i + 1], "%u", &state->quantisationParameter) == 1)
488 case CommandProfile: // H264 profile
490 state->profile = raspicli_map_xref(argv[i + 1], profile_map, profile_map_size);
492 if( state->profile == -1)
493 state->profile = MMAL_VIDEO_PROFILE_H264_HIGH;
499 case CommandInlineHeaders: // H264 inline headers
501 state->bInlineHeaders = 1;
507 if (sscanf(argv[i + 1], "%u,%u", &state->onTime, &state->offTime) == 2)
511 if (state->onTime < 1000)
512 state->onTime = 1000;
514 if (state->offTime < 1000)
515 state->offTime = 1000;
517 state->waitMethod = WAIT_METHOD_TIMED;
524 case CommandKeypress:
525 state->waitMethod = WAIT_METHOD_KEYPRESS;
529 state->waitMethod = WAIT_METHOD_SIGNAL;
530 // Reenable the signal
531 signal(SIGUSR1, signal_handler);
534 case CommandInitialState:
536 state->bCapturing = raspicli_map_xref(argv[i + 1], initial_map, initial_map_size);
538 if( state->bCapturing == -1)
539 state->bCapturing = 0;
545 case CommandSegmentFile: // Segment file in to chunks of specified time
547 if (sscanf(argv[i + 1], "%u", &state->segmentSize) == 1)
549 // Must enable inline headers for this to work
550 state->bInlineHeaders = 1;
558 case CommandSegmentWrap: // segment wrap value
560 if (sscanf(argv[i + 1], "%u", &state->segmentWrap) == 1)
567 case CommandSegmentStart: // initial segment number
569 if((sscanf(argv[i + 1], "%u", &state->segmentNumber) == 1) && (!state->segmentWrap || (state->segmentNumber <= state->segmentWrap)))
576 case CommandSplitWait: // split files on restart
578 // Must enable inline headers for this to work
579 state->bInlineHeaders = 1;
580 state->splitWait = 1;
584 case CommandCircular:
586 state->bCircularBuffer = 1;
590 case CommandIMV: // output filename
592 state->inlineMotionVectors = 1;
593 int len = strlen(argv[i + 1]);
596 state->imv_filename = malloc(len + 1);
597 vcos_assert(state->imv_filename);
598 if (state->imv_filename)
599 strncpy(state->imv_filename, argv[i + 1], len+1);
606 case CommandCamSelect: //Select camera input port
608 if (sscanf(argv[i + 1], "%u", &state->cameraNum) == 1)
617 case CommandSettings:
621 case CommandSensorMode:
623 if (sscanf(argv[i + 1], "%u", &state->sensor_mode) == 1)
632 case CommandIntraRefreshType:
634 state->config.intra_refresh_type = raspicli_map_xref(argv[i + 1], intra_refresh_map, intra_refresh_map_size);
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));
647 // Still unused, try preview options
649 parms_used = raspipreview_parse_cmdline(&state->preview_parameters, &argv[i][1], second_arg);
652 // If no parms were used, this must be a bad parameters
665 fprintf(stderr, "Invalid command line option (%s)\n", argv[i-1]);
669 // Always disable verbose if output going to stdout
670 if (state->filename && state->filename[0] == '-')
679 * Display usage information for the application to stdout
681 * @param app_name String to display as the application name
683 static void display_valid_parameters(char *app_name)
687 fprintf(stderr, "Display camera output to display, and optionally saves an H264 capture at requested bitrate\n\n");
688 fprintf(stderr, "\nusage: %s [options]\n\n", app_name);
690 fprintf(stderr, "Image parameter commands\n\n");
692 raspicli_display_help(cmdline_commands, cmdline_commands_size);
695 fprintf(stderr, "\n\nH264 Profile options :\n%s", profile_map[0].mode );
697 for (i=1;i<profile_map_size;i++)
699 fprintf(stderr, ",%s", profile_map[i].mode);
702 fprintf(stderr, "\n");
704 // Intra refresh options
705 fprintf(stderr, "\n\nH264 Intra refresh options :\n%s", intra_refresh_map[0].mode );
707 for (i=1;i<intra_refresh_map_size;i++)
709 fprintf(stderr, ",%s", intra_refresh_map[i].mode);
712 fprintf(stderr, "\n");
714 // Help for preview options
715 raspipreview_display_help();
717 // Now display any help information from the camcontrol code
718 raspicamcontrol_display_help();
720 fprintf(stderr, "\n");
727 * buffer header callback function for camera control
729 * Callback will dump buffer data to the specific file
731 * @param port Pointer to port from which callback originated
732 * @param buffer mmal buffer header pointer
734 static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
736 if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED)
738 MMAL_EVENT_PARAMETER_CHANGED_T *param = (MMAL_EVENT_PARAMETER_CHANGED_T *)buffer->data;
739 switch (param->hdr.id) {
740 case MMAL_PARAMETER_CAMERA_SETTINGS:
742 MMAL_PARAMETER_CAMERA_SETTINGS_T *settings = (MMAL_PARAMETER_CAMERA_SETTINGS_T*)param;
743 vcos_log_error("Exposure now %u, analog gain %u/%u, digital gain %u/%u",
745 settings->analog_gain.num, settings->analog_gain.den,
746 settings->digital_gain.num, settings->digital_gain.den);
747 vcos_log_error("AWB R=%u/%u, B=%u/%u",
748 settings->awb_red_gain.num, settings->awb_red_gain.den,
749 settings->awb_blue_gain.num, settings->awb_blue_gain.den
755 else if (buffer->cmd == MMAL_EVENT_ERROR) {
756 vcos_log_error("Camera control callback got an error");
758 vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd);
761 mmal_buffer_header_release(buffer);
766 * Open a file based on the settings in state
768 * @param state Pointer to state
770 static FILE *open_filename(RASPIVID_STATE *pState)
772 FILE *new_handle = NULL;
773 char *tempname = NULL, *filename = NULL;
775 if (pState->segmentSize || pState->splitWait)
777 // Create a new filename string
778 asprintf(&tempname, pState->filename, pState->segmentNumber);
783 filename = pState->filename;
787 new_handle = fopen(filename, "wb");
792 fprintf(stderr, "Opening output file \"%s\"\n", filename);
794 fprintf(stderr, "Failed to open new file \"%s\"\n", filename);
804 * Open a file based on the settings in state
806 * This time for the imv output file
808 * @param state Pointer to state
810 static FILE *open_imv_filename(RASPIVID_STATE *pState)
812 FILE *new_handle = NULL;
813 char *tempname = NULL, *filename = NULL;
815 if (pState->segmentSize || pState->splitWait)
817 // Create a new filename string
818 asprintf(&tempname, pState->imv_filename, pState->segmentNumber);
823 filename = pState->imv_filename;
827 new_handle = fopen(filename, "wb");
832 fprintf(stderr, "Opening imv output file \"%s\"\n", filename);
834 fprintf(stderr, "Failed to open new imv file \"%s\"\n", filename);
845 * Update any annotation data specific to the video.
846 * This simply passes on the setting from cli, or
847 * if application defined annotate requested, updates
848 * with the H264 parameters
850 * @param state Pointer to state control struct
853 static void update_annotation_data(RASPIVID_STATE *state)
855 RASPIVID_CONFIG *config = &state->config;
857 // So, if we have asked for a application supplied string, set it to the H264 parameters
858 if (config->camera_parameters.enable_annotate & ANNOTATE_APP_TEXT)
861 const char *refresh = raspicli_unmap_xref(config->intra_refresh_type, intra_refresh_map, intra_refresh_map_size);
863 asprintf(&text, "%dk,%ff,%s,%d,%s",
864 config->bitrate / 1000, ((float)(config->fps_n) / config->fps_d),
865 refresh ? refresh : "(none)",
867 raspicli_unmap_xref(config->profile, profile_map, profile_map_size));
869 raspicamcontrol_set_annotate(state->camera_component, config->camera_parameters.enable_annotate, text,
870 config->camera_parameters.annotate_text_size,
871 config->camera_parameters.annotate_text_colour,
872 config->camera_parameters.annotate_bg_colour);
878 raspicamcontrol_set_annotate(state->camera_component, config->camera_parameters.enable_annotate,
879 config->camera_parameters.annotate_string,
880 config->camera_parameters.annotate_text_size,
881 config->camera_parameters.annotate_text_colour,
882 config->camera_parameters.annotate_bg_colour);
889 * buffer header callback function for encoder
891 * Callback will dump buffer data to the specific file
893 * @param port Pointer to port from which callback originated
894 * @param buffer mmal buffer header pointer
896 static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
898 PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata;
899 RASPIVID_STATE *state = pData->state;
900 int64_t current_time;
902 // All our segment times based on the receipt of the first encoder callback
903 if (state->base_time == -1)
904 state->base_time = vcos_getmicrosecs64()/1000;
908 vcos_log_error("Received a encoder buffer callback with no state");
909 // release buffer back to the pool
910 mmal_buffer_header_release(buffer);
914 current_time = vcos_getmicrosecs64()/1000;
915 if (state->base_time == -1)
916 state->base_time = current_time;
918 // See if the second count has changed and we need to update any annotation
919 if (current_time/1000 != state->last_second)
921 update_annotation_data(state);
922 state->last_second = current_time/1000;
925 /* Send buffer to GStreamer element for pushing to the pipeline */
926 mmal_queue_put(state->encoded_buffer_q, buffer);
930 raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **bufp,
931 GstClock *clock, GstClockTime base_time)
933 RASPIVID_CONFIG *config = &state->config;
935 MMAL_BUFFER_HEADER_T *buffer;
936 GstFlowReturn ret = GST_FLOW_ERROR;
937 /* No timestamps if no clockm or invalid PTS */
938 GstClockTime gst_pts = GST_CLOCK_TIME_NONE;
940 /* FIXME: Use our own interruptible cond wait: */
941 buffer = mmal_queue_wait(state->encoded_buffer_q);
944 if (G_LIKELY (config->useSTC && clock)) {
945 MMAL_PARAMETER_INT64_T param;
946 GstClockTime runtime;
948 runtime = gst_clock_get_time (clock) - base_time;
950 param.hdr.id = MMAL_PARAMETER_SYSTEM_TIME;
951 param.hdr.size = sizeof(param);
954 mmal_port_parameter_get(state->encoder_output_port, ¶m.hdr);
956 if (buffer->pts != -1 && param.value != -1 && param.value >= buffer->pts) {
957 /* Convert microsecond RPi TS to GStreamer clock: */
958 GstClockTime offset = (param.value - buffer->pts) * 1000;
959 if (runtime >= offset)
960 gst_pts = runtime - offset;
962 GST_LOG ("Buf (uS) PTS %" G_GINT64_FORMAT " DTS %" G_GINT64_FORMAT
963 " STC %" G_GINT64_FORMAT " (latency %" G_GINT64_FORMAT
964 "uS) TS %" GST_TIME_FORMAT,
965 buffer->pts, buffer->dts, param.value, param.value - buffer->pts,
966 GST_TIME_ARGS (gst_pts));
969 GST_LOG ("use-stc=false. Not applying STC to buffer");
972 mmal_buffer_header_mem_lock(buffer);
973 buf = gst_buffer_new_allocate(NULL, buffer->length, NULL);
976 GST_BUFFER_DTS(buf) = GST_BUFFER_PTS(buf) = gst_pts;
977 /* FIXME: Can we avoid copies and give MMAL our own buffers to fill? */
978 gst_buffer_fill(buf, 0, buffer->data, buffer->length);
982 mmal_buffer_header_mem_unlock(buffer);
985 // release buffer back to the pool
986 mmal_buffer_header_release(buffer);
988 // and send one back to the port (if still open)
989 if (state->encoder_output_port->is_enabled)
991 MMAL_STATUS_T status = MMAL_SUCCESS;
993 buffer = mmal_queue_get(state->encoder_pool->queue);
995 status = mmal_port_send_buffer(state->encoder_output_port, buffer);
997 if (!buffer || status != MMAL_SUCCESS) {
998 vcos_log_error("Unable to return a buffer to the encoder port");
999 ret = GST_FLOW_ERROR;
1007 * Create the camera component, set up its ports
1009 * @param state Pointer to state control struct
1011 * @return MMAL_SUCCESS if all OK, something else otherwise
1014 static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
1016 MMAL_COMPONENT_T *camera = NULL;
1017 MMAL_STATUS_T status;
1018 RASPIVID_CONFIG *config = &state->config;
1020 /* Create the component */
1021 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
1023 if (status != MMAL_SUCCESS)
1025 vcos_log_error("Failed to create camera component");
1029 MMAL_PARAMETER_INT32_T camera_num =
1030 {{MMAL_PARAMETER_CAMERA_NUM, sizeof(camera_num)}, config->cameraNum};
1032 status = mmal_port_parameter_set(camera->control, &camera_num.hdr);
1034 if (status != MMAL_SUCCESS)
1036 vcos_log_error("Could not select camera : error %d", status);
1040 if (!camera->output_num)
1042 status = MMAL_ENOSYS;
1043 vcos_log_error("Camera doesn't have output ports");
1047 status = mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, config->sensor_mode);
1049 if (status != MMAL_SUCCESS)
1051 vcos_log_error("Could not set sensor mode : error %d", status);
1055 if (config->settings)
1057 MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T change_event_request =
1058 {{MMAL_PARAMETER_CHANGE_EVENT_REQUEST, sizeof(MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T)},
1059 MMAL_PARAMETER_CAMERA_SETTINGS, 1};
1061 status = mmal_port_parameter_set(camera->control, &change_event_request.hdr);
1062 if ( status != MMAL_SUCCESS )
1064 vcos_log_error("No camera settings events");
1068 // Enable the camera, and tell it its control callback function
1069 status = mmal_port_enable(camera->control, camera_control_callback);
1071 if (status != MMAL_SUCCESS)
1073 vcos_log_error("Unable to enable control port : error %d", status);
1077 state->camera_component = camera;
1083 mmal_component_destroy(camera);
1089 raspi_capture_set_format_and_start(RASPIVID_STATE *state)
1091 MMAL_COMPONENT_T *camera = NULL;
1092 MMAL_STATUS_T status;
1093 MMAL_ES_FORMAT_T *format;
1094 MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL;
1095 RASPIVID_CONFIG *config = &state->config;
1097 // set up the camera configuration
1099 MMAL_PARAMETER_CAMERA_CONFIG_T cam_config =
1101 { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) },
1102 .max_stills_w = config->width,
1103 .max_stills_h = config->height,
1105 .one_shot_stills = 0,
1106 .max_preview_video_w = config->width,
1107 .max_preview_video_h = config->height,
1108 .num_preview_video_frames = 3,
1109 .stills_capture_circular_buffer_height = 0,
1110 .fast_preview_resume = 0,
1111 .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RAW_STC
1114 camera = state->camera_component;
1115 preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT];
1116 video_port = camera->output[MMAL_CAMERA_VIDEO_PORT];
1117 still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT];
1119 mmal_port_parameter_set(camera->control, &cam_config.hdr);
1121 // Now set up the port formats
1123 // Set the encode format on the Preview port
1124 // HW limitations mean we need the preview to be the same size as the required recorded output
1126 format = preview_port->format;
1128 if(config->camera_parameters.shutter_speed > 6000000)
1130 MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
1131 { 50, 1000 }, {166, 1000}};
1132 mmal_port_parameter_set(preview_port, &fps_range.hdr);
1134 else if(config->camera_parameters.shutter_speed > 1000000)
1136 MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
1137 { 166, 1000 }, {999, 1000}};
1138 mmal_port_parameter_set(preview_port, &fps_range.hdr);
1141 //enable dynamic framerate if necessary
1142 if (config->camera_parameters.shutter_speed)
1144 if (((float)(config->fps_n) / config->fps_d) > 1000000.0 / config->camera_parameters.shutter_speed)
1148 GST_INFO ("Enabling dynamic frame rate to fulfil shutter speed requirement");
1152 format->encoding = MMAL_ENCODING_OPAQUE;
1153 format->encoding_variant = MMAL_ENCODING_I420;
1155 format->es->video.width = VCOS_ALIGN_UP(config->width, 32);
1156 format->es->video.height = VCOS_ALIGN_UP(config->height, 16);
1157 format->es->video.crop.x = 0;
1158 format->es->video.crop.y = 0;
1159 format->es->video.crop.width = config->width;
1160 format->es->video.crop.height = config->height;
1161 format->es->video.frame_rate.num = config->fps_n;
1162 format->es->video.frame_rate.den = config->fps_d;
1164 status = mmal_port_format_commit(preview_port);
1166 if (status != MMAL_SUCCESS)
1168 vcos_log_error("camera viewfinder format couldn't be set");
1172 // Set the encode format on the video port
1173 format = video_port->format;
1175 if(config->camera_parameters.shutter_speed > 6000000)
1177 MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
1178 { 50, 1000 }, {166, 1000}};
1179 mmal_port_parameter_set(video_port, &fps_range.hdr);
1181 else if(config->camera_parameters.shutter_speed > 1000000)
1183 MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
1184 { 167, 1000 }, {999, 1000}};
1185 mmal_port_parameter_set(video_port, &fps_range.hdr);
1188 /* If encoding, set opaque tunneling format */
1189 if (state->encoder_component) {
1190 format->encoding = MMAL_ENCODING_OPAQUE;
1191 format->encoding_variant = MMAL_ENCODING_I420;
1194 format->encoding = config->encoding;
1195 format->encoding_variant = config->encoding;
1198 format->es->video.width = VCOS_ALIGN_UP(config->width, 32);
1199 format->es->video.height = VCOS_ALIGN_UP(config->height, 16);
1200 format->es->video.crop.x = 0;
1201 format->es->video.crop.y = 0;
1202 format->es->video.crop.width = config->width;
1203 format->es->video.crop.height = config->height;
1204 format->es->video.frame_rate.num = config->fps_n;
1205 format->es->video.frame_rate.den = config->fps_d;
1207 status = mmal_port_format_commit(video_port);
1209 if (status != MMAL_SUCCESS)
1211 vcos_log_error("camera video format couldn't be set");
1215 // Ensure there are enough buffers to avoid dropping frames
1216 if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
1217 video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
1220 // Set the encode format on the still port
1222 format = still_port->format;
1224 format->encoding = MMAL_ENCODING_OPAQUE;
1225 format->encoding_variant = MMAL_ENCODING_I420;
1227 format->es->video.width = VCOS_ALIGN_UP(config->width, 32);
1228 format->es->video.height = VCOS_ALIGN_UP(config->height, 16);
1229 format->es->video.crop.x = 0;
1230 format->es->video.crop.y = 0;
1231 format->es->video.crop.width = config->width;
1232 format->es->video.crop.height = config->height;
1233 format->es->video.frame_rate.num = 0;
1234 format->es->video.frame_rate.den = 1;
1236 status = mmal_port_format_commit(still_port);
1238 if (status != MMAL_SUCCESS)
1240 vcos_log_error("camera still format couldn't be set");
1244 /* Ensure there are enough buffers to avoid dropping frames */
1245 if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
1246 still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
1248 /* Enable component */
1249 status = mmal_component_enable(camera);
1251 if (status != MMAL_SUCCESS)
1253 vcos_log_error("camera component couldn't be enabled");
1257 raspicamcontrol_set_all_parameters(camera, &config->camera_parameters);
1259 update_annotation_data(state);
1261 if (config->verbose)
1262 fprintf(stderr, "Camera component done\n");
1269 mmal_component_destroy(camera);
1275 * Destroy the camera component
1277 * @param state Pointer to state control struct
1280 static void destroy_camera_component(RASPIVID_STATE *state)
1282 if (state->camera_component)
1284 mmal_component_destroy(state->camera_component);
1285 state->camera_component = NULL;
1289 gboolean raspi_capture_request_i_frame(RASPIVID_STATE *state)
1291 MMAL_PORT_T *encoder_output = NULL;
1292 MMAL_STATUS_T status;
1293 MMAL_PARAMETER_BOOLEAN_T param = {{ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME, sizeof(param)}, 1};
1295 if (state->encoder_component)
1298 encoder_output = state->encoder_component->output[0];
1299 status = mmal_port_parameter_set(encoder_output, ¶m.hdr);
1300 if (status != MMAL_SUCCESS)
1302 vcos_log_error("Unable to request I-frame");
1309 * Create the encoder component, set up its ports
1311 * @param state Pointer to state control struct
1313 * @return MMAL_SUCCESS if all OK, something else otherwise
1316 static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
1318 MMAL_COMPONENT_T *encoder = 0;
1319 MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL;
1320 MMAL_STATUS_T status;
1321 RASPIVID_CONFIG *config = &state->config;
1323 gboolean encoded_format =
1324 (config->encoding == MMAL_ENCODING_H264 ||
1325 config->encoding == MMAL_ENCODING_MJPEG ||
1326 config->encoding == MMAL_ENCODING_JPEG);
1328 if (!encoded_format)
1329 return MMAL_SUCCESS;
1331 if (config->encoding == MMAL_ENCODING_JPEG)
1332 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER, &encoder);
1334 status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, &encoder);
1336 if (status != MMAL_SUCCESS) {
1337 vcos_log_error("Unable to create video encoder component");
1341 if (!encoder->input_num || !encoder->output_num)
1343 status = MMAL_ENOSYS;
1344 vcos_log_error("Video encoder doesn't have input/output ports");
1348 encoder_input = encoder->input[0];
1349 encoder_output = encoder->output[0];
1351 // We want same format on input and output
1352 mmal_format_copy(encoder_output->format, encoder_input->format);
1354 // Configure desired encoding
1355 encoder_output->format->encoding = config->encoding;
1357 encoder_output->format->bitrate = config->bitrate;
1359 if (config->encoding == MMAL_ENCODING_H264)
1360 encoder_output->buffer_size = encoder_output->buffer_size_recommended;
1362 encoder_output->buffer_size = 256<<10;
1364 if (encoder_output->buffer_size < encoder_output->buffer_size_min)
1365 encoder_output->buffer_size = encoder_output->buffer_size_min;
1367 encoder_output->buffer_num = encoder_output->buffer_num_recommended;
1369 if (encoder_output->buffer_num < encoder_output->buffer_num_min)
1370 encoder_output->buffer_num = encoder_output->buffer_num_min;
1372 GST_DEBUG ("encoder wants %d buffers of size %u",
1373 (guint)encoder_output->buffer_num, (guint)encoder_output->buffer_size);
1375 // We need to set the frame rate on output to 0, to ensure it gets
1376 // updated correctly from the input framerate when port connected
1377 encoder_output->format->es->video.frame_rate.num = 0;
1378 encoder_output->format->es->video.frame_rate.den = 1;
1380 // Commit the port changes to the output port
1381 status = mmal_port_format_commit(encoder_output);
1382 if (status != MMAL_SUCCESS) {
1383 vcos_log_error("Unable to set format on video encoder output port");
1387 // Set the rate control parameter
1390 MMAL_PARAMETER_VIDEO_RATECONTROL_T param = {{ MMAL_PARAMETER_RATECONTROL, sizeof(param)}, MMAL_VIDEO_RATECONTROL_DEFAULT};
1391 status = mmal_port_parameter_set(encoder_output, ¶m.hdr);
1392 if (status != MMAL_SUCCESS)
1394 vcos_log_error("Unable to set ratecontrol");
1400 if (config->encoding == MMAL_ENCODING_H264 && config->intraperiod != -1)
1402 MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, config->intraperiod};
1403 status = mmal_port_parameter_set(encoder_output, ¶m.hdr);
1404 if (status != MMAL_SUCCESS)
1406 vcos_log_error("Unable to set intraperiod");
1411 if (config->encoding == MMAL_ENCODING_H264 && config->quantisationParameter)
1413 MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, config->quantisationParameter};
1414 status = mmal_port_parameter_set(encoder_output, ¶m.hdr);
1415 if (status != MMAL_SUCCESS)
1417 vcos_log_error("Unable to set initial QP");
1421 MMAL_PARAMETER_UINT32_T param2 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, sizeof(param)}, config->quantisationParameter};
1422 status = mmal_port_parameter_set(encoder_output, ¶m2.hdr);
1423 if (status != MMAL_SUCCESS)
1425 vcos_log_error("Unable to set min QP");
1429 MMAL_PARAMETER_UINT32_T param3 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, sizeof(param)}, config->quantisationParameter};
1430 status = mmal_port_parameter_set(encoder_output, ¶m3.hdr);
1431 if (status != MMAL_SUCCESS)
1433 vcos_log_error("Unable to set max QP");
1438 if (config->encoding == MMAL_ENCODING_H264)
1440 MMAL_PARAMETER_VIDEO_PROFILE_T param;
1441 param.hdr.id = MMAL_PARAMETER_PROFILE;
1442 param.hdr.size = sizeof(param);
1444 param.profile[0].profile = config->profile;
1445 param.profile[0].level = MMAL_VIDEO_LEVEL_H264_4; // This is the only value supported
1447 status = mmal_port_parameter_set(encoder_output, ¶m.hdr);
1448 if (status != MMAL_SUCCESS)
1450 vcos_log_error("Unable to set H264 profile");
1455 if (config->encoding != MMAL_ENCODING_JPEG)
1457 if (mmal_port_parameter_set_boolean(encoder_input, MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, config->immutableInput) != MMAL_SUCCESS)
1459 vcos_log_error("Unable to set immutable input flag");
1460 // Continue rather than abort..
1463 //set INLINE HEADER flag to generate SPS and PPS for every IDR if requested
1464 if (mmal_port_parameter_set_boolean(encoder_output, MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, config->bInlineHeaders) != MMAL_SUCCESS)
1466 vcos_log_error("failed to set INLINE HEADER FLAG parameters");
1467 // Continue rather than abort..
1471 if (config->encoding == MMAL_ENCODING_H264)
1473 //set INLINE VECTORS flag to request motion vector estimates
1474 if (mmal_port_parameter_set_boolean(encoder_output, MMAL_PARAMETER_VIDEO_ENCODE_INLINE_VECTORS, config->inlineMotionVectors) != MMAL_SUCCESS)
1476 vcos_log_error("failed to set INLINE VECTORS parameters");
1477 // Continue rather than abort..
1480 // Adaptive intra refresh settings
1481 if (config->intra_refresh_type != -1)
1483 MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T param;
1485 /* Need to memset, apparently mmal_port_parameter_get()
1486 * doesn't retrieve all parameters, causing random failures
1489 memset (¶m, 0, sizeof (MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T));
1491 param.hdr.id = MMAL_PARAMETER_VIDEO_INTRA_REFRESH;
1492 param.hdr.size = sizeof(param);
1494 // Get first so we don't overwrite anything unexpectedly
1495 status = mmal_port_parameter_get(encoder_output, ¶m.hdr);
1497 param.refresh_mode = config->intra_refresh_type;
1499 //if (state->intra_refresh_type == MMAL_VIDEO_INTRA_REFRESH_CYCLIC_MROWS)
1500 // param.cir_mbs = 10;
1502 status = mmal_port_parameter_set(encoder_output, ¶m.hdr);
1503 if (status != MMAL_SUCCESS)
1505 vcos_log_error("Unable to set H264 intra-refresh values");
1511 if (config->encoding == MMAL_ENCODING_JPEG)
1513 status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_Q_FACTOR, config->jpegQuality);
1514 if (status != MMAL_SUCCESS) {
1515 vcos_log_error("Unable to set JPEG quality");
1516 // Continue after warning
1519 #ifdef MMAL_PARAMETER_JPEG_RESTART_INTERVAL
1520 status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_RESTART_INTERVAL, config->jpegRestartInterval);
1521 if (status != MMAL_SUCCESS) {
1522 vcos_log_error("Unable to set JPEG restart interval");
1523 // Continue after warning
1529 status = mmal_component_enable(encoder);
1531 if (status != MMAL_SUCCESS)
1533 vcos_log_error("Unable to enable video encoder component");
1537 state->encoder_component = encoder;
1539 if (config->verbose)
1540 fprintf(stderr, "Encoder component done\n");
1546 mmal_component_destroy(encoder);
1548 state->encoder_component = NULL;
1554 * Destroy the encoder component
1556 * @param state Pointer to state control struct
1559 static void destroy_encoder_component(RASPIVID_STATE *state)
1561 /* Empty the buffer header q */
1562 if (state->encoded_buffer_q) {
1563 while (mmal_queue_length(state->encoded_buffer_q)) {
1564 MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->encoded_buffer_q);
1565 mmal_buffer_header_release(buffer);
1569 // Get rid of any port buffers first
1570 if (state->encoder_pool)
1572 mmal_port_pool_destroy(state->encoder_output_port, state->encoder_pool);
1573 state->encoder_pool = NULL;
1576 if (state->encoder_component) {
1578 mmal_component_destroy(state->encoder_component);
1579 state->encoder_component = NULL;
1584 * Connect two specific ports together
1586 * @param output_port Pointer the output port
1587 * @param input_port Pointer the input port
1588 * @param Pointer to a mmal connection pointer, reassigned if function successful
1589 * @return Returns a MMAL_STATUS_T giving result of operation
1592 static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection)
1594 MMAL_STATUS_T status;
1596 status = mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT);
1598 if (status == MMAL_SUCCESS)
1600 status = mmal_connection_enable(*connection);
1601 if (status != MMAL_SUCCESS)
1602 mmal_connection_destroy(*connection);
1609 * Checks if specified port is valid and enabled, then disables it
1611 * @param port Pointer the port
1614 static void check_disable_port(MMAL_PORT_T *port)
1616 if (port && port->is_enabled)
1617 mmal_port_disable(port);
1620 void raspicapture_init()
1624 // Register our application with the logging system
1625 vcos_log_register("RaspiVid", VCOS_LOG_CATEGORY);
1629 raspi_capture_setup(RASPIVID_CONFIG *config)
1631 // Our main data storage vessel..
1632 RASPIVID_STATE *state;
1634 MMAL_STATUS_T status = MMAL_SUCCESS;
1636 /* Default everything to zero */
1637 state = calloc(1, sizeof(RASPIVID_STATE));
1639 /* Apply passed in config */
1640 state->config = *config;
1642 /* Initialize timestamping */
1643 state->base_time = state->last_second = -1;
1645 /* So far, all we can do is create the camera component. Actual
1646 * config and connection of encoders etc happens in _start()
1648 // OK, we have a nice set of parameters. Now set up our components
1649 // We have three components. Camera, Preview and encoder.
1651 if ((status = create_camera_component(state)) != MMAL_SUCCESS)
1653 vcos_log_error("%s: Failed to create camera component", __func__);
1657 if ((status = raspipreview_create(&state->preview_state, &config->preview_parameters)) != MMAL_SUCCESS)
1659 vcos_log_error("%s: Failed to create preview component", __func__);
1660 destroy_camera_component(state);
1664 state->encoded_buffer_q = mmal_queue_create();
1670 raspi_capture_start(RASPIVID_STATE *state)
1672 MMAL_STATUS_T status = MMAL_SUCCESS;
1673 RASPIVID_CONFIG *config = &state->config;
1675 MMAL_PORT_T *camera_preview_port = NULL;
1676 MMAL_PORT_T *preview_input_port = NULL;
1677 MMAL_PORT_T *encoder_input_port = NULL;
1681 if ((status = create_encoder_component(state)) != MMAL_SUCCESS) {
1682 vcos_log_error("%s: Failed to create encode component", __func__);
1686 if (config->verbose)
1691 state->camera_video_port = state->camera_component->output[MMAL_CAMERA_VIDEO_PORT];
1692 state->camera_still_port = state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
1693 camera_preview_port = state->camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
1694 preview_input_port = state->preview_state.preview_component->input[0];
1696 if (state->encoder_component) {
1697 encoder_input_port = state->encoder_component->input[0];
1698 state->encoder_output_port = state->encoder_component->output[0];
1700 state->encoder_output_port = state->camera_video_port;
1703 if ((status = raspi_capture_set_format_and_start(state)) != MMAL_SUCCESS) {
1707 GST_DEBUG ("Creating pool of %d buffers of size %d",
1708 state->encoder_output_port->buffer_num, state->encoder_output_port->buffer_size);
1709 /* Create pool of buffer headers for the output port to consume */
1710 pool = mmal_port_pool_create(state->encoder_output_port,
1711 state->encoder_output_port->buffer_num, state->encoder_output_port->buffer_size);
1714 vcos_log_error("Failed to create buffer header pool for encoder output port %s",
1715 state->encoder_output_port->name);
1718 state->encoder_pool = pool;
1720 if (state->config.verbose)
1721 fprintf(stderr, "Starting component connection stage\n");
1723 if (config->preview_parameters.wantPreview )
1725 if (config->verbose)
1727 fprintf(stderr, "Connecting camera preview port to preview input port\n");
1728 fprintf(stderr, "Starting video preview\n");
1731 // Connect camera to preview
1732 status = connect_ports(camera_preview_port, preview_input_port, &state->preview_connection);
1733 if (status != MMAL_SUCCESS)
1735 vcos_log_error("%s: Failed to connect camera to preview", __func__);
1740 if (state->encoder_component) {
1741 if (config->verbose)
1742 fprintf(stderr, "Connecting camera video port to encoder input port\n");
1744 // Now connect the camera to the encoder
1745 status = connect_ports(state->camera_video_port, encoder_input_port, &state->encoder_connection);
1746 if (status != MMAL_SUCCESS)
1748 if (config->preview_parameters.wantPreview )
1749 mmal_connection_destroy(state->preview_connection);
1750 vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__);
1755 // Set up our userdata - this is passed though to the callback where we need the information.
1756 state->callback_data.state = state;
1757 state->callback_data.abort = 0;
1759 state->encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&state->callback_data;
1761 if (config->verbose)
1762 fprintf(stderr, "Enabling encoder output port\n");
1764 // Enable the encoder output port and tell it its callback function
1765 status = mmal_port_enable(state->encoder_output_port, encoder_buffer_callback);
1766 if (status != MMAL_SUCCESS)
1768 vcos_log_error("Failed to setup encoder output");
1772 if (config->demoMode)
1774 // Run for the user specific time..
1775 int num_iterations = config->timeout / config->demoInterval;
1778 if (config->verbose)
1779 fprintf(stderr, "Running in demo mode\n");
1781 for (i=0;config->timeout == 0 || i<num_iterations;i++)
1783 raspicamcontrol_cycle_test(state->camera_component);
1784 vcos_sleep(state->config.demoInterval);
1788 if (config->verbose)
1789 fprintf(stderr, "Starting video capture\n");
1791 if (mmal_port_parameter_set_boolean(state->camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
1796 // Send all the buffers to the encoder output port
1798 int num = mmal_queue_length(state->encoder_pool->queue);
1802 MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->encoder_pool->queue);
1805 vcos_log_error("Unable to get a required buffer %d from pool queue", q);
1807 if (mmal_port_send_buffer(state->encoder_output_port, buffer)!= MMAL_SUCCESS)
1808 vcos_log_error("Unable to send a buffer to encoder output port (%d)", q);
1813 // Now wait until we need to stop. Whilst waiting we do need to check to see if we have aborted (for example
1814 // out of storage space)
1815 // Going to check every ABORT_INTERVAL milliseconds
1818 for (wait = 0; config->timeout == 0 || wait < config->timeout; wait+= ABORT_INTERVAL)
1820 vcos_sleep(ABORT_INTERVAL);
1821 if (state->callback_data.abort)
1825 if (config->verbose)
1826 fprintf(stderr, "Finished capture\n");
1829 return (status == MMAL_SUCCESS);
1832 raspi_capture_stop(state);
1834 if (status != MMAL_SUCCESS) {
1835 mmal_status_to_int(status);
1836 raspicamcontrol_check_configuration(128);
1843 raspi_capture_stop(RASPIVID_STATE *state)
1845 RASPIVID_CONFIG *config = &state->config;
1847 if (config->verbose)
1848 fprintf(stderr, "Closing down\n");
1850 if (config->preview_parameters.wantPreview )
1851 mmal_connection_destroy(state->preview_connection);
1853 // Disable all our ports that are not handled by connections
1854 check_disable_port(state->camera_still_port);
1855 check_disable_port(state->encoder_output_port);
1857 if (state->encoder_component) {
1858 mmal_connection_destroy(state->encoder_connection);
1859 mmal_component_disable(state->encoder_component);
1860 destroy_encoder_component(state);
1865 raspi_capture_free(RASPIVID_STATE *state)
1867 RASPIVID_CONFIG *config = &state->config;
1869 // Can now close our file. Note disabling ports may flush buffers which causes
1870 // problems if we have already closed the file!
1871 if (state->output_file && state->output_file != stdout)
1872 fclose(state->output_file);
1874 /* Disable components */
1875 if (state->encoder_component)
1876 mmal_component_disable(state->encoder_component);
1878 if (state->preview_state.preview_component)
1879 mmal_component_disable(state->preview_state.preview_component);
1881 if (state->camera_component)
1882 mmal_component_disable(state->camera_component);
1884 destroy_encoder_component(state);
1885 raspipreview_destroy(&state->preview_state);
1886 destroy_camera_component(state);
1888 if (state->encoded_buffer_q) {
1889 mmal_queue_destroy(state->encoded_buffer_q);
1890 state->encoded_buffer_q = NULL;
1893 if (config->verbose)
1894 fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
1900 raspi_capture_update_config (RASPIVID_STATE *state, RASPIVID_CONFIG *config, gboolean dynamic)
1902 MMAL_STATUS_T status;
1903 RASPICAM_CAMERA_PARAMETERS *params = &config->camera_parameters;
1904 MMAL_COMPONENT_T *camera = state->camera_component;
1906 /* Store the new config */
1907 state->config = *config;
1911 if (state->encoder_component && config->change_flags & PROP_CHANGE_ENCODING) {
1912 /* BITRATE or QUANT or KEY Interval, intra refresh */
1913 MMAL_COMPONENT_T *encoder = state->encoder_component;
1914 MMAL_PORT_T *encoder_output = encoder->output[0];
1916 status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_VIDEO_BIT_RATE, config->bitrate);
1917 if (status != MMAL_SUCCESS)
1918 vcos_log_warn("Unable to change bitrate dynamically");
1921 MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, config->intraperiod};
1922 status = mmal_port_parameter_set(encoder_output, ¶m.hdr);
1923 if (status != MMAL_SUCCESS)
1924 vcos_log_warn("Unable to change intraperiod dynamically");
1927 #if 0 /* not dynamically change-able */
1929 MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, config->quantisationParameter};
1930 status = mmal_port_parameter_set(encoder_output, ¶m.hdr);
1931 if (status != MMAL_SUCCESS)
1932 vcos_log_warn("Unable to change Initial Quantisation Parameter dynamically");
1934 MMAL_PARAMETER_UINT32_T param2 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, sizeof(param)}, config->quantisationParameter};
1935 status = mmal_port_parameter_set(encoder_output, ¶m2.hdr);
1936 if (status != MMAL_SUCCESS)
1937 vcos_log_warn("Unable to change Minimum Quantisation Parameter dynamically");
1939 MMAL_PARAMETER_UINT32_T param3 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, sizeof(param)}, config->quantisationParameter};
1940 status = mmal_port_parameter_set(encoder_output, ¶m3.hdr);
1941 if (status != MMAL_SUCCESS)
1942 vcos_log_warn("Unable to change Maximum Quantisation Parameter dynamically");
1946 // Adaptive intra refresh settings
1947 MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T param;
1948 param.hdr.id = MMAL_PARAMETER_VIDEO_INTRA_REFRESH;
1949 param.hdr.size = sizeof(param);
1951 // Get first so we don't overwrite anything unexpectedly
1952 status = mmal_port_parameter_get(encoder_output, ¶m.hdr);
1953 if (state != MMAL_SUCCESS) {
1954 /* Need to memset, apparently mmal_port_parameter_get()
1955 * doesn't retrieve all parameters, causing random failures
1956 * when we set it. On older firmware the get fails.
1958 memset (¶m, 0, sizeof (MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T));
1960 param.refresh_mode = config->intra_refresh_type;
1962 status = mmal_port_parameter_set(encoder_output, ¶m.hdr);
1963 if (status != MMAL_SUCCESS)
1964 vcos_log_warn("Unable to set H264 intra-refresh values dynamically");
1968 if (config->change_flags & PROP_CHANGE_PREVIEW) {
1969 /* Preview settings or fullscreen */
1970 status = raspipreview_update_config (&state->preview_state,
1971 &config->preview_parameters);
1972 if (status != MMAL_SUCCESS)
1973 vcos_log_warn("Unable to change preview config dynamically");
1975 if (config->change_flags & PROP_CHANGE_COLOURBALANCE) {
1976 raspicamcontrol_set_saturation(camera, params->saturation);
1977 raspicamcontrol_set_sharpness(camera, params->sharpness);
1978 raspicamcontrol_set_contrast(camera, params->contrast);
1979 raspicamcontrol_set_brightness(camera, params->brightness);
1981 if (config->change_flags & PROP_CHANGE_SENSOR_SETTINGS) {
1982 /* ISO, EXPOSURE, SHUTTER, DRC, Sensor Mode */
1983 raspicamcontrol_set_ISO(camera, params->ISO);
1984 raspicamcontrol_set_exposure_compensation(camera, params->exposureCompensation);
1985 raspicamcontrol_set_exposure_mode(camera, params->exposureMode);
1986 raspicamcontrol_set_metering_mode(camera, params->exposureMeterMode);
1987 raspicamcontrol_set_shutter_speed(camera, params->shutter_speed);
1988 raspicamcontrol_set_DRC(camera, params->drc_level);
1990 /* Can we change sensor mode on the fly? Disable if not */
1991 status = mmal_port_parameter_set_uint32(camera->control,
1992 MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, config->sensor_mode);
1993 if (status != MMAL_SUCCESS)
1994 vcos_log_warn("Unable to change sensor mode dynamically");
1996 if (config->change_flags & PROP_CHANGE_VIDEO_STABILISATION) {
1997 raspicamcontrol_set_video_stabilisation(camera, params->videoStabilisation);
1999 if (config->change_flags & PROP_CHANGE_AWB) {
2000 raspicamcontrol_set_awb_mode(camera, params->awbMode);
2001 raspicamcontrol_set_awb_gains(camera, params->awb_gains_r, params->awb_gains_b);
2003 if (config->change_flags & PROP_CHANGE_IMAGE_COLOUR_EFFECT) {
2004 raspicamcontrol_set_imageFX(camera, params->imageEffect);
2005 raspicamcontrol_set_colourFX(camera, ¶ms->colourEffects);
2007 if (config->change_flags & PROP_CHANGE_ORIENTATION) {
2008 raspicamcontrol_set_rotation(camera, params->rotation);
2009 raspicamcontrol_set_flips(camera, params->hflip, params->vflip);
2011 if (config->change_flags & PROP_CHANGE_ROI) {
2012 raspicamcontrol_set_ROI(camera, params->roi);
2014 if (config->change_flags & PROP_CHANGE_ANNOTATION)
2015 update_annotation_data(state);