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 };
54 
55 static COMMAND_LIST cmdline_commands[] =
56 {
57    { CommandPreview,       "-preview",    "p",  "Preview window settings <'x,y,w,h'>", 1 },
58    { CommandFullScreen,    "-fullscreen", "f",  "Fullscreen preview mode", 0 },
59    { CommandOpacity,       "-opacity",    "op", "Preview window opacity (0-255)", 1},
60    { CommandDisablePreview,"-nopreview",  "n",  "Do not display a preview window", 0},
61 };
62 
63 static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
64 
65 /**
66  * Create the preview component, set up its ports
67  *
68  * @param state Pointer to state control struct
69  *
70  * @return MMAL_SUCCESS if all OK, something else otherwise
71  *
72  */
raspipreview_create(RASPIPREVIEW_PARAMETERS * state)73 MMAL_STATUS_T raspipreview_create(RASPIPREVIEW_PARAMETERS *state)
74 {
75    MMAL_COMPONENT_T *preview = 0;
76    MMAL_PORT_T *preview_port = NULL;
77    MMAL_STATUS_T status;
78 
79    if (!state->wantPreview)
80    {
81       // No preview required, so create a null sink component to take its place
82       status = mmal_component_create("vc.null_sink", &preview);
83 
84       if (status != MMAL_SUCCESS)
85       {
86          vcos_log_error("Unable to create null sink component");
87          goto error;
88       }
89    }
90    else
91    {
92       status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER,
93                                      &preview);
94 
95       if (status != MMAL_SUCCESS)
96       {
97          vcos_log_error("Unable to create preview component");
98          goto error;
99       }
100 
101       if (!preview->input_num)
102       {
103          status = MMAL_ENOSYS;
104          vcos_log_error("No input ports found on component");
105          goto error;
106       }
107 
108       preview_port = preview->input[0];
109 
110       MMAL_DISPLAYREGION_T param;
111       param.hdr.id = MMAL_PARAMETER_DISPLAYREGION;
112       param.hdr.size = sizeof(MMAL_DISPLAYREGION_T);
113 
114       param.set = MMAL_DISPLAY_SET_LAYER;
115       param.layer = PREVIEW_LAYER;
116 
117       param.set |= MMAL_DISPLAY_SET_ALPHA;
118       param.alpha = state->opacity;
119 
120       if (state->wantFullScreenPreview)
121       {
122          param.set |= MMAL_DISPLAY_SET_FULLSCREEN;
123          param.fullscreen = 1;
124       }
125       else
126       {
127          param.set |= (MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN);
128          param.fullscreen = 0;
129          param.dest_rect = state->previewWindow;
130       }
131 
132       status = mmal_port_parameter_set(preview_port, &param.hdr);
133 
134       if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
135       {
136          vcos_log_error("unable to set preview port parameters (%u)", status);
137          goto error;
138       }
139    }
140 
141    /* Enable component */
142    status = mmal_component_enable(preview);
143 
144    if (status != MMAL_SUCCESS)
145    {
146       vcos_log_error("Unable to enable preview/null sink component (%u)", status);
147       goto error;
148    }
149 
150    state->preview_component = preview;
151 
152    return status;
153 
154 error:
155 
156    if (preview)
157       mmal_component_destroy(preview);
158 
159    return status;
160 }
161 
162 /**
163  * Destroy the preview component
164  *
165  * @param state Pointer to state control struct
166  *
167  */
raspipreview_destroy(RASPIPREVIEW_PARAMETERS * state)168 void raspipreview_destroy(RASPIPREVIEW_PARAMETERS *state)
169 {
170    if (state->preview_component)
171    {
172       mmal_component_destroy(state->preview_component);
173       state->preview_component = NULL;
174    }
175 }
176 
177 /**
178  * Assign set of default parameters to the passed in parameter block
179  *
180  * @param state Pointer to parameter block
181  *
182  */
raspipreview_set_defaults(RASPIPREVIEW_PARAMETERS * state)183 void raspipreview_set_defaults(RASPIPREVIEW_PARAMETERS *state)
184 {
185    state->wantPreview = 1;
186    state->wantFullScreenPreview = 1;
187    state->opacity = 255;
188    state->previewWindow.x = 0;
189    state->previewWindow.y = 0;
190    state->previewWindow.width = 1024;
191    state->previewWindow.height = 768;
192    state->preview_component = NULL;
193 }
194 
195 /**
196  * Dump parameters as human readable to stdout
197  *
198  * @param state Pointer to parameter block
199  *
200  */
raspipreview_dump_parameters(RASPIPREVIEW_PARAMETERS * state)201 void raspipreview_dump_parameters(RASPIPREVIEW_PARAMETERS *state)
202 {
203    fprintf(stderr, "Preview %s, Full screen %s\n", state->wantPreview ? "Yes" : "No",
204            state->wantFullScreenPreview ? "Yes" : "No");
205 
206    fprintf(stderr, "Preview window %d,%d,%d,%d\nOpacity %d\n", state->previewWindow.x,
207            state->previewWindow.y, state->previewWindow.width,
208            state->previewWindow.height, state->opacity);
209 };
210 
211 /**
212  * Parse a possible command pair - command and parameter
213  * @param arg1 Command
214  * @param arg2 Parameter (could be NULL)
215  * @return How many parameters were used, 0,1,2
216  */
raspipreview_parse_cmdline(RASPIPREVIEW_PARAMETERS * params,const char * arg1,const char * arg2)217 int raspipreview_parse_cmdline(RASPIPREVIEW_PARAMETERS *params, const char *arg1, const char *arg2)
218 {
219    int command_id, used = 0, num_parameters;
220 
221    if (!arg1)
222       return 0;
223 
224    command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, arg1, &num_parameters);
225 
226    // If invalid command, or we are missing a parameter, drop out
227    if (command_id==-1 || (command_id != -1 && num_parameters > 0 && arg2 == NULL))
228       return 0;
229 
230    switch (command_id)
231    {
232    case CommandPreview: // Preview window
233    {
234       int tmp;
235 
236       params->wantPreview = 1;
237 
238       tmp = sscanf(arg2, "%d,%d,%d,%d",
239                    &params->previewWindow.x, &params->previewWindow.y,
240                    &params->previewWindow.width, &params->previewWindow.height);
241 
242       // Failed to get any window parameters, so revert to full screen
243       if (tmp == 0)
244          params->wantFullScreenPreview = 1;
245       else
246          params->wantFullScreenPreview = 0;
247 
248       used = 2;
249 
250       break;
251    }
252 
253    case CommandFullScreen: // Want full screen preview mode (overrides display rect)
254       params->wantPreview = 1;
255       params->wantFullScreenPreview = 1;
256 
257       used = 1;
258       break;
259 
260    case CommandOpacity: // Define preview window opacity
261       if (sscanf(arg2, "%u", &params->opacity) != 1)
262          params->opacity = 255;
263       else
264          used = 2;
265       break;
266 
267    case CommandDisablePreview: // Turn off preview output
268       params->wantPreview = 0;
269       used = 1;
270       break;
271    }
272 
273    return used;
274 }
275 
276 /**
277  * Display help for command line options
278  */
raspipreview_display_help()279 void raspipreview_display_help()
280 {
281    fprintf(stdout, "\nPreview parameter commands\n\n");
282    raspicli_display_help(cmdline_commands, cmdline_commands_size);
283 }
284