nuttx-apps/system/nxcamera/nxcamera_main.c
Peter Bee ce84d5d7cd system/nxcamera: fix sscanf overflow
Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
2023-02-16 19:00:29 +08:00

497 lines
13 KiB
C

/****************************************************************************
* apps/system/nxcamera/nxcamera_main.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/video/video.h>
#include <sys/types.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <system/readline.h>
#include <system/nxcamera.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define NXCAMERA_VER "1.00"
#ifdef CONFIG_NXCAMERA_INCLUDE_HELP
# define NXCAMERA_HELP_TEXT(x) x
#else
# define NXCAMERA_HELP_TEXT(x)
#endif
/****************************************************************************
* Private Type Declarations
****************************************************************************/
typedef CODE int (*nxcamera_func)(FAR struct nxcamera_s *cam, FAR char *arg);
struct nxcamera_cmd_s
{
FAR const char *cmd; /* The command text */
FAR const char *arghelp; /* Text describing the args */
nxcamera_func pfunc; /* Pointer to command handler */
FAR const char *help; /* The help text */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int nxcamera_cmd_quit(FAR struct nxcamera_s *pcam, FAR char *parg);
static int nxcamera_cmd_stream(FAR struct nxcamera_s *pcam, FAR char *parg);
static int nxcamera_cmd_input(FAR struct nxcamera_s *pcam, FAR char *parg);
static int nxcamera_cmd_output(FAR struct nxcamera_s *pcam, FAR char *parg);
static int nxcamera_cmd_stop(FAR struct nxcamera_s *pcam, FAR char *parg);
#ifdef CONFIG_NXCAMERA_INCLUDE_HELP
static int nxcamera_cmd_help(FAR struct nxcamera_s *pcam, FAR char *parg);
#endif
/****************************************************************************
* Private Data
****************************************************************************/
static const struct nxcamera_cmd_s g_nxcamera_cmds[] =
{
{
"input",
"videodev",
nxcamera_cmd_input,
NXCAMERA_HELP_TEXT("Specify a preferred capture device")
},
{
"output",
"fbdev|filename",
nxcamera_cmd_output,
NXCAMERA_HELP_TEXT("Specify a display device or filename")
},
#ifdef CONFIG_NXCAMERA_INCLUDE_HELP
{
"h",
"",
nxcamera_cmd_help,
NXCAMERA_HELP_TEXT("Display help for commands")
},
{
"help",
"",
nxcamera_cmd_help,
NXCAMERA_HELP_TEXT("Display help for commands")
},
#endif
{
"stream",
"width height framerate format",
nxcamera_cmd_stream,
NXCAMERA_HELP_TEXT("Video stream test (format is fourcc)")
},
{
"stop",
"",
nxcamera_cmd_stop,
NXCAMERA_HELP_TEXT("Stop stream")
},
{
"q",
"",
nxcamera_cmd_quit,
NXCAMERA_HELP_TEXT("Exit NxCamera")
},
{
"quit",
"",
nxcamera_cmd_quit,
NXCAMERA_HELP_TEXT("Exit NxCamera")
}
};
static const int g_nxcamera_cmd_count = sizeof(g_nxcamera_cmds) /
sizeof(struct nxcamera_cmd_s);
/****************************************************************************
* Name: nxcamera_cmd_stream
*
* nxcamera_cmd_loop() play and record the raw data file using the nxcamera
* context.
*
****************************************************************************/
static int nxcamera_cmd_stream(FAR struct nxcamera_s *pcam, FAR char *parg)
{
uint16_t width = 0;
uint16_t height = 0;
uint32_t framerate = 0;
uint32_t format = 0;
int ret;
char cc[5] =
{
0
};
sscanf(parg, "%hd %hd %d %4s", &width, &height, &framerate, cc);
format = v4l2_fourcc(cc[0], cc[1], cc[2], cc[3]);
/* Try to stream raw data with settings specified */
ret = nxcamera_stream(pcam, width, height, framerate, format);
/* nxcamera_stream returned values:
*
* OK Stream is being run
* -EBUSY The media device is busy
* -ENOSYS The video format is not unsupported
* -ENODEV No video device suitable to capture media
*/
switch (ret)
{
case OK:
break;
case -ENODEV:
printf("No suitable Video Device found\n");
break;
case -EBUSY:
printf("Video device busy\n");
break;
case -ENOSYS:
printf("Unknown video format\n");
break;
default:
printf("Error stream test: %d\n", ret);
break;
}
return ret;
}
/****************************************************************************
* Name: nxcamera_cmd_stop
*
* nxcamera_cmd_stop() stops stream context.
*
****************************************************************************/
static int nxcamera_cmd_stop(FAR struct nxcamera_s *pcam, FAR char *parg)
{
/* Stop the stream */
return nxcamera_stop(pcam);
}
/****************************************************************************
* Name: nxcamera_cmd_input
*
* nxcamera_cmd_input() sets the preferred capture device for stream.
*
****************************************************************************/
static int nxcamera_cmd_input(FAR struct nxcamera_s *pcam, FAR char *parg)
{
int ret;
char path[PATH_MAX];
/* First try to open the file directly */
ret = nxcamera_setdevice(pcam, parg);
if (ret < 0)
{
/* Append the /dev path and try again */
snprintf(path, sizeof(path), "/dev/%s", parg);
ret = nxcamera_setdevice(pcam, path);
}
/* Test if the device file exists */
if (ret == -ENOENT)
{
/* Device doesn't exit. Report error */
printf("Device %s not found\n", parg);
}
else if (ret == -ENODEV)
{
/* Test if is is an video device */
printf("Device %s is not an video device\n", parg);
}
/* Return error value */
return ret;
}
/****************************************************************************
* Name: nxcamera_cmd_output
*
* nxcamera_cmd_device() sets the output device/file for display/save.
*
****************************************************************************/
static int nxcamera_cmd_output(FAR struct nxcamera_s *pcam, FAR char *parg)
{
int ret;
char path[PATH_MAX];
FAR char *ext;
bool isimage = false;
/* First try to open the device directly */
ret = nxcamera_setfb(pcam, parg);
if (ret < 0)
{
/* Append the /dev path and try again */
snprintf(path, sizeof(path), "/dev/%s", parg);
ret = nxcamera_setfb(pcam, path);
}
/* Device doesn't exist or is not a video device. Treat as file */
if (ret < 0)
{
if (ret == -ENODEV)
{
printf("Device %s is not an video device\n", parg);
return ret;
}
ext = strrchr(parg, '.');
if (ext && (ext != parg))
{
ext++;
isimage = strncmp(ext, "jpg", sizeof("jpg")) == 0 ||
strncmp(ext, "jpeg", sizeof("jpeg")) == 0;
}
ret = nxcamera_setfile(pcam, parg, isimage);
}
if (ret < 0)
{
/* Create file error. Report error */
printf("Error outputting to %s\n", parg);
}
/* Output device or file set successfully */
return ret;
}
/****************************************************************************
* Name: nxcamera_cmd_quit
*
* nxcamera_cmd_quit() terminates the application.
*
****************************************************************************/
static int nxcamera_cmd_quit(FAR struct nxcamera_s *pcam, FAR char *parg)
{
/* Stop the stream if any */
return nxcamera_stop(pcam);
}
/****************************************************************************
* Name: nxcamera_cmd_help
*
* nxcamera_cmd_help() displays the application's help information on
* supported commands and command syntax.
*
****************************************************************************/
#ifdef CONFIG_NXCAMERA_INCLUDE_HELP
static int nxcamera_cmd_help(FAR struct nxcamera_s *pcam, FAR char *parg)
{
int len;
int maxlen = 0;
int x;
int c;
/* Calculate length of longest cmd + arghelp */
for (x = 0; x < g_nxcamera_cmd_count; x++)
{
len = strlen(g_nxcamera_cmds[x].cmd) +
strlen(g_nxcamera_cmds[x].arghelp);
if (len > maxlen)
{
maxlen = len;
}
}
printf("NxCamera commands\n================\n");
for (x = 0; x < g_nxcamera_cmd_count; x++)
{
/* Print the command and it's arguments */
printf(" %s %s", g_nxcamera_cmds[x].cmd, g_nxcamera_cmds[x].arghelp);
/* Calculate number of spaces to print before the help text */
len = maxlen - (strlen(g_nxcamera_cmds[x].cmd) +
strlen(g_nxcamera_cmds[x].arghelp));
for (c = 0; c < len; c++)
{
printf(" ");
}
printf(" : %s\n", g_nxcamera_cmds[x].help);
}
return OK;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nxcamera
*
* nxcamera reads in commands from the console using the readline
* system add-in and impalements a command-line based media loop
* tester that uses the NuttX video system to capture and then display
* or save video from the lower video driver. Commands are provided for
* setting width, height, framerate, pixel format and other video controls,
* as well as for stopping the test.
*
****************************************************************************/
int main(int argc, FAR char *argv[])
{
char buffer[CONFIG_NSH_LINELEN];
int len;
int x;
bool running = true;
FAR char *cmd;
FAR char *arg;
FAR struct nxcamera_s *pcam;
printf("NxCamera version " NXCAMERA_VER "\n");
printf("h for commands, q to exit\n");
#ifndef CONFIG_LIBYUV
printf("Libyuv is not enabled, won't output to RGB framebuffer\n");
#endif
printf("\n");
/* Initialize our NxCamera context */
pcam = nxcamera_create();
if (pcam == NULL)
{
printf("Error: Out of RAM\n");
return -ENOMEM;
}
/* Loop until the user exits */
while (running)
{
/* Print a prompt */
printf("nxcamera> ");
fflush(stdout);
/* Read a line from the terminal */
len = readline(buffer, sizeof(buffer), stdin, stdout);
if (len > 0)
{
buffer[len] = '\0';
if (strncmp(buffer, "!", 1) != 0)
{
/* nxcamera command */
if (buffer[len - 1] == '\n')
{
buffer[len - 1] = '\0';
}
/* Parse the command from the argument */
cmd = strtok_r(buffer, " \n", &arg);
if (cmd == NULL)
{
continue;
}
/* Find the command in our cmd array */
for (x = 0; x < g_nxcamera_cmd_count; x++)
{
if (strcmp(cmd, g_nxcamera_cmds[x].cmd) == 0)
{
/* Command found. Call it's handler if not NULL */
if (g_nxcamera_cmds[x].pfunc != NULL)
{
g_nxcamera_cmds[x].pfunc(pcam, arg);
}
/* Test if it is a quit command */
if (g_nxcamera_cmds[x].pfunc == nxcamera_cmd_quit)
{
running = false;
}
break;
}
}
}
else
{
#ifdef CONFIG_SYSTEM_SYSTEM
/* Transfer nuttx shell */
system(buffer + 1);
#else
printf("%s: unknown nxcamera command\n", buffer);
#endif
}
}
}
/* Release the NxCamera context */
nxcamera_release(pcam);
return OK;
}