apps/system: add nxcamera app
Add NxCamera app similar to NxLooper, which can be used to control video capture device. The basic capture n' display function is complete, while file output and camera control features are left TODO. Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
This commit is contained in:
parent
091ff57126
commit
38a190156a
254
include/system/nxcamera.h
Normal file
254
include/system/nxcamera.h
Normal file
@ -0,0 +1,254 @@
|
||||
/****************************************************************************
|
||||
* apps/include/system/nxcamera.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __APPS_INCLUDE_SYSTEM_NXCAMERA_H
|
||||
#define __APPS_INCLUDE_SYSTEM_NXCAMERA_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <nuttx/video/video.h>
|
||||
#include <nuttx/video/fb.h>
|
||||
#include <mqueue.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Standard Video Message Queue message IDs */
|
||||
|
||||
#define VIDEO_MSG_NONE 0
|
||||
#define VIDEO_MSG_STOP 1
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Declarations
|
||||
****************************************************************************/
|
||||
|
||||
/* This structure describes the internal state of the nxcamera */
|
||||
|
||||
struct nxcamera_s
|
||||
{
|
||||
int loopstate; /* Current looper test state */
|
||||
int capture_fd; /* File descriptor of active
|
||||
* capture device */
|
||||
char capturedev[CONFIG_NAME_MAX]; /* Preferred capture device */
|
||||
int display_fd; /* File descriptor of active
|
||||
* display device */
|
||||
char displaydev[CONFIG_NAME_MAX]; /* Display framebuffer device */
|
||||
struct fb_planeinfo_s display_pinfo; /* Display plane info */
|
||||
char videopath[CONFIG_NAME_MAX]; /* Output video file path */
|
||||
char imagepath[CONFIG_NAME_MAX]; /* Output image file path */
|
||||
int crefs; /* Number of references */
|
||||
pthread_mutex_t mutex; /* Thread sync mutex */
|
||||
char mqname[14]; /* Name of display message queue */
|
||||
mqd_t mq; /* Message queue for the
|
||||
* loopthread */
|
||||
pthread_t loop_id; /* Thread ID of the loopthread */
|
||||
v4l2_format_t fmt; /* Buffer format */
|
||||
size_t nbuffers; /* Number of buffers */
|
||||
FAR size_t *buf_sizes; /* Buffer lengths */
|
||||
FAR uint8_t **bufs; /* Buffer pointers */
|
||||
};
|
||||
|
||||
struct video_msg_s
|
||||
{
|
||||
uint16_t msg_id; /* Message ID */
|
||||
union
|
||||
{
|
||||
FAR void *ptr; /* Buffer being dequeued */
|
||||
uint32_t data; /* Message data */
|
||||
} u;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_create
|
||||
*
|
||||
* Allocates and Initializes a nxcamera context that is passed to all
|
||||
* nxcamera routines. The looper MUST be destroyed using the
|
||||
* nxcamera_destroy() routine since the context is reference counted.
|
||||
* The context can be used in a mode where the caller creates the
|
||||
* context, starts a looping, and then forgets about the context
|
||||
* and it will self free. This is because the nxcamera_stream
|
||||
* will also create a reference to the context, so the client calling
|
||||
* nxcamera_destroy() won't actually de-allocate anything. The freeing
|
||||
* will occur after the loopthread has completed.
|
||||
*
|
||||
* Alternately, the caller can create the object and hold on to it, then
|
||||
* the context will persist until the original creator destroys it.
|
||||
*
|
||||
* Input Parameters: None
|
||||
*
|
||||
* Returned Value:
|
||||
* Pointer to created nxcamera context or NULL if error.
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct nxcamera_s *nxcamera_create(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_release
|
||||
*
|
||||
* Reduces the reference count to the looper and if it reaches zero,
|
||||
* frees all memory used by the context.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pcam Pointer to the nxcamera context
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void nxcamera_release(FAR struct nxcamera_s *pcam);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_reference
|
||||
*
|
||||
* Increments the reference count to the looper.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pcam Pointer to the nxcamera context
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void nxcamera_reference(FAR struct nxcamera_s *pcam);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_stream
|
||||
*
|
||||
* nxcamera_stream() tries to capture and then display the raw data using
|
||||
* the Video system. If a capture device is specified, it will try to use
|
||||
* that device.
|
||||
*
|
||||
* Input:
|
||||
* pcam Pointer to the initialized Looper context
|
||||
* width Capture frame width
|
||||
* height Capture frame height
|
||||
* framerate Capture frame rate
|
||||
* format Capture frame pixel format
|
||||
*
|
||||
* Returns:
|
||||
* OK Video is being streamed
|
||||
* -EBUSY Capture device is busy
|
||||
* -ENOSYS No supported video format found
|
||||
* -ENODEV No video capture or framebuffer device suitable
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nxcamera_stream(FAR struct nxcamera_s *pcam,
|
||||
uint16_t width, uint16_t height,
|
||||
uint32_t framerate, uint32_t format);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_stop
|
||||
*
|
||||
* Stops current loopback.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pcam - Pointer to the context to initialize
|
||||
*
|
||||
* Returned Value:
|
||||
* OK if file found, device found, and loopback started.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nxcamera_stop(FAR struct nxcamera_s *pcam);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_setdevice
|
||||
*
|
||||
* Sets the preferred video device to use with the instance of the
|
||||
* nxcamera.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pcam - Pointer to the context to initialize
|
||||
* device - Pointer to pathname of the preferred device
|
||||
*
|
||||
* Returned Value:
|
||||
* OK if context initialized successfully, error code otherwise.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nxcamera_setdevice(FAR struct nxcamera_s *pcam,
|
||||
FAR const char *device);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_setfb
|
||||
*
|
||||
* Sets the output framebuffer device to use with the
|
||||
* provided nxcamera context.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pcam - Pointer to the context to initialize
|
||||
* device - Pointer to pathname of the preferred framebuffer device
|
||||
*
|
||||
* Returned Value:
|
||||
* OK if context initialized successfully, error code otherwise.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nxcamera_setfb(FAR struct nxcamera_s *pcam, FAR const char *device);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_setfile
|
||||
*
|
||||
* Sets the output file path to use with the provided nxcamera context.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pcam - Pointer to the context to initialize
|
||||
* file - Pointer to pathname of the preferred output file
|
||||
* isimage - The path is for image file or not
|
||||
*
|
||||
* Returned Value:
|
||||
* OK if file found, device found, and loopback started.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nxcamera_setfile(FAR struct nxcamera_s *pcam, FAR const char *pfile,
|
||||
bool isimage);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __APPS_INCLUDE_SYSTEM_NXCAMERA_H */
|
41
system/nxcamera/Kconfig
Normal file
41
system/nxcamera/Kconfig
Normal file
@ -0,0 +1,41 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
config SYSTEM_NXCAMERA
|
||||
bool "NxCamera video test application"
|
||||
default n
|
||||
depends on VIDEO
|
||||
---help---
|
||||
Enable support for the NxCam media tester library and optional
|
||||
command line interface.
|
||||
|
||||
if SYSTEM_NXCAMERA
|
||||
|
||||
config NXCAMERA_MAINTHREAD_STACKSIZE
|
||||
int "NxCamera main thread stack size"
|
||||
default DEFAULT_TASK_STACKSIZE
|
||||
---help---
|
||||
Stack size to use with the NxCamera main thread.
|
||||
|
||||
config NXCAMERA_LOOPTHREAD_STACKSIZE
|
||||
int "NxCamera thread stack size"
|
||||
default PTHREAD_STACK_DEFAULT
|
||||
---help---
|
||||
Stack size to use with the NxCamera play thread.
|
||||
|
||||
config NXCAMERA_MSG_PRIO
|
||||
int "NxCamera priority of message queen"
|
||||
default 1
|
||||
---help---
|
||||
Priority of stop message to notice NxCamera thread.
|
||||
|
||||
config NXCAMERA_INCLUDE_HELP
|
||||
bool "Include HELP command and text"
|
||||
default y
|
||||
---help---
|
||||
Compiles in the NxCamera help text to provide online help
|
||||
for available commands with syntax.
|
||||
|
||||
endif
|
23
system/nxcamera/Make.defs
Normal file
23
system/nxcamera/Make.defs
Normal file
@ -0,0 +1,23 @@
|
||||
############################################################################
|
||||
# apps/system/nxcamera/Make.defs
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
ifneq ($(CONFIG_SYSTEM_NXCAMERA),)
|
||||
CONFIGURED_APPS += $(APPDIR)/system/nxcamera
|
||||
endif
|
36
system/nxcamera/Makefile
Normal file
36
system/nxcamera/Makefile
Normal file
@ -0,0 +1,36 @@
|
||||
############################################################################
|
||||
# apps/system/nxcamera/Makefile
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
include $(APPDIR)/Make.defs
|
||||
|
||||
# NxCamera Library
|
||||
|
||||
CSRCS = nxcamera.c
|
||||
|
||||
ifneq ($(CONFIG_SYSTEM_NXCAMERA),)
|
||||
PROGNAME = nxcamera
|
||||
PRIORITY = SCHED_PRIORITY_DEFAULT
|
||||
STACKSIZE = $(CONFIG_NXCAMERA_MAINTHREAD_STACKSIZE)
|
||||
MODULE = $(CONFIG_SYSTEM_NXCAMERA)
|
||||
|
||||
MAINSRC = nxcamera_main.c
|
||||
endif
|
||||
|
||||
include $(APPDIR)/Application.mk
|
849
system/nxcamera/nxcamera.c
Normal file
849
system/nxcamera/nxcamera.c
Normal file
@ -0,0 +1,849 @@
|
||||
/****************************************************************************
|
||||
* apps/system/nxcamera/nxcamera.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 <assert.h>
|
||||
#include <debug.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <nuttx/queue.h>
|
||||
#include <nuttx/video/video.h>
|
||||
#include <nuttx/video/fb.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <system/nxcamera.h>
|
||||
|
||||
#ifdef CONFIG_LIBYUV
|
||||
# include <libyuv.h>
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define NXCAMERA_STATE_IDLE 0
|
||||
#define NXCAMERA_STATE_STREAMING 1
|
||||
#define NXCAMERA_STATE_LOOPING 2
|
||||
#define NXCAMERA_STATE_PAUSED 3
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define convert_frame ConvertToARGB
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static int show_image(FAR struct nxcamera_s *pcam, FAR v4l2_buffer_t *buf)
|
||||
{
|
||||
#ifdef CONFIG_LIBYUV
|
||||
return convert_frame(pcam->bufs[buf->index],
|
||||
pcam->buf_sizes[buf->index],
|
||||
pcam->display_pinfo.fbmem,
|
||||
pcam->display_pinfo.stride,
|
||||
0,
|
||||
0,
|
||||
pcam->fmt.fmt.pix.width,
|
||||
pcam->fmt.fmt.pix.height,
|
||||
pcam->fmt.fmt.pix.width,
|
||||
pcam->fmt.fmt.pix.height,
|
||||
0,
|
||||
pcam->fmt.fmt.pix.pixelformat);
|
||||
#else
|
||||
uint32_t *pbuf = pcam->bufs[buf->index];
|
||||
vinfo("show image from %p: %" PRIx32 " %" PRIx32, pbuf, pbuf[0], pbuf[1]);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_opendevice
|
||||
*
|
||||
* nxcamera_opendevice() tries to open the preferred devices as specified.
|
||||
*
|
||||
* Return:
|
||||
* OK if compatible device opened (searched or preferred)
|
||||
* -ENODEV if no compatible device opened.
|
||||
* -ENOENT if preferred device couldn't be opened.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int nxcamera_opendevice(FAR struct nxcamera_s *pcam)
|
||||
{
|
||||
int errcode;
|
||||
|
||||
if (pcam->capturedev[0] != '\0')
|
||||
{
|
||||
pcam->capture_fd = open(pcam->capturedev, O_RDWR);
|
||||
if (pcam->capture_fd == -1)
|
||||
{
|
||||
errcode = errno;
|
||||
DEBUGASSERT(errcode > 0);
|
||||
|
||||
verr("ERROR: Failed to open pcam->capturedev %d\n", -errcode);
|
||||
return -errcode;
|
||||
}
|
||||
|
||||
if (pcam->displaydev[0] != '\0')
|
||||
{
|
||||
pcam->display_fd = open(pcam->displaydev, O_RDWR);
|
||||
if (pcam->display_fd == -1)
|
||||
{
|
||||
errcode = errno;
|
||||
DEBUGASSERT(errcode > 0);
|
||||
|
||||
close(pcam->capture_fd);
|
||||
pcam->capture_fd = -1;
|
||||
verr("ERROR: Failed to open pcam->displaydev %d\n", -errcode);
|
||||
return -errcode;
|
||||
}
|
||||
|
||||
errcode = ioctl(pcam->display_fd, FBIOGET_PLANEINFO,
|
||||
((uintptr_t)&pcam->display_pinfo));
|
||||
|
||||
if (errcode == OK)
|
||||
{
|
||||
pcam->display_pinfo.fbmem = mmap(NULL,
|
||||
pcam->display_pinfo.fblen,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_FILE,
|
||||
pcam->display_fd,
|
||||
0);
|
||||
}
|
||||
|
||||
if (errcode < 0 || pcam->display_pinfo.fbmem == MAP_FAILED)
|
||||
{
|
||||
errcode = errno;
|
||||
close(pcam->capture_fd);
|
||||
close(pcam->display_fd);
|
||||
verr("ERROR: ioctl(FBIOGET_PLANEINFO) failed: %d\n", -errcode);
|
||||
return -errcode;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: Add file output */
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_loopthread
|
||||
*
|
||||
* This is the thread that streams the video and handles video controls.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void *nxcamera_loopthread(pthread_addr_t pvarg)
|
||||
{
|
||||
FAR struct nxcamera_s *pcam = (FAR struct nxcamera_s *)pvarg;
|
||||
unsigned int prio;
|
||||
ssize_t size;
|
||||
struct video_msg_s msg;
|
||||
bool streaming = true;
|
||||
int i;
|
||||
int ret;
|
||||
struct v4l2_buffer buf;
|
||||
uint32_t type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
|
||||
vinfo("Entry\n");
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
for (i = 0; i < pcam->nbuffers; i++)
|
||||
{
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = i;
|
||||
ret = ioctl(pcam->capture_fd, VIDIOC_QBUF, (uintptr_t)&buf);
|
||||
if (ret < 0)
|
||||
{
|
||||
verr("VIDIOC_QBUF failed: %d\n", ret);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
/* VIDIOC_STREAMON start stream */
|
||||
|
||||
ret = ioctl(pcam->capture_fd, VIDIOC_STREAMON, (uintptr_t)&type);
|
||||
if (ret < 0)
|
||||
{
|
||||
verr("VIDIOC_STREAMON failed: %d\n", ret);
|
||||
goto err_out;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcam->loopstate = NXCAMERA_STATE_STREAMING;
|
||||
}
|
||||
|
||||
/* Loop until we specifically break. streaming == true means that we are
|
||||
* still looping waiting for the stream to complete. All of the data
|
||||
* may have been sent, but the stream is not complete until we get
|
||||
* VIDEO_MSG_STOP message
|
||||
*
|
||||
* The normal protocol for looping errors detected by the video driver
|
||||
* is as follows:
|
||||
*
|
||||
* (1) The video driver will indicated the error by returning a negated
|
||||
* error value when the next buffer is enqueued. The upper level
|
||||
* then knows that this buffer was not queued.
|
||||
* (2) The video driver must return all queued buffers using the
|
||||
* VIDEO_MSG_DEQUEUE message.
|
||||
*/
|
||||
|
||||
while (streaming)
|
||||
{
|
||||
size = mq_receive(pcam->mq, (FAR char *)&msg, sizeof(msg), &prio);
|
||||
|
||||
/* Validate a message was received */
|
||||
|
||||
if (size == sizeof(msg))
|
||||
{
|
||||
/* Perform operation based on message id */
|
||||
|
||||
vinfo("message received size %zd id%d\n", size, msg.msg_id);
|
||||
switch (msg.msg_id)
|
||||
{
|
||||
/* Someone wants to stop the stream. */
|
||||
|
||||
case VIDEO_MSG_STOP:
|
||||
|
||||
/* Send a stop message to the device */
|
||||
|
||||
vinfo("Stopping looping\n");
|
||||
ioctl(pcam->capture_fd, VIDIOC_STREAMOFF, (uintptr_t)&type);
|
||||
streaming = false;
|
||||
goto err_out;
|
||||
|
||||
/* Unknown / unsupported message ID */
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ioctl(pcam->capture_fd, VIDIOC_DQBUF, (uintptr_t)&buf);
|
||||
if (ret < 0)
|
||||
{
|
||||
verr("Fail DQBUF %d\n", errno);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ret = show_image(pcam, &buf);
|
||||
if (ret < 0)
|
||||
{
|
||||
verr("Fail to show image %d\n", -ret);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ret = ioctl(pcam->capture_fd, VIDIOC_QBUF, (uintptr_t)&buf);
|
||||
if (ret < 0)
|
||||
{
|
||||
verr("Fail QBUF %d\n", errno);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release our video buffers and unregister / release the device */
|
||||
|
||||
err_out:
|
||||
vinfo("Clean-up and exit\n");
|
||||
|
||||
/* Cleanup */
|
||||
|
||||
pthread_mutex_lock(&pcam->mutex); /* Lock the mutex */
|
||||
|
||||
close(pcam->display_fd); /* Close the display device */
|
||||
close(pcam->capture_fd); /* Close the capture device */
|
||||
pcam->display_fd = -1; /* Mark display device as closed */
|
||||
pcam->capture_fd = -1; /* Mark capture device as closed */
|
||||
mq_close(pcam->mq); /* Close the message queue */
|
||||
mq_unlink(pcam->mqname); /* Unlink the message queue */
|
||||
pcam->loopstate = NXCAMERA_STATE_IDLE;
|
||||
for (i = 0; i < pcam->nbuffers; i++)
|
||||
{
|
||||
munmap(pcam->bufs[i], pcam->buf_sizes[i]);
|
||||
}
|
||||
|
||||
free(pcam->bufs);
|
||||
free(pcam->buf_sizes);
|
||||
pthread_mutex_unlock(&pcam->mutex); /* Unlock the mutex */
|
||||
|
||||
vinfo("Exit\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_setdevice
|
||||
*
|
||||
* nxcamera_setdevice() sets the preferred video device to use with the
|
||||
* provided nxcamera context.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nxcamera_setdevice(FAR struct nxcamera_s *pcam,
|
||||
FAR const char *device)
|
||||
{
|
||||
int temp_fd;
|
||||
struct v4l2_capability caps;
|
||||
|
||||
DEBUGASSERT(pcam != NULL);
|
||||
DEBUGASSERT(device != NULL);
|
||||
|
||||
/* Try to open the device */
|
||||
|
||||
temp_fd = open(device, O_RDWR);
|
||||
if (temp_fd == -1)
|
||||
{
|
||||
/* Error opening the device */
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Validate it's a video device by issuing an VIDIOC_QUERYCAP ioctl */
|
||||
|
||||
if (ioctl(temp_fd, VIDIOC_QUERYCAP, (uintptr_t)&caps) != OK)
|
||||
{
|
||||
/* Not a video device! */
|
||||
|
||||
close(temp_fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Close the file */
|
||||
|
||||
close(temp_fd);
|
||||
|
||||
/* Save the path of the preferred device */
|
||||
|
||||
if ((caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
strlcpy(pcam->capturedev, device, sizeof(pcam->capturedev));
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_setfb
|
||||
*
|
||||
* nxcamera_setfb() sets the output framebuffer device to use with the
|
||||
* provided nxcamera context.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nxcamera_setfb(FAR struct nxcamera_s *pcam, FAR const char *device)
|
||||
{
|
||||
int temp_fd;
|
||||
struct fb_videoinfo_s vinfo;
|
||||
|
||||
DEBUGASSERT(pcam != NULL);
|
||||
DEBUGASSERT(device != NULL);
|
||||
|
||||
/* Try to open the device */
|
||||
|
||||
temp_fd = open(device, O_RDWR);
|
||||
if (temp_fd == -1)
|
||||
{
|
||||
/* Error opening the device */
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Validate it's a fb device by issuing an FBIOGET_VIDEOINFO ioctl */
|
||||
|
||||
if (ioctl(temp_fd, FBIOGET_VIDEOINFO, (uintptr_t)&vinfo) != OK)
|
||||
{
|
||||
/* Not an Video device! */
|
||||
|
||||
close(temp_fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Close the file */
|
||||
|
||||
close(temp_fd);
|
||||
|
||||
if (vinfo.nplanes == 0)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Save the path of the framebuffer device */
|
||||
|
||||
strlcpy(pcam->displaydev, device, sizeof(pcam->displaydev));
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_setfile
|
||||
*
|
||||
* nxcamera_setfile() sets the output file path to use with the provided
|
||||
* nxcamera context.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nxcamera_setfile(FAR struct nxcamera_s *pcam, FAR const char *pfile,
|
||||
bool isimage)
|
||||
{
|
||||
int temp_fd;
|
||||
|
||||
DEBUGASSERT(pcam != NULL);
|
||||
DEBUGASSERT(pfile != NULL);
|
||||
|
||||
/* Try to open the file */
|
||||
|
||||
temp_fd = open(pfile, O_CREAT | O_RDWR);
|
||||
if (temp_fd == -1)
|
||||
{
|
||||
/* Error opening the file */
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Close the file */
|
||||
|
||||
close(temp_fd);
|
||||
|
||||
/* Save the path of the output file */
|
||||
|
||||
if (isimage)
|
||||
{
|
||||
strlcpy(pcam->imagepath, pfile, sizeof(pcam->imagepath));
|
||||
}
|
||||
else
|
||||
{
|
||||
strlcpy(pcam->videopath, pfile, sizeof(pcam->videopath));
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_stop
|
||||
*
|
||||
* nxcamera_stop() stops the current playback to loop and closes the
|
||||
* file and the associated device.
|
||||
*
|
||||
* Input:
|
||||
* pcam Pointer to the initialized looper context
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nxcamera_stop(FAR struct nxcamera_s *pcam)
|
||||
{
|
||||
struct video_msg_s term_msg;
|
||||
FAR void *value;
|
||||
|
||||
DEBUGASSERT(pcam != NULL);
|
||||
|
||||
/* Validate we are not in IDLE state */
|
||||
|
||||
pthread_mutex_lock(&pcam->mutex); /* Lock the mutex */
|
||||
if (pcam->loopstate == NXCAMERA_STATE_IDLE)
|
||||
{
|
||||
pthread_mutex_unlock(&pcam->mutex); /* Unlock the mutex */
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Notify the stream thread that it needs to cancel the stream */
|
||||
|
||||
term_msg.msg_id = VIDEO_MSG_STOP;
|
||||
term_msg.u.data = 0;
|
||||
mq_send(pcam->mq, (FAR const char *)&term_msg, sizeof(term_msg),
|
||||
CONFIG_NXCAMERA_MSG_PRIO);
|
||||
|
||||
pthread_mutex_unlock(&pcam->mutex);
|
||||
|
||||
/* Join the thread. The thread will do all the cleanup. */
|
||||
|
||||
pthread_join(pcam->loop_id, &value);
|
||||
pcam->loop_id = 0;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_stream
|
||||
*
|
||||
* nxcamera_stream() tries to capture and then display the raw data using
|
||||
* the Video system. If a capture device is specified, it will try to use
|
||||
* that device.
|
||||
*
|
||||
* Input:
|
||||
* pcam Pointer to the initialized Looper context
|
||||
* width Capture frame width
|
||||
* height Capture frame height
|
||||
* framerate Capture frame rate
|
||||
* format Capture frame pixel format
|
||||
*
|
||||
* Returns:
|
||||
* OK Video is being looped
|
||||
* -EBUSY Capture device is busy
|
||||
* -ENOSYS No supported video format found
|
||||
* -ENODEV No video capture or framebuffer device suitable
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int nxcamera_stream(FAR struct nxcamera_s *pcam,
|
||||
uint16_t width, uint16_t height,
|
||||
uint32_t framerate, uint32_t format)
|
||||
{
|
||||
struct mq_attr attr;
|
||||
struct sched_param sparam;
|
||||
pthread_attr_t tattr;
|
||||
FAR void *value;
|
||||
int ret;
|
||||
int i;
|
||||
struct v4l2_buffer buf;
|
||||
struct v4l2_requestbuffers req;
|
||||
struct v4l2_streamparm parm;
|
||||
|
||||
DEBUGASSERT(pcam != NULL);
|
||||
|
||||
pthread_mutex_lock(&pcam->mutex); /* Lock the mutex */
|
||||
if (pcam->loopstate != NXCAMERA_STATE_IDLE)
|
||||
{
|
||||
pthread_mutex_unlock(&pcam->mutex); /* Unlock the mutex */
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&pcam->mutex); /* Unlock the mutex */
|
||||
|
||||
vinfo("==============================\n");
|
||||
vinfo("streaming video\n");
|
||||
vinfo("==============================\n");
|
||||
|
||||
/* Try to open the device */
|
||||
|
||||
ret = nxcamera_opendevice(pcam);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Error opening the device */
|
||||
|
||||
verr("ERROR: nxcamera_opendevice failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* VIDIOC_S_FMT set format */
|
||||
|
||||
pcam->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
pcam->fmt.fmt.pix.width = width;
|
||||
pcam->fmt.fmt.pix.height = height;
|
||||
pcam->fmt.fmt.pix.field = V4L2_FIELD_ANY;
|
||||
pcam->fmt.fmt.pix.pixelformat = format;
|
||||
|
||||
ret = ioctl(pcam->capture_fd, VIDIOC_S_FMT, (uintptr_t)&pcam->fmt);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = -errno;
|
||||
verr("VIDIOC_S_FMT failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
memset(&parm, 0, sizeof(parm));
|
||||
parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
parm.parm.capture.timeperframe.denominator = framerate;
|
||||
parm.parm.capture.timeperframe.numerator = 1;
|
||||
ret = ioctl(pcam->capture_fd, VIDIOC_S_PARM, (uintptr_t)&parm);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = -errno;
|
||||
verr("VIDIOC_S_PARM failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* VIDIOC_REQBUFS initiate user pointer I/O */
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
req.memory = V4L2_MEMORY_MMAP;
|
||||
req.count = CONFIG_VIDEO_REQBUFS_COUNT_MAX;
|
||||
|
||||
ret = ioctl(pcam->capture_fd, VIDIOC_REQBUFS, (uintptr_t)&req);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = -errno;
|
||||
verr("VIDIOC_REQBUFS failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (req.count < 2)
|
||||
{
|
||||
verr("VIDIOC_REQBUFS failed: not enough buffers\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pcam->nbuffers = req.count;
|
||||
pcam->bufs = calloc(req.count, sizeof(*pcam->bufs));
|
||||
pcam->buf_sizes = calloc(req.count, sizeof(*pcam->buf_sizes));
|
||||
if (pcam->bufs == NULL || pcam->buf_sizes == NULL)
|
||||
{
|
||||
verr("Cannot allocate buffer pointers\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* VIDIOC_QBUF enqueue buffer */
|
||||
|
||||
for (i = 0; i < req.count; i++)
|
||||
{
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.type = req.type;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = i;
|
||||
ret = ioctl(pcam->capture_fd, VIDIOC_QUERYBUF, (uintptr_t)&buf);
|
||||
if (ret < 0)
|
||||
{
|
||||
ret = -errno;
|
||||
verr("VIDIOC_QUERYBUF failed: %d\n", ret);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
pcam->bufs[i] = mmap(NULL, buf.length,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
pcam->capture_fd, buf.m.offset);
|
||||
if (pcam->bufs[i] == MAP_FAILED)
|
||||
{
|
||||
ret = -errno;
|
||||
verr("MMAP failed\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
pcam->buf_sizes[i] = buf.length;
|
||||
}
|
||||
|
||||
/* Create a message queue for the loopthread */
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.mq_maxmsg = 8;
|
||||
attr.mq_msgsize = sizeof(struct video_msg_s);
|
||||
|
||||
snprintf(pcam->mqname, sizeof(pcam->mqname), "/tmp/%lx",
|
||||
(unsigned long)((uintptr_t)pcam) & 0xffffffff);
|
||||
|
||||
pcam->mq = mq_open(pcam->mqname, O_RDWR | O_CREAT | O_NONBLOCK, 0644,
|
||||
&attr);
|
||||
if (pcam->mq == (mqd_t)-1)
|
||||
{
|
||||
/* Unable to open message queue! */
|
||||
|
||||
ret = -errno;
|
||||
verr("ERROR: mq_open failed: %d\n", ret);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Check if there was a previous thread and join it if there was
|
||||
* to perform clean-up.
|
||||
*/
|
||||
|
||||
if (pcam->loop_id != 0)
|
||||
{
|
||||
pthread_join(pcam->loop_id, &value);
|
||||
}
|
||||
|
||||
pthread_attr_init(&tattr);
|
||||
sparam.sched_priority = sched_get_priority_max(SCHED_FIFO) - 9;
|
||||
pthread_attr_setschedparam(&tattr, &sparam);
|
||||
pthread_attr_setstacksize(&tattr, CONFIG_NXCAMERA_LOOPTHREAD_STACKSIZE);
|
||||
|
||||
/* Add a reference count to the looper for the thread and start the
|
||||
* thread. We increment for the thread to avoid thread start-up
|
||||
* race conditions.
|
||||
*/
|
||||
|
||||
nxcamera_reference(pcam);
|
||||
ret = pthread_create(&pcam->loop_id, &tattr, nxcamera_loopthread,
|
||||
(pthread_addr_t)pcam);
|
||||
pthread_attr_destroy(&tattr);
|
||||
if (ret != OK)
|
||||
{
|
||||
ret = -ret;
|
||||
verr("ERROR: Failed to create loopthread: %d\n", ret);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Name the thread */
|
||||
|
||||
pthread_setname_np(pcam->loop_id, "nxcameraloop");
|
||||
return OK;
|
||||
|
||||
err_out:
|
||||
if (pcam->bufs)
|
||||
{
|
||||
for (i = 0; i < pcam->nbuffers; i++)
|
||||
{
|
||||
if (pcam->bufs[i] != NULL && pcam->bufs[i] != MAP_FAILED)
|
||||
{
|
||||
munmap(pcam->bufs[i], pcam->buf_sizes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(pcam->bufs);
|
||||
}
|
||||
|
||||
if (pcam->buf_sizes)
|
||||
{
|
||||
free(pcam->buf_sizes);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_create
|
||||
*
|
||||
* nxcamera_create() allocates and initializes a nxcamera context for
|
||||
* use by further nxcamera operations. This routine must be called before
|
||||
* to perform the create for proper reference counting.
|
||||
*
|
||||
* Input Parameters: None
|
||||
*
|
||||
* Returned values:
|
||||
* Pointer to the created context or NULL if there was an error.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct nxcamera_s *nxcamera_create(void)
|
||||
{
|
||||
FAR struct nxcamera_s *pcam;
|
||||
int err;
|
||||
|
||||
/* Allocate the memory */
|
||||
|
||||
pcam = (FAR struct nxcamera_s *)calloc(1, sizeof(struct nxcamera_s));
|
||||
if (pcam == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize the context data */
|
||||
|
||||
pcam->loopstate = NXCAMERA_STATE_IDLE;
|
||||
pcam->display_fd = -1;
|
||||
pcam->capture_fd = -1;
|
||||
err = pthread_mutex_init(&pcam->mutex, NULL);
|
||||
if (err)
|
||||
{
|
||||
verr("ERROR: pthread_mutex_init failed: %d\n", err);
|
||||
free(pcam);
|
||||
pcam = NULL;
|
||||
}
|
||||
|
||||
return pcam;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_release
|
||||
*
|
||||
* nxcamera_release() reduces the reference count by one and if it
|
||||
* reaches zero, frees the context.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pcam Pointer to the NxCamera context
|
||||
*
|
||||
* Returned values: None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void nxcamera_release(FAR struct nxcamera_s *pcam)
|
||||
{
|
||||
FAR void *value;
|
||||
int refcount;
|
||||
|
||||
/* Lock the mutex */
|
||||
|
||||
pthread_mutex_lock(&pcam->mutex);
|
||||
|
||||
/* Check if there was a previous thread and join it if there was */
|
||||
|
||||
if (pcam->loop_id != 0)
|
||||
{
|
||||
pthread_mutex_unlock(&pcam->mutex);
|
||||
pthread_join(pcam->loop_id, &value);
|
||||
pcam->loop_id = 0;
|
||||
|
||||
pthread_mutex_lock(&pcam->mutex);
|
||||
}
|
||||
|
||||
/* Reduce the reference count */
|
||||
|
||||
refcount = pcam->crefs--;
|
||||
pthread_mutex_unlock(&pcam->mutex);
|
||||
|
||||
/* If the ref count *was* one, then free the context */
|
||||
|
||||
if (refcount == 1)
|
||||
{
|
||||
pthread_mutex_destroy(&pcam->mutex);
|
||||
free(pcam);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxcamera_reference
|
||||
*
|
||||
* nxcamera_reference() increments the reference count by one.
|
||||
*
|
||||
* Input Parameters:
|
||||
* pcam Pointer to the NxCamera context
|
||||
*
|
||||
* Returned values: None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void nxcamera_reference(FAR struct nxcamera_s *pcam)
|
||||
{
|
||||
/* Lock the mutex */
|
||||
|
||||
pthread_mutex_lock(&pcam->mutex);
|
||||
|
||||
/* Increment the reference count */
|
||||
|
||||
pcam->crefs++;
|
||||
pthread_mutex_unlock(&pcam->mutex);
|
||||
}
|
496
system/nxcamera/nxcamera_main.c
Normal file
496
system/nxcamera/nxcamera_main.c
Normal file
@ -0,0 +1,496 @@
|
||||
/****************************************************************************
|
||||
* 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[4] =
|
||||
{
|
||||
0
|
||||
};
|
||||
|
||||
sscanf(parg, "%hd %hd %d %s", &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;
|
||||
|
||||
/* 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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user