417 lines
14 KiB
C
417 lines
14 KiB
C
#include "basic_include.h"
|
|
#include "lib/multimedia/msi.h"
|
|
|
|
#include "dev/gen/hggen420.h"
|
|
#include "jpg_concat_msi.h"
|
|
#include "lib/heap/av_heap.h"
|
|
#include "lib/heap/av_psram_heap.h"
|
|
#include "lib/video/dvp/jpeg/jpg.h"
|
|
#include "lib/video/gen/gen420_dev.h"
|
|
#include "stream_define.h"
|
|
|
|
#include "app/video_app/gen420_hardware_msi.h"
|
|
#include "lib/video/dvp/jpeg/jpg_common.h"
|
|
#include "gen420_hardware_msi.h"
|
|
#include "user_work/user_work.h"
|
|
#include "video_msi.h"
|
|
/****************************************************************************************************
|
|
* 该文件主要是利用jpg1通过gen420重新编码jpg
|
|
* 主要最终调用以下函数去触发gen420:
|
|
register_gen420_queue
|
|
wake_up_gen420_queue
|
|
unregister_gen420_queue
|
|
****************************************************************************************************/
|
|
// data申请空间函数
|
|
#define STREAM_MALLOC av_psram_malloc
|
|
#define STREAM_FREE av_psram_free
|
|
#define STREAM_ZALLOC av_psram_zalloc
|
|
|
|
// 结构体申请空间函数
|
|
#define STREAM_LIBC_MALLOC av_malloc
|
|
#define STREAM_LIBC_FREE av_free
|
|
#define STREAM_LIBC_ZALLOC av_zalloc
|
|
|
|
#define MAX_GEN420_RX 8
|
|
|
|
#ifdef JPG_NODE_COUNT
|
|
#define GEN420_JPG_COUNT JPG_NODE_COUNT
|
|
#else
|
|
#define GEN420_JPG_COUNT 10
|
|
#endif
|
|
struct gen420_msi_s
|
|
{
|
|
struct os_work work;
|
|
struct msi *msi;
|
|
struct msi *register_jpg_msi; // 注册的jpg的msi,因为gen420需要与jpg或者其他硬件联动
|
|
struct framebuff *fb;
|
|
gen420_filter_fn fn;
|
|
uint32_t magic;
|
|
uint8_t hardware_ready;
|
|
uint16_t *filter_type;
|
|
uint8_t force_type;
|
|
uint16_t last_w, last_h;
|
|
uint8_t src_from;
|
|
uint8_t which_jpg;
|
|
uint8_t lock_value;
|
|
uint8_t queue_value;
|
|
uint8_t output_en;
|
|
uint8_t recv_type;
|
|
uint8_t wait_close_jpg;
|
|
uint8_t stop;
|
|
};
|
|
|
|
static int32_t gen420_kick(struct gen420_msg_s *msg)
|
|
{
|
|
int32_t ret = RET_OK;
|
|
struct gen420_msi_s *gen420 = (struct gen420_msi_s *) msg->fn_data;
|
|
// 配置一下jpg的类型
|
|
if (gen420->register_jpg_msi)
|
|
{
|
|
msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_SET_DATATAG, gen420->fb->datatag, 0);
|
|
msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_SET_GEN420_TYPE, gen420->force_type ? gen420->force_type : gen420->fb->stype);
|
|
}
|
|
// 关闭jpg
|
|
// msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_START, 0);
|
|
msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_NODE_COUNT, GEN420_JPG_COUNT);
|
|
msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_SET_TIME, gen420->fb->time);
|
|
// 修改jpg参数
|
|
msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_MSG, gen420->last_w << 16 | gen420->last_h);
|
|
// 修改数据源头
|
|
msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_FROM, GEN420_DATA);
|
|
// 重新启动mjpg
|
|
ret = msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_START, 1);
|
|
return ret;
|
|
}
|
|
|
|
static int32_t gen420_free(struct gen420_msg_s *msg)
|
|
{
|
|
struct gen420_msi_s *gen420 = (struct gen420_msi_s *) msg->fn_data;
|
|
unregister_gen420_queue(gen420->queue_value);
|
|
msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_START, 0);
|
|
// 移除
|
|
msi_delete_fb(NULL, gen420->fb);
|
|
gen420->fb = NULL;
|
|
jpg_mutex_unlock(gen420->which_jpg, gen420->lock_value);
|
|
gen420->hardware_ready = 1;
|
|
// 唤醒workqueue的任务
|
|
_os_printf("]");
|
|
os_run_work(&gen420->work);
|
|
return 0;
|
|
}
|
|
|
|
static int32_t gen420_err_free(struct gen420_msi_s *gen420)
|
|
{
|
|
// 移除
|
|
msi_delete_fb(NULL, gen420->fb);
|
|
gen420->fb = NULL;
|
|
jpg_mutex_unlock(gen420->which_jpg, gen420->lock_value);
|
|
gen420->hardware_ready = 1;
|
|
os_run_work(&gen420->work);
|
|
return 0;
|
|
}
|
|
|
|
static int32_t gen420_run(void *fn_data, struct framebuff *fb, uint16_t w, uint16_t h)
|
|
{
|
|
struct gen420_msi_s *gen420 = (struct gen420_msi_s *) fn_data;
|
|
// msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_START, 0);
|
|
int ret = register_gen420_queue(gen420->queue_value, w, h, gen420_kick, gen420_free, (uint32) fn_data);
|
|
if (ret == 0)
|
|
{
|
|
wake_up_gen420_queue(gen420->queue_value, fb->data);
|
|
}
|
|
else
|
|
{
|
|
gen420_err_free(gen420);
|
|
os_printf(KERN_ERR "gen420_run err:%d\n", ret);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int32 gen420_jpg_work(struct os_work *work)
|
|
{
|
|
uint32_t delay_time = 0;
|
|
struct gen420_msi_s *gen420 = (struct gen420_msi_s *) work;
|
|
uint8_t last_lock_value;
|
|
int32_t ret;
|
|
|
|
// 如果gen420没有启动,那么一定可以启动mjpg或者gen420
|
|
if (gen420->hardware_ready)
|
|
{
|
|
// 尝试看看是否有新的数据需要编码
|
|
if (!gen420->fb)
|
|
{
|
|
gen420->fb = msi_get_fb(gen420->msi, 0);
|
|
if (!gen420->output_en && gen420->fb)
|
|
{
|
|
uint32_t send_count = msi_output_fb(gen420->msi, NULL);
|
|
// 有下一级的流需要接收,那么就传递下去,如果没有,则移除,不需要做后面的动作
|
|
if (!send_count)
|
|
{
|
|
msi_delete_fb(NULL, gen420->fb);
|
|
gen420->fb = NULL;
|
|
if (gen420->stop)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gen420->output_en = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 有新的数据需要编码,则尝试去编码
|
|
if (gen420->fb)
|
|
{
|
|
gen420->wait_close_jpg = 0;
|
|
|
|
// 去获取jpg1的锁
|
|
ret = jpg_mutex_lock(gen420->which_jpg, gen420->lock_value, &last_lock_value);
|
|
// 获取成功,则去编码
|
|
if (ret == 0)
|
|
{
|
|
// os_printf("lock jpg:%d\n",gen420->which_jpg);
|
|
// 获取成功后,初始化mjpg1相关硬件
|
|
if (!gen420->register_jpg_msi)
|
|
{
|
|
gen420->register_jpg_msi = jpg_concat_msi_init_start(gen420->which_jpg, 320, 180, NULL, gen420->src_from, 0);
|
|
if (gen420->register_jpg_msi)
|
|
{
|
|
// 主动停止一下
|
|
msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_START, 0);
|
|
msi_add_output(gen420->register_jpg_msi, NULL, gen420->msi->name);
|
|
}
|
|
}
|
|
|
|
if (gen420->register_jpg_msi)
|
|
{
|
|
// 使用不一致,就先停再启动
|
|
if (last_lock_value != gen420->lock_value)
|
|
{
|
|
msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_START, 0);
|
|
}
|
|
msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_OPEN, GEN420_DATA);
|
|
}
|
|
// 异常,不应该出现,除非其他地方打开了占用该jpg需要检查,应该应用去规避
|
|
else
|
|
{
|
|
jpg_mutex_unlock_check(gen420->which_jpg, gen420->lock_value);
|
|
os_printf("gen420->register_jpg_msi init err\r\n");
|
|
delay_time = 1;
|
|
goto gen420_jpg_work_end;
|
|
}
|
|
struct yuv_arg_s *yuv_msg;
|
|
yuv_msg = (struct yuv_arg_s *) gen420->fb->priv;
|
|
if (yuv_msg)
|
|
{
|
|
uint32_t p_w, p_h;
|
|
p_w = yuv_msg->out_w;
|
|
p_h = yuv_msg->out_h;
|
|
gen420->last_w = p_w;
|
|
gen420->last_h = p_h;
|
|
gen420->hardware_ready = 0;
|
|
gen420->stop = 0;
|
|
gen420_run(gen420, gen420->fb, p_w, p_h);
|
|
}
|
|
// 不应该进入这里,可能fb给错了,下一次移除
|
|
else
|
|
{
|
|
// 移除
|
|
msi_delete_fb(NULL, gen420->fb);
|
|
gen420->fb = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delay_time = 1;
|
|
goto gen420_jpg_work_end;
|
|
}
|
|
}
|
|
// 没有找到等到新的yuv数据,那么就等100ms去检查是否需要关闭mjpeg
|
|
else
|
|
{
|
|
if (!gen420->wait_close_jpg)
|
|
{
|
|
gen420->wait_close_jpg = 1;
|
|
delay_time = 100;
|
|
}
|
|
else
|
|
{
|
|
ret = jpg_mutex_lock(gen420->which_jpg, gen420->lock_value, &last_lock_value);
|
|
if (ret == 0)
|
|
{
|
|
if (gen420->lock_value == last_lock_value)
|
|
{
|
|
if (gen420->register_jpg_msi)
|
|
{
|
|
gen420->stop = 1;
|
|
msi_do_cmd(gen420->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_START, 0);
|
|
}
|
|
}
|
|
jpg_mutex_unlock_check(gen420->which_jpg, gen420->lock_value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delay_time = 1;
|
|
}
|
|
|
|
gen420_jpg_work_end:
|
|
if (delay_time)
|
|
{
|
|
os_run_work_delay(work, delay_time);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int32_t gen420_msi_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
|
|
{
|
|
int32_t ret = RET_OK;
|
|
struct gen420_msi_s *gen420 = (struct gen420_msi_s *) msi->priv;
|
|
switch (cmd_id)
|
|
{
|
|
case MSI_CMD_POST_DESTROY:
|
|
{
|
|
os_work_cancle2(&gen420->work, 1);
|
|
STREAM_LIBC_FREE(gen420);
|
|
}
|
|
break;
|
|
case MSI_CMD_PRE_DESTROY:
|
|
{
|
|
os_work_cancle2(&gen420->work, 1);
|
|
if (gen420->register_jpg_msi)
|
|
{
|
|
msi_destroy(gen420->register_jpg_msi);
|
|
gen420->register_jpg_msi = NULL;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MSI_CMD_JPG_RECODE:
|
|
{
|
|
uint32_t cmd_self = (uint32_t) param1;
|
|
uint32_t arg = param2;
|
|
switch (cmd_self)
|
|
{
|
|
// 需要注册jpg,中断可能需要用到
|
|
case MSI_JPG_RECODE_MAGIC:
|
|
{
|
|
gen420->magic = arg;
|
|
}
|
|
break;
|
|
case MSI_JPG_RECODE_FORCE_TYPE:
|
|
{
|
|
gen420->force_type = (uint16_t) arg;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MSI_CMD_TRANS_FB:
|
|
{
|
|
struct framebuff *fb = (struct framebuff *) param1;
|
|
// 判断是否要转发
|
|
if (gen420->fn && gen420->fn((void *) fb, gen420->recv_type) == 0)
|
|
{
|
|
// 所有图片都转发
|
|
struct framebuff *fb = (struct framebuff *) param1;
|
|
fb_get(fb);
|
|
int send = msi_output_fb(msi, fb);
|
|
if (!send)
|
|
{
|
|
gen420->output_en = 0;
|
|
}
|
|
ret = RET_OK + 1;
|
|
break;
|
|
}
|
|
|
|
if (fb->mtype != F_YUV)
|
|
{
|
|
ret = RET_ERR;
|
|
}
|
|
else
|
|
{
|
|
if (gen420->filter_type)
|
|
{
|
|
// 轮询类型是否有一致
|
|
ret = RET_ERR;
|
|
uint16_t *each = gen420->filter_type;
|
|
while (*each)
|
|
{
|
|
// 如果一致,返回OK
|
|
if (*each == fb->stype)
|
|
{
|
|
ret = RET_OK;
|
|
break;
|
|
}
|
|
each++;
|
|
}
|
|
}
|
|
|
|
if (ret == RET_OK)
|
|
{
|
|
struct yuv_arg_s *yuv_msg;
|
|
yuv_msg = (struct yuv_arg_s *) fb->priv;
|
|
ret = RET_ERR;
|
|
// 如果magic为0,不需要处理
|
|
if (!gen420->magic)
|
|
{
|
|
ret = RET_OK;
|
|
}
|
|
// magic不是0,则需要匹配
|
|
else if (gen420->magic == yuv_msg->magic)
|
|
{
|
|
ret = RET_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case MSI_CMD_TRANS_FB_END:
|
|
{
|
|
os_run_work(&gen420->work);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
struct msi *gen420_jpg_msi_init(const char *msi_name, uint8_t which_jpg, uint8_t recv_type, uint8_t lock_value, uint8_t queue_value, uint16_t *filter_type, gen420_filter_fn fn)
|
|
{
|
|
uint8_t isnew;
|
|
ASSERT(which_jpg == 0 || which_jpg == 1);
|
|
struct msi *msi = msi_new(msi_name, MAX_GEN420_RX, &isnew);
|
|
struct gen420_msi_s *gen420 = (struct gen420_msi_s *) msi->priv;
|
|
if (isnew)
|
|
{
|
|
gen420 = (struct gen420_msi_s *) STREAM_LIBC_ZALLOC(sizeof(struct gen420_msi_s));
|
|
msi->priv = (void *) gen420;
|
|
msi->action = gen420_msi_action;
|
|
gen420->msi = msi;
|
|
gen420->filter_type = filter_type;
|
|
gen420->hardware_ready = 1;
|
|
gen420->force_type = 0; // 强转类型
|
|
gen420->which_jpg = which_jpg;
|
|
gen420->lock_value = lock_value;
|
|
gen420->queue_value = queue_value;
|
|
gen420->recv_type = recv_type;
|
|
gen420->fn = fn;
|
|
gen420->output_en = 0;
|
|
msi->enable = 1;
|
|
// 启动workqueue
|
|
OS_WORK_INIT(&gen420->work, gen420_jpg_work, 0);
|
|
os_run_work(&gen420->work);
|
|
}
|
|
|
|
return msi;
|
|
} |