Files
BPI-CM9-Linux/aml-comp/hardware/amlogic/arm-isp-6.12/aml_isp5/libaiq/isp5service/handler.c
T
2026-08-24 10:03:24 +08:00

404 lines
9.5 KiB
C

/*
*
* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2020 Amlogic or its affiliates
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2.
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "camera.h"
#include "handler.h"
#include "video.h"
#define IMAGE_DIR "/data/camera"
static int video_mkdir_image(void)
{
int ret = 0;
DIR *dir = NULL;
dir = opendir(IMAGE_DIR);
if (dir != NULL) {
closedir(dir);
return ret;
}
ret = mkdir(IMAGE_DIR, 0777);
if (ret) {
printf("Failed to mkdir %s: %s\n", IMAGE_DIR, strerror(errno));
return ret;
}
return ret;
}
static void video_buff_save(struct video_dev *vdev, struct buffer_t *buff)
{
int fd = -1;
uint32_t i;
uint8_t *data;
uint32_t size;
uint32_t frm_num = 0;
char name[96] = {'\0'};
frm_num = buff->sequence;
sprintf(name, "%s/%s_%s_ca_%d.raw", IMAGE_DIR,
vdev->cam->name, vdev->entity.name, frm_num);
fd = open(name, O_RDWR | O_CREAT, 0666);
if (fd < 0) {
printf("%s:Error open file\n", __func__);
return;
}
for (i = 0 ; i < buff->nplane; i++) {
data = buff->planes[i].data;
size = buff->planes[i].size;
write(fd, data, size);
}
printf("%s: %s save file %s\n", vdev->cam->name, vdev->entity.name, name);
close(fd);
}
static uint64_t video_get_msec_time(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
static void video_get_frame_fps(struct video_dev *vdev, struct buffer_t *buff, int inter)
{
uint32_t fps = 0;
uint32_t frm_num = 0;
static uint64_t start = 0;
static uint64_t end = 0;
frm_num = buff->sequence;
if (frm_num % inter == 1)
start = video_get_msec_time();
if ((frm_num >= inter) && (frm_num % inter == 0)) {
end = video_get_msec_time();
fps = inter * 1000 / (end - start);
printf("%s: %s fps: %u\n", vdev->cam->name, vdev->entity.name, fps);
}
}
static void *stats_buff_handler_thread(void *params)
{
struct buffer_t *sbuf = NULL;
struct buffer_t *pbuf = NULL;
struct video_dev *stats = params;
struct camera_dev *cam = stats->cam;
struct video_dev *para = &cam->param;
while (cam->status == STATUS_ON) {
pbuf = video_get_list_buff(para);
sbuf = video_get_list_buff(stats);
if (!pbuf || !sbuf) {
usleep(5000);
continue;
}
video_delete_list_buff(stats, sbuf);
video_delete_list_buff(para, pbuf);
alg_params_process(sbuf, pbuf);
video_dev_queue_buff(stats, sbuf);
video_dev_queue_buff(para, pbuf);
}
return NULL;
}
static void *video_buff_handler_thread(void *params)
{
struct buffer_t *vbuf = NULL;
struct video_dev *vdev = params;
while (vdev->cam->status == STATUS_ON) {
vbuf = video_get_list_buff(vdev);
if (vbuf == NULL) {
usleep(5000);
continue;
}
video_delete_list_buff(vdev, vbuf);
video_get_frame_fps(vdev, vbuf, 70);
video_dev_queue_buff(vdev, vbuf);
}
return NULL;
}
static int offtile_buff_handler(void *params)
{
struct buffer_t *imp_buff;
struct buffer_t *vc0_buff;
struct buffer_t *vc1_buff;
struct video_dev *imp = params;
struct camera_dev *cam = imp->cam;
struct video_dev *vc0 = &cam->vc0;
struct video_dev *vc1 = &cam->vc1;
imp_buff = video_get_list_buff(imp);
vc0_buff = video_get_list_buff(vc0);
if (cam->isp.img_mode == C4_ISP_IMAGE_HDR)
vc1_buff = video_get_list_buff(vc1);
else
vc1_buff = vc0_buff;
if (!imp_buff || !vc0_buff || !vc1_buff)
return -EINVAL;
video_delete_list_buff(imp, imp_buff);
video_delete_list_buff(vc0, vc0_buff);
if (cam->isp.img_mode == C4_ISP_IMAGE_HDR)
video_delete_list_buff(vc1, vc1_buff);
imp_buff->planes[0].fd = vc0_buff->planes[0].fd;
imp_buff->planes[0].bytesused = vc0_buff->planes[0].size;
imp_buff->planes[1].fd = vc1_buff->planes[0].fd;
imp_buff->planes[1].bytesused = vc1_buff->planes[0].size;
/* Will wait until the ISP processing is completed */
video_dev_queue_buff(imp, imp_buff);
video_dev_queue_buff(vc0, vc0_buff);
if (cam->isp.img_mode == C4_ISP_IMAGE_HDR)
video_dev_queue_buff(vc1, vc1_buff);
return 0;
}
static void offpost_queue_imp_buff(struct video_dev *imp,
struct video_dev *vc,
struct buffer_t *imp_buff,
struct buffer_t *vc_buff)
{
imp_buff->planes[0].fd = vc_buff->planes[0].fd;
imp_buff->planes[0].bytesused = vc_buff->planes[0].size;
imp_buff->planes[1].fd = vc_buff->planes[1].fd;
imp_buff->planes[1].bytesused = vc_buff->planes[1].size;
/* Will wait until the ISP processing is completed */
video_dev_queue_buff(imp, imp_buff);
video_dev_queue_buff(vc, vc_buff);
}
static int offpost_buff_handler(void *params)
{
struct video_dev *imp = params;
struct camera_dev *cam = imp->cam;
struct video_dev *vc0 = &cam->vc0;
struct video_dev *vc1 = &cam->vc1;
struct video_dev *vc2 = &cam->vc2;
struct video_dev *vc3 = &cam->vc3;
struct buffer_t *imp_buff;
struct buffer_t *vc0_buff;
struct buffer_t *vc1_buff;
struct buffer_t *vc2_buff;
struct buffer_t *vc3_buff;
if (cam->isp.img_mode != C4_ISP_IMAGE_SDR)
return -EINVAL;
imp_buff = video_get_list_buff(imp);
vc0_buff = video_get_list_buff(vc0);
vc1_buff = video_get_list_buff(vc1);
vc2_buff = video_get_list_buff(vc2);
vc3_buff = video_get_list_buff(vc3);
if (!imp_buff || (!vc0_buff && !vc1_buff && !vc2_buff && !vc3_buff))
return -EINVAL;
video_delete_list_buff(imp, imp_buff);
if (vc0_buff) {
video_delete_list_buff(vc0, vc0_buff);
offpost_queue_imp_buff(imp, vc0, imp_buff, vc0_buff);
}
if (vc1_buff) {
video_delete_list_buff(vc1, vc1_buff);
offpost_queue_imp_buff(imp, vc1, imp_buff, vc1_buff);
}
if (vc2_buff) {
video_delete_list_buff(vc2, vc2_buff);
offpost_queue_imp_buff(imp, vc2, imp_buff, vc2_buff);
}
if (vc3_buff) {
video_delete_list_buff(vc3, vc3_buff);
offpost_queue_imp_buff(imp, vc3, imp_buff, vc3_buff);
}
return 0;
}
static void *offline_buff_handler_thread(void *params)
{
struct video_dev *imp = params;
struct camera_dev *cam = imp->cam;
int ret;
while (cam->status == STATUS_ON) {
if (cam->isp.work_mode == C4_ISP_OFFTILE_MODE)
ret = offtile_buff_handler(params);
else if (cam->isp.work_mode == C4_ISP_OFFPOST_MODE)
ret = offpost_buff_handler(params);
else {
printf("Invalid offline work mode: %u\n",
cam->isp.work_mode);
break;
}
if (ret) {
usleep(3000);
continue;
}
}
return NULL;
}
static int video_dev_create_thread(struct video_dev *vdev, void *func)
{
int ret;
if (!vdev->used)
return 0;
pthread_mutex_init(&vdev->lock, NULL);
ret = pthread_create(&vdev->tid, NULL, func, (void *)vdev);
if (ret)
printf("Failed to create %s handler thread\n", vdev->entity.name);
return ret;
}
static void video_dev_destroy_thread(struct video_dev *vdev)
{
if (!vdev->used)
return;
pthread_join(vdev->tid, NULL);
}
void video_dev_buff_ready(struct video_dev *vdev, struct buffer_t *buff)
{
pthread_mutex_lock(&vdev->lock);
local_list_add(&vdev->head, &buff->list);
pthread_mutex_unlock(&vdev->lock);
}
struct buffer_t *video_get_list_buff(struct video_dev *vdev)
{
struct buffer_t *buff = NULL;
pthread_mutex_lock(&vdev->lock);
if (local_list_empty(&vdev->head)) {
pthread_mutex_unlock(&vdev->lock);
goto normal_return;
}
buff = local_list_first_entry(&vdev->head, struct buffer_t, list);
pthread_mutex_unlock(&vdev->lock);
normal_return:
return buff;
}
void video_delete_list_buff(struct video_dev *vdev, struct buffer_t *buff)
{
pthread_mutex_lock(&vdev->lock);
local_list_delete(&vdev->head, &buff->list);
pthread_mutex_unlock(&vdev->lock);
}
void videos_dev_thread_create(struct camera_dev *cam)
{
pthread_mutex_init(&cam->param.lock, NULL);
video_dev_create_thread(&cam->stats, stats_buff_handler_thread);
video_dev_create_thread(&cam->imp, offline_buff_handler_thread);
video_dev_create_thread(&cam->raw, video_buff_handler_thread);
video_dev_create_thread(&cam->view, video_buff_handler_thread);
video_dev_create_thread(&cam->cap, video_buff_handler_thread);
video_dev_create_thread(&cam->record, video_buff_handler_thread);
video_dev_create_thread(&cam->disp, video_buff_handler_thread);
if (cam->isp.work_mode != C4_ISP_OFFTILE_MODE &&
cam->isp.work_mode != C4_ISP_OFFPOST_MODE) {
video_dev_create_thread(&cam->vc0, video_buff_handler_thread);
video_dev_create_thread(&cam->vc1, video_buff_handler_thread);
video_dev_create_thread(&cam->vc2, video_buff_handler_thread);
video_dev_create_thread(&cam->vc3, video_buff_handler_thread);
}
video_mkdir_image();
}
void videos_dev_thread_destroy(struct camera_dev *cam)
{
video_dev_destroy_thread(&cam->stats);
video_dev_destroy_thread(&cam->imp);
video_dev_destroy_thread(&cam->raw);
video_dev_destroy_thread(&cam->view);
video_dev_destroy_thread(&cam->cap);
video_dev_destroy_thread(&cam->record);
video_dev_destroy_thread(&cam->disp);
if (cam->isp.work_mode != C4_ISP_OFFTILE_MODE &&
cam->isp.work_mode != C4_ISP_OFFPOST_MODE) {
video_dev_destroy_thread(&cam->vc0);
video_dev_destroy_thread(&cam->vc1);
video_dev_destroy_thread(&cam->vc2);
video_dev_destroy_thread(&cam->vc3);
}
}