1 | /* |
2 | Copyright (c) 2013, Broadcom Europe Ltd |
3 | Copyright (c) 2013, James Hughes |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met: |
8 | * Redistributions of source code must retain the above copyright |
9 | notice, this list of conditions and the following disclaimer. |
10 | * Redistributions in binary form must reproduce the above copyright |
11 | notice, this list of conditions and the following disclaimer in the |
12 | documentation and/or other materials provided with the distribution. |
13 | * Neither the name of the copyright holder nor the |
14 | names of its contributors may be used to endorse or promote products |
15 | derived from this software without specific prior written permission. |
16 | |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include <stdio.h> |
30 | #include <stdlib.h> |
31 | #include <string.h> |
32 | #include <memory.h> |
33 | |
34 | #include "interface/vcos/vcos.h" |
35 | |
36 | #include "interface/mmal/mmal.h" |
37 | #include "interface/mmal/mmal_logging.h" |
38 | #include "interface/mmal/mmal_buffer.h" |
39 | #include "interface/mmal/util/mmal_util.h" |
40 | #include "interface/mmal/util/mmal_util_params.h" |
41 | #include "interface/mmal/util/mmal_default_components.h" |
42 | #include "interface/mmal/util/mmal_connection.h" |
43 | |
44 | #include "RaspiPreview.h" |
45 | #include "RaspiCLI.h" |
46 | |
47 | enum |
48 | { |
49 | CommandPreview, |
50 | CommandFullScreen, |
51 | CommandOpacity, |
52 | CommandDisablePreview, |
53 | CommandDisplayNum, |
54 | }; |
55 | |
56 | static COMMAND_LIST cmdline_commands[] = |
57 | { |
58 | { CommandPreview, "-preview" , "p" , "Preview window settings <'x,y,w,h'>" , 1 }, |
59 | { CommandFullScreen, "-fullscreen" , "f" , "Fullscreen preview mode" , 0 }, |
60 | { CommandOpacity, "-opacity" , "op" , "Preview window opacity (0-255)" , 1}, |
61 | { CommandDisablePreview,"-nopreview" , "n" , "Do not display a preview window" , 0}, |
62 | { CommandDisplayNum, "-dispnum" , "dn" , "Display on which to display the preview window (dispmanx/tvservice numbering)" , 1}, |
63 | }; |
64 | |
65 | static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]); |
66 | |
67 | /** |
68 | * Create the preview component, set up its ports |
69 | * |
70 | * @param state Pointer to state control struct |
71 | * |
72 | * @return MMAL_SUCCESS if all OK, something else otherwise |
73 | * |
74 | */ |
75 | MMAL_STATUS_T raspipreview_create(RASPIPREVIEW_PARAMETERS *state) |
76 | { |
77 | MMAL_COMPONENT_T *preview = 0; |
78 | MMAL_PORT_T *preview_port = NULL; |
79 | MMAL_STATUS_T status; |
80 | |
81 | if (!state->wantPreview) |
82 | { |
83 | // No preview required, so create a null sink component to take its place |
84 | status = mmal_component_create("vc.null_sink" , &preview); |
85 | |
86 | if (status != MMAL_SUCCESS) |
87 | { |
88 | vcos_log_error("Unable to create null sink component" ); |
89 | goto error; |
90 | } |
91 | } |
92 | else |
93 | { |
94 | status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, |
95 | &preview); |
96 | |
97 | if (status != MMAL_SUCCESS) |
98 | { |
99 | vcos_log_error("Unable to create preview component" ); |
100 | goto error; |
101 | } |
102 | |
103 | if (!preview->input_num) |
104 | { |
105 | status = MMAL_ENOSYS; |
106 | vcos_log_error("No input ports found on component" ); |
107 | goto error; |
108 | } |
109 | |
110 | preview_port = preview->input[0]; |
111 | |
112 | MMAL_DISPLAYREGION_T param; |
113 | param.hdr.id = MMAL_PARAMETER_DISPLAYREGION; |
114 | param.hdr.size = sizeof(MMAL_DISPLAYREGION_T); |
115 | |
116 | param.set = MMAL_DISPLAY_SET_LAYER; |
117 | param.layer = PREVIEW_LAYER; |
118 | |
119 | param.set |= MMAL_DISPLAY_SET_ALPHA; |
120 | param.alpha = state->opacity; |
121 | |
122 | if (state->wantFullScreenPreview) |
123 | { |
124 | param.set |= MMAL_DISPLAY_SET_FULLSCREEN; |
125 | param.fullscreen = 1; |
126 | } |
127 | else |
128 | { |
129 | param.set |= (MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN); |
130 | param.fullscreen = 0; |
131 | param.dest_rect = state->previewWindow; |
132 | } |
133 | |
134 | if (state->display_num >= 0) |
135 | { |
136 | param.set |= MMAL_DISPLAY_SET_NUM; |
137 | param.display_num = state->display_num; |
138 | } |
139 | |
140 | status = mmal_port_parameter_set(preview_port, ¶m.hdr); |
141 | |
142 | if (status != MMAL_SUCCESS && status != MMAL_ENOSYS) |
143 | { |
144 | vcos_log_error("unable to set preview port parameters (%u)" , status); |
145 | goto error; |
146 | } |
147 | } |
148 | |
149 | /* Enable component */ |
150 | status = mmal_component_enable(preview); |
151 | |
152 | if (status != MMAL_SUCCESS) |
153 | { |
154 | vcos_log_error("Unable to enable preview/null sink component (%u)" , status); |
155 | goto error; |
156 | } |
157 | |
158 | state->preview_component = preview; |
159 | |
160 | return status; |
161 | |
162 | error: |
163 | |
164 | if (preview) |
165 | mmal_component_destroy(preview); |
166 | |
167 | return status; |
168 | } |
169 | |
170 | |
171 | /** |
172 | * Destroy the preview component |
173 | * |
174 | * @param state Pointer to state control struct |
175 | * |
176 | */ |
177 | void raspipreview_destroy(RASPIPREVIEW_PARAMETERS *state) |
178 | { |
179 | if (state->preview_component) |
180 | { |
181 | mmal_component_destroy(state->preview_component); |
182 | state->preview_component = NULL; |
183 | } |
184 | } |
185 | |
186 | /** |
187 | * Assign set of default parameters to the passed in parameter block |
188 | * |
189 | * @param state Pointer to parameter block |
190 | * |
191 | */ |
192 | void raspipreview_set_defaults(RASPIPREVIEW_PARAMETERS *state) |
193 | { |
194 | state->wantPreview = 1; |
195 | state->wantFullScreenPreview = 1; |
196 | state->opacity = 255; |
197 | state->previewWindow.x = 0; |
198 | state->previewWindow.y = 0; |
199 | state->previewWindow.width = 1024; |
200 | state->previewWindow.height = 768; |
201 | state->preview_component = NULL; |
202 | state->display_num = -1; |
203 | } |
204 | |
205 | /** |
206 | * Dump parameters as human readable to stdout |
207 | * |
208 | * @param state Pointer to parameter block |
209 | * |
210 | */ |
211 | void raspipreview_dump_parameters(RASPIPREVIEW_PARAMETERS *state) |
212 | { |
213 | fprintf(stderr, "Preview %s, Full screen %s\n" , state->wantPreview ? "Yes" : "No" , |
214 | state->wantFullScreenPreview ? "Yes" : "No" ); |
215 | |
216 | fprintf(stderr, "Preview window %d,%d,%d,%d\nOpacity %d\n" , state->previewWindow.x, |
217 | state->previewWindow.y, state->previewWindow.width, |
218 | state->previewWindow.height, state->opacity); |
219 | }; |
220 | |
221 | /** |
222 | * Parse a possible command pair - command and parameter |
223 | * @param arg1 Command |
224 | * @param arg2 Parameter (could be NULL) |
225 | * @return How many parameters were used, 0,1,2 |
226 | */ |
227 | int raspipreview_parse_cmdline(RASPIPREVIEW_PARAMETERS *params, const char *arg1, const char *arg2) |
228 | { |
229 | int command_id, used = 0, num_parameters; |
230 | |
231 | if (!arg1) |
232 | return 0; |
233 | |
234 | command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, arg1, &num_parameters); |
235 | |
236 | // If invalid command, or we are missing a parameter, drop out |
237 | if (command_id==-1 || (command_id != -1 && num_parameters > 0 && arg2 == NULL)) |
238 | return 0; |
239 | |
240 | switch (command_id) |
241 | { |
242 | case CommandPreview: // Preview window |
243 | { |
244 | int tmp; |
245 | |
246 | params->wantPreview = 1; |
247 | |
248 | tmp = sscanf(arg2, "%d,%d,%d,%d" , |
249 | ¶ms->previewWindow.x, ¶ms->previewWindow.y, |
250 | ¶ms->previewWindow.width, ¶ms->previewWindow.height); |
251 | |
252 | // Failed to get any window parameters, so revert to full screen |
253 | if (tmp == 0) |
254 | params->wantFullScreenPreview = 1; |
255 | else |
256 | params->wantFullScreenPreview = 0; |
257 | |
258 | used = 2; |
259 | |
260 | break; |
261 | } |
262 | |
263 | case CommandFullScreen: // Want full screen preview mode (overrides display rect) |
264 | params->wantPreview = 1; |
265 | params->wantFullScreenPreview = 1; |
266 | |
267 | used = 1; |
268 | break; |
269 | |
270 | case CommandOpacity: // Define preview window opacity |
271 | if (sscanf(arg2, "%u" , ¶ms->opacity) != 1) |
272 | params->opacity = 255; |
273 | else |
274 | used = 2; |
275 | break; |
276 | |
277 | case CommandDisablePreview: // Turn off preview output |
278 | params->wantPreview = 0; |
279 | used = 1; |
280 | break; |
281 | |
282 | case CommandDisplayNum: |
283 | if (sscanf(arg2, "%d" , ¶ms->display_num) != 1) |
284 | params->display_num = -1; |
285 | else |
286 | used = 2; |
287 | break; |
288 | } |
289 | |
290 | return used; |
291 | } |
292 | |
293 | /** |
294 | * Display help for command line options |
295 | */ |
296 | void raspipreview_display_help() |
297 | { |
298 | fprintf(stdout, "\nPreview parameter commands\n\n" ); |
299 | raspicli_display_help(cmdline_commands, cmdline_commands_size); |
300 | } |
301 | |