ae9f4e2231
Signed-off-by: shizhenghui <shizhenghui@xiaomi.com>
386 lines
9.1 KiB
C
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);
|
|
}
|