403 lines
9.5 KiB
C
403 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, cam->cam_id);
|
|
|
|
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);
|
|
}
|
|
}
|