1/*
2Copyright (c) 2013, Broadcom Europe Ltd
3Copyright (c) 2013, James Hughes
4All rights reserved.
5
6Redistribution and use in source and binary forms, with or without
7modification, 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
17THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
21DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24ON 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
26SOFTWARE, 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
47enum
48{
49 CommandPreview,
50 CommandFullScreen,
51 CommandOpacity,
52 CommandDisablePreview,
53 CommandDisplayNum,
54};
55
56static 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
65static 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 */
75MMAL_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, &param.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
162error:
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 */
177void 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 */
192void 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 */
211void 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 */
227int 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 &params->previewWindow.x, &params->previewWindow.y,
250 &params->previewWindow.width, &params->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", &params->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", &params->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 */
296void raspipreview_display_help()
297{
298 fprintf(stdout, "\nPreview parameter commands\n\n");
299 raspicli_display_help(cmdline_commands, cmdline_commands_size);
300}
301