From 9312a740043d79d35ee1162ca4a82eeff227e5a3 Mon Sep 17 00:00:00 2001 From: yangsen5 Date: Tue, 5 Mar 2024 20:45:08 +0800 Subject: [PATCH] add m2m decoder/encoder test Signed-off-by: yangsen5 --- system/nxcodec/Kconfig | 30 +++ system/nxcodec/Make.defs | 23 ++ system/nxcodec/Makefile | 36 +++ system/nxcodec/nxcodec.c | 259 +++++++++++++++++++++ system/nxcodec/nxcodec.h | 51 ++++ system/nxcodec/nxcodec_context.c | 383 +++++++++++++++++++++++++++++++ system/nxcodec/nxcodec_context.h | 65 ++++++ system/nxcodec/nxcodec_main.c | 206 +++++++++++++++++ 8 files changed, 1053 insertions(+) create mode 100644 system/nxcodec/Kconfig create mode 100644 system/nxcodec/Make.defs create mode 100644 system/nxcodec/Makefile create mode 100644 system/nxcodec/nxcodec.c create mode 100644 system/nxcodec/nxcodec.h create mode 100644 system/nxcodec/nxcodec_context.c create mode 100644 system/nxcodec/nxcodec_context.h create mode 100644 system/nxcodec/nxcodec_main.c diff --git a/system/nxcodec/Kconfig b/system/nxcodec/Kconfig new file mode 100644 index 000000000..f7850dccf --- /dev/null +++ b/system/nxcodec/Kconfig @@ -0,0 +1,30 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config SYSTEM_NXCODEC + bool "NxCodec test application" + default n + ---help--- + Enable support for the NxCodec test application and optional + command line interface. + +if SYSTEM_NXCODEC + +config SYSTEM_NXCODEC_PROGNAME + string "Program name" + default "nxcodec" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config SYSTEM_NXCODEC_PRIORITY + int "nxcodec task priority" + default 100 + +config SYSTEM_NXCODEC_STACKSIZE + int "nxcodec stack size" + default DEFAULT_TASK_STACKSIZE + +endif # SYSTEM_NXCODEC diff --git a/system/nxcodec/Make.defs b/system/nxcodec/Make.defs new file mode 100644 index 000000000..ba0768549 --- /dev/null +++ b/system/nxcodec/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/system/nxcodec/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_NXCODEC),) +CONFIGURED_APPS += $(APPDIR)/system/nxcodec +endif diff --git a/system/nxcodec/Makefile b/system/nxcodec/Makefile new file mode 100644 index 000000000..220e4f82c --- /dev/null +++ b/system/nxcodec/Makefile @@ -0,0 +1,36 @@ +############################################################################ +# apps/system/nxcodec/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 + +CSRCS = nxcodec.c nxcodec_context.c + +# nxcodec test built-in application info + +PROGNAME = $(CONFIG_SYSTEM_NXCODEC_PROGNAME) +PRIORITY = $(CONFIG_SYSTEM_NXCODEC_PRIORITY) +STACKSIZE = $(CONFIG_SYSTEM_NXCODEC_STACKSIZE) +MODULE = $(CONFIG_SYSTEM_NXCODEC) + +# nxcodec test + +MAINSRC = nxcodec_main.c + +include $(APPDIR)/Application.mk diff --git a/system/nxcodec/nxcodec.c b/system/nxcodec/nxcodec.c new file mode 100644 index 000000000..d6a99e4de --- /dev/null +++ b/system/nxcodec/nxcodec.c @@ -0,0 +1,259 @@ +/**************************************************************************** + * apps/system/nxcodec/nxcodec.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 +#include +#include +#include +#include +#include + +#include "nxcodec.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline bool nxcodec_splane_video(FAR struct v4l2_capability *cap) +{ + return (cap->capabilities & V4L2_CAP_VIDEO_M2M) || + ((cap->capabilities & V4L2_CAP_STREAMING) && + (cap->capabilities & (V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_CAPTURE))); +} + +static inline bool nxcodec_mplane_video(FAR struct v4l2_capability *cap) +{ + return (cap->capabilities & V4L2_CAP_VIDEO_M2M_MPLANE) || + ((cap->capabilities & V4L2_CAP_STREAMING) && + (cap->capabilities & (V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_CAPTURE_MPLANE))); +} + +static int nxcodec_prepare_contexts(FAR nxcodec_t *codec) +{ + struct v4l2_capability cap; + int ret; + + memset(&cap, 0, sizeof(cap)); + ret = ioctl(codec->fd, VIDIOC_QUERYCAP, &cap); + if (ret < 0) + { + return -errno; + } + + if (nxcodec_mplane_video(&cap)) + { + codec->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + codec->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + return 0; + } + + if (nxcodec_splane_video(&cap)) + { + codec->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + codec->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + return 0; + } + + return -EINVAL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int nxcodec_init(FAR nxcodec_t *codec) +{ + int ret; + + codec->fd = open(codec->devname, O_RDWR | O_NONBLOCK); + if (codec->fd < 0) + { + return -errno; + } + + ret = nxcodec_prepare_contexts(codec); + if (ret < 0) + { + goto err0; + } + + ret = nxcodec_context_get_format(&codec->output); + if (ret < 0) + { + printf("v4l2 output format not supported\n"); + goto err0; + } + + ret = nxcodec_context_get_format(&codec->capture); + if (ret < 0) + { + printf("v4l2 capture format not supported\n"); + goto err0; + } + + if (codec->output.fdesc.pixelformat != + codec->output.format.fmt.pix.pixelformat) + { + ret = -EINVAL; + goto err0; + } + + codec->output.format.type = codec->output.type; + + ret = nxcodec_context_set_format(&codec->output); + if (ret < 0) + { + printf("can't set v4l2 output format\n"); + goto err0; + } + + codec->output.fd = open(codec->output.filename, O_RDONLY); + if (codec->output.fd < 0) + { + printf("Failed to open input file %s \n", codec->output.filename); + ret = -errno; + goto err0; + } + + if (codec->capture.fdesc.pixelformat != + codec->capture.format.fmt.pix.pixelformat) + { + ret = -EINVAL; + goto err1; + } + + codec->capture.format.type = codec->capture.type; + + ret = nxcodec_context_set_format(&codec->capture); + if (ret < 0) + { + printf("can't to set v4l2 capture format\n"); + goto err1; + } + + codec->capture.fd = open(codec->capture.filename, + O_WRONLY | O_CREAT, 0644); + if (codec->capture.fd < 0) + { + printf("Failed to open input file %s \n", codec->capture.filename); + ret = -errno; + goto err1; + } + + return 0; + +err1: + close(codec->output.fd); +err0: + close(codec->fd); + return ret; +} + +int nxcodec_start(FAR nxcodec_t *codec) +{ + int ret; + + ret = nxcodec_context_init(&codec->output); + if (ret < 0) + { + printf("can't request output buffers\n"); + return ret; + } + + ret = nxcodec_context_set_status(&codec->output, VIDIOC_STREAMON); + if (ret < 0) + { + printf("set output VIDIOC_STREAMON failed\n"); + goto err0; + } + + ret = nxcodec_context_init(&codec->capture); + if (ret < 0) + { + printf("can't request capture buffers\n"); + goto err0; + } + + ret = nxcodec_context_set_status(&codec->capture, VIDIOC_STREAMON); + if (ret < 0) + { + printf("set capture VIDIOC_STREAMON failed\n"); + goto err1; + } + + ret = nxcodec_context_enqueue_frame(&codec->output); + if (ret < 0 && ret != -EAGAIN) + { + goto err1; + } + + return 0; + +err1: + nxcodec_context_uninit(&codec->capture); +err0: + nxcodec_context_uninit(&codec->output); + return ret; +} + +int nxcodec_stop(FAR nxcodec_t *codec) +{ + int ret; + + if (!codec) + { + return 0; + } + + nxcodec_context_uninit(&codec->output); + + ret = nxcodec_context_set_status(&codec->output, VIDIOC_STREAMOFF); + if (ret < 0) + { + printf("set output VIDIOC_STREAMOFF failed\n"); + return ret; + } + + nxcodec_context_uninit(&codec->capture); + + ret = nxcodec_context_set_status(&codec->capture, VIDIOC_STREAMOFF); + if (ret < 0) + { + printf("set capture VIDIOC_STREAMOFF failed\n"); + return ret; + } + + return 0; +} + +int nxcodec_uninit(FAR nxcodec_t *codec) +{ + close(codec->capture.fd); + close(codec->output.fd); + close(codec->fd); + + return 0; +} diff --git a/system/nxcodec/nxcodec.h b/system/nxcodec/nxcodec.h new file mode 100644 index 000000000..a3e89217b --- /dev/null +++ b/system/nxcodec/nxcodec.h @@ -0,0 +1,51 @@ +/**************************************************************************** + * apps/system/nxcodec/nxcodec.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_SYSTEM_NXCODEC_NXCODEC_H +#define __APPS_SYSTEM_NXCODEC_NXCODEC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "nxcodec_context.h" + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef struct nxcodec_s +{ + char devname[PATH_MAX]; + int fd; + nxcodec_context_t capture; + nxcodec_context_t output; +} nxcodec_t; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +int nxcodec_init(FAR nxcodec_t *codec); +int nxcodec_start(FAR nxcodec_t *codec); +int nxcodec_stop(FAR nxcodec_t *codec); +int nxcodec_uninit(FAR nxcodec_t *codec); + +#endif /* __APPS_SYSTEM_NXCODEC_NXCODEC_H */ diff --git a/system/nxcodec/nxcodec_context.c b/system/nxcodec/nxcodec_context.c new file mode 100644 index 000000000..16514d94a --- /dev/null +++ b/system/nxcodec/nxcodec_context.c @@ -0,0 +1,383 @@ +/**************************************************************************** + * apps/system/nxcodec/nxcodec_context.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 +#include +#include +#include +#include +#include +#include + +#include + +#include "nxcodec_context.h" +#include "nxcodec.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NXCODEC_CONTEXT_BUFNUMBER 3 + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline FAR nxcodec_t * +nxcodec_context_to_nxcodec(FAR nxcodec_context_t *ctx) +{ + return V4L2_TYPE_IS_OUTPUT(ctx->type) ? + container_of(ctx, nxcodec_t, output) : + container_of(ctx, nxcodec_t, capture); +} + +static FAR nxcodec_context_buf_t * +nxcodec_context_dequeue_buf(FAR nxcodec_context_t *ctx) +{ + FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx); + struct v4l2_buffer buf; + int ret; + + memset(&buf, 0, sizeof(buf)); + buf.memory = V4L2_MEMORY_MMAP; + buf.type = ctx->type; + + ret = ioctl(codec->fd, VIDIOC_DQBUF, &buf); + if (ret < 0) + { + printf("type: %d VIDIOC_DQBUF, err: %s\n", ctx->type, strerror(errno)); + return NULL; + } + + ctx->buf[buf.index].free = true; + ctx->buf[buf.index].buf = buf; + + return &ctx->buf[buf.index]; +} + +static FAR nxcodec_context_buf_t * +nxcodec_context_get_freebuf(FAR nxcodec_context_t *ctx) +{ + int i; + + if (V4L2_TYPE_IS_OUTPUT(ctx->type)) + { + while (nxcodec_context_dequeue_buf(ctx)); + } + + for (i = 0; i < ctx->nbuffers; i++) + { + if (ctx->buf[i].free) + { + return &ctx->buf[i]; + } + } + + return NULL; +} + +static int nxcodec_context_write_data(FAR nxcodec_context_t *ctx, + FAR const char *buf, int size) +{ + return write(ctx->fd, buf, size) < 0 ? -errno : 0; +} + +static int nxcodec_context_read_yuv_data(FAR nxcodec_context_t *ctx, + FAR char *buf, + FAR uint32_t *bytesused) +{ + size_t buflen = ctx->format.fmt.pix.width * + ctx->format.fmt.pix.height * 3 / 2; + ssize_t ret; + + ret = read(ctx->fd, buf, buflen); + if (ret <= 0) + { + return -errno; + } + + *bytesused = ret; + return 0; +} + +static int nxcodec_context_read_h264_data(FAR nxcodec_context_t *ctx, + FAR char *buf, + FAR uint32_t *bytesused) +{ + char start_code[4]; + ssize_t ret; + int size; + + memset(start_code, 0, 4); + + ret = read(ctx->fd, buf, 4); + if (ret <= 0) + { + return -errno; + } + + if (buf[0] == 0x00 && buf[1] == 0x00 && + buf[2] == 0x00 && buf[3] == 0x01) + { + size = 4; + while (1) + { + ret = read(ctx->fd, buf + size, 1); + if (ret < 0) + { + return -errno; + } + else if (ret == 0) + { + break; + } + + start_code[0] = start_code[1]; + start_code[1] = start_code[2]; + start_code[2] = start_code[3]; + start_code[3] = *(buf + size); + size++; + + if (start_code[0] == 0x00 && start_code[1] == 0x00 && + start_code[2] == 0x00 && start_code[3] == 0x01) + { + size -= 4; + lseek(ctx->fd, -4, SEEK_CUR); + break; + } + } + } + else + { + return -EINVAL; + } + + *bytesused = size; + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int nxcodec_context_set_status(FAR nxcodec_context_t *ctx, uint32_t cmd) +{ + FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx); + + return ioctl(codec->fd, cmd, &ctx->type) < 0 ? -errno : 0; +} + +int nxcodec_context_enqueue_frame(FAR nxcodec_context_t *ctx) +{ + FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx); + FAR nxcodec_context_buf_t *buf; + int ret; + + buf = nxcodec_context_get_freebuf(ctx); + if (!buf) + { + return -EAGAIN; + } + + if (ctx->format.fmt.pix.pixelformat == V4L2_PIX_FMT_H264) + { + ret = nxcodec_context_read_h264_data(ctx, + buf->addr, + &buf->buf.bytesused); + if (ret < 0) + { + return ret; + } + } + else if (ctx->format.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) + { + ret = nxcodec_context_read_yuv_data(ctx, + buf->addr, + &buf->buf.bytesused); + if (ret < 0) + { + return ret; + } + } + + ret = ioctl(codec->fd, VIDIOC_QBUF, &buf->buf); + if (ret < 0) + { + return -errno; + } + + buf->free = false; + return 0; +} + +int nxcodec_context_dequeue_frame(FAR nxcodec_context_t *ctx) +{ + FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx); + FAR nxcodec_context_buf_t *buf; + int ret; + + buf = nxcodec_context_dequeue_buf(ctx); + if (!buf) + { + return -EAGAIN; + } + + if (buf->buf.length > 0) + { + nxcodec_context_write_data(ctx, buf->addr, buf->buf.bytesused); + } + + ret = ioctl(codec->fd, VIDIOC_QBUF, &buf->buf); + if (ret < 0) + { + return -errno; + } + + buf->free = false; + return 0; +} + +int nxcodec_context_get_format(FAR nxcodec_context_t *ctx) +{ + FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx); + + memset(&ctx->fdesc, 0, sizeof(ctx->fdesc)); + ctx->fdesc.type = ctx->type; + + return ioctl(codec->fd, VIDIOC_ENUM_FMT, &ctx->fdesc) < 0 ? -errno : 0; +} + +int nxcodec_context_set_format(FAR nxcodec_context_t *ctx) +{ + FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx); + + return ioctl(codec->fd, VIDIOC_S_FMT, &ctx->format) < 0 ? -errno : 0; +} + +int nxcodec_context_init(FAR nxcodec_context_t *ctx) +{ + FAR nxcodec_t *codec = nxcodec_context_to_nxcodec(ctx); + struct v4l2_requestbuffers req; + int ret; + int i; + + memset(&req, 0, sizeof(req)); + req.count = NXCODEC_CONTEXT_BUFNUMBER; + req.memory = V4L2_MEMORY_MMAP; + req.type = ctx->type; + + ret = ioctl(codec->fd, VIDIOC_REQBUFS, &req); + if (ret < 0) + { + printf("type: %d VIDIOC_REQBUFS failed: %s\n", + ctx->type, strerror(errno)); + return -errno; + } + + ctx->nbuffers = req.count; + ctx->buf = calloc(ctx->nbuffers, sizeof(nxcodec_context_buf_t)); + if (!ctx->buf) + { + printf("type: %d malloc enomem\n", ctx->type); + return -ENOMEM; + } + + for (i = 0; i < ctx->nbuffers; i++) + { + FAR nxcodec_context_buf_t *buf = &ctx->buf[i]; + + buf->buf.memory = V4L2_MEMORY_MMAP; + buf->buf.type = ctx->type; + buf->buf.index = i; + + ret = ioctl(codec->fd, VIDIOC_QUERYBUF, &buf->buf); + if (ret < 0) + { + goto error; + } + + buf->length = buf->buf.length; + buf->addr = mmap(NULL, + buf->buf.length, + PROT_READ | PROT_WRITE, + MAP_SHARED, + codec->fd, + buf->buf.m.offset); + + if (buf->addr == MAP_FAILED) + { + goto error; + } + + buf->free = true; + + if (V4L2_TYPE_IS_OUTPUT(ctx->type)) + { + continue; + } + + ret = ioctl(codec->fd, VIDIOC_QBUF, &buf->buf); + if (ret < 0) + { + munmap(buf->addr, buf->length); + goto error; + } + + buf->free = false; + } + + return 0; + +error: + free(ctx->buf); + return -errno; +} + +void nxcodec_context_uninit(FAR nxcodec_context_t *ctx) +{ + int i; + + if (!ctx->buf) + { + return; + } + + for (i = 0; i < ctx->nbuffers; i++) + { + FAR nxcodec_context_buf_t *buf = &ctx->buf[i]; + + if (buf->addr && buf->length) + { + if (munmap(buf->addr, buf->length) < 0) + { + printf("type: %d unmap plane (%s))\n", + ctx->type, strerror(errno)); + } + } + } + + free(ctx->buf); +} diff --git a/system/nxcodec/nxcodec_context.h b/system/nxcodec/nxcodec_context.h new file mode 100644 index 000000000..09319e6ff --- /dev/null +++ b/system/nxcodec/nxcodec_context.h @@ -0,0 +1,65 @@ +/**************************************************************************** + * apps/system/nxcodec/nxcodec_context.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 __APP_SYSTEM_NXCODEC_NXCODEC_CONTEXT_H +#define __APP_SYSTEM_NXCODEC_NXCODEC_CONTEXT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef struct nxcodec_context_buf_s +{ + FAR void *addr; + size_t length; + struct v4l2_buffer buf; + bool free; +} nxcodec_context_buf_t; + +typedef struct nxcodec_context_s +{ + char filename[PATH_MAX]; + int fd; + enum v4l2_buf_type type; + struct v4l2_format format; + struct v4l2_fmtdesc fdesc; + FAR nxcodec_context_buf_t *buf; + int nbuffers; +} nxcodec_context_t; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +int nxcodec_context_init(FAR nxcodec_context_t *ctx); +int nxcodec_context_set_status(FAR nxcodec_context_t *ctx, uint32_t cmd); +int nxcodec_context_enqueue_frame(FAR nxcodec_context_t *ctx); +int nxcodec_context_dequeue_frame(FAR nxcodec_context_t *ctx); +int nxcodec_context_get_format(FAR nxcodec_context_t *ctx); +int nxcodec_context_set_format(FAR nxcodec_context_t *ctx); +void nxcodec_context_uninit(FAR nxcodec_context_t *ctx); + +#endif /* __APP_SYSTEM_NXCODEC_NXCODEC_CONTEXT_H */ diff --git a/system/nxcodec/nxcodec_main.c b/system/nxcodec/nxcodec_main.c new file mode 100644 index 000000000..d25f57180 --- /dev/null +++ b/system/nxcodec/nxcodec_main.c @@ -0,0 +1,206 @@ +/**************************************************************************** + * apps/system/nxcodec/nxcodec_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 +#include +#include +#include +#include + +#include "nxcodec.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char g_short_options[] = "d:s:hf:i:o:"; + +static const struct option g_long_options[] = +{ + { "device", required_argument, NULL, 'd' }, + { "size", required_argument, NULL, 's' }, + { "help", no_argument, NULL, 'h' }, + { "format", required_argument, NULL, 'f' }, + { "infile", required_argument, NULL, 'i' }, + { "outfile", required_argument, NULL, 'o' }, + { NULL, 0, NULL, 0 } +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void usage(FAR const char *progname) +{ + printf("Usage: %s [options]\n\n" + "Version 1.3\n" + "Options:\n" + "-d | --device Video device name\n" + "-s | --size Size of stream\n" + "-h | --help Print this message\n" + "-f | --format Format of stream\n" + "-i | --infile Input filename for M2M devices\n" + "-o | --outfile Outputs stream to filename\n\n" + "eg: nxcodec -d /dev/video1 -s 256x144 \ + -f H264 -i input.h264 -f YU12 -o output.yuv\n", + progname); + + exit(EXIT_SUCCESS); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * nxcodec_main + ****************************************************************************/ + +int main(int argc, FAR char **argv) +{ + nxcodec_t codec; + int ret; + char cc[5] = + { + 0 + }; + + memset(&codec, 0, sizeof(codec)); + + while (1) + { + int idx; + int c; + + c = getopt_long(argc, argv, g_short_options, g_long_options, &idx); + if (-1 == c) + { + break; + } + + switch (c) + { + case 0: /* getopt_long() flag */ + break; + + case 'd': + memset(codec.devname, 0, sizeof(codec.devname)); + snprintf(codec.devname, sizeof(codec.devname), "%s", optarg); + break; + + case 's' : + sscanf(optarg, "%"SCNu32"x%"SCNu32"", + &codec.capture.format.fmt.pix.width, + &codec.capture.format.fmt.pix.height); + + codec.output.format.fmt.pix.width = + codec.capture.format.fmt.pix.width; + codec.output.format.fmt.pix.height = + codec.capture.format.fmt.pix.height; + break; + + case 'h': + usage(argv[0]); + + case 'f': + memset(cc, 0, 5); + snprintf(cc, sizeof(cc), "%s", optarg); + break; + + case 'i': + memset(codec.output.filename, 0, sizeof(codec.output.filename)); + snprintf(codec.output.filename, + sizeof(codec.output.filename), "%s", optarg); + + codec.output.format.fmt.pix.pixelformat = + v4l2_fourcc(cc[0], cc[1], cc[2], cc[3]); + break; + + case 'o': + memset(codec.capture.filename, 0, + sizeof(codec.capture.filename)); + snprintf(codec.capture.filename, + sizeof(codec.capture.filename), "%s", optarg); + + codec.capture.format.fmt.pix.pixelformat = + v4l2_fourcc(cc[0], cc[1], cc[2], cc[3]); + break; + + default: + usage(argv[0]); + break; + } + } + + if (argc != optind) + { + printf("Too few input parameter!\n\n"); + usage(argv[0]); + } + + ret = nxcodec_init(&codec); + if (ret < 0) + { + return ret; + } + + ret = nxcodec_start(&codec); + if (ret < 0) + { + goto end0; + } + + while (1) + { + struct pollfd pfd = + { + .events = POLLIN | POLLOUT, + .fd = codec.fd, + }; + + poll(&pfd, 1, -1); + + if (pfd.revents & POLLIN) + { + if (nxcodec_context_dequeue_frame(&codec.capture) < 0) + { + break; + } + } + + if (pfd.revents & POLLOUT) + { + if (nxcodec_context_enqueue_frame(&codec.output) < 0) + { + break; + } + } + } + + nxcodec_stop(&codec); + +end0: + nxcodec_uninit(&codec); + return ret; +}