nuttx-apps/system/nxcodec/nxcodec_context.c
shizhenghui ae9f4e2231 nxcodec: update log information
Signed-off-by: shizhenghui <shizhenghui@xiaomi.com>
2024-07-09 16:32:21 +08:00

386 lines
9.1 KiB
C

/****************************************************************************
* 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 <sys/ioctl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <nuttx/nuttx.h>
#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("%s: VIDIOC_DQBUF - %s\n",
V4L2_TYPE_IS_OUTPUT(ctx->type) ? "output" : "capture",
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);
}