Files
TAIXIN/sdk/app/scale_msi/scale2_msi.c

554 lines
17 KiB
C
Raw Normal View History

#include "scale_msi.h"
#include "dev/vpp/hgvpp.h"
#include "dev/scale/hgscale.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
// 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
uint8 *scaler2buf;
extern uint32 scale_p1_w;
#define SCALE2_SRAMBUF_WLEN 64//64
//0:满屏保留所有的画面,不在意变形
//1:保证画面不变型,再进行缩放
#define SCALE2_MODE_SELECT 1
//SCALE2_MODE_SELECT为1有效10为不放大11为放大1.1倍20为放大2.0倍,以此类推
#define SCALE2_LARGER_SIZE 10
struct scale2_yuv_arg_s
{
struct yuv_arg_s yuv_arg;
uint8_t seq;
};
struct scale2_msg_t scale2_msg[3] = {
//ISP_VIDEO_0
{
.stype = FSTYPE_YUV_P1,
.iw = 640,
.ih = 480,
.ow = 320,
.oh = 240,
.x = 0,
.y = 0,
.video_only = 0,
.larger = 10,
},
//ISP_VIDEO_1
{
.stype = FSTYPE_YUV_P0,
.iw = 640,
.ih = 480,
.ow = 320,
.oh = 240,
.x = 320,
.y = 0,
.video_only = 0,
.larger = 10,
},
//ISP_VIDEO_2
{
.stype = FSTYPE_YUV_P2,
.iw = 640,
.ih = 480,
.ow = 320,
.oh = 240,
.x = 0,
.y = 180,
.video_only = 0,
.larger = 10,
},
};
volatile uint8_t scaler2_dev_id = 0;
// 这里可能采用信号量的形式,通知到线程去处理数据
static int32_t scale2_stream_done(uint32 irq_flag, uint32 irq_data, uint32 param1)
{
struct scale2_msi_s *scale2 = (struct scale2_msi_s *)irq_data;
//struct framebuff *fb;
struct scale2_yuv_arg_s *arg;
//判断序号,有可能双镜头
scale2->seq++;
if (scale2->now_fb) {
arg = (struct scale2_yuv_arg_s*)scale2->now_fb->priv;
arg->seq = scale2->seq;
arg->yuv_arg.y_size = scale2->ow*scale2->oh;
arg->yuv_arg.x = scale2->x;
arg->yuv_arg.y = scale2->y;
arg->yuv_arg.video_only = scale2_msg[scaler2_dev_id].video_only;
arg->yuv_arg.out_w =scale2->ow;
arg->yuv_arg.out_h =scale2->oh;
scale2->now_fb->stype = scale2_msg[scaler2_dev_id].stype;
// 不再直接放now_fb而是把now_fb放到预分配的槽(now_fb_msg)中,然后把槽地址放入消息队列
uint8_t idx = scale2->now_fb_msg_idx;
if (scale2->now_fb_msg[idx] == NULL) {
scale2->now_fb_msg[idx] = scale2->now_fb;
// advance index
scale2->now_fb_msg_idx = (idx + 1) % MAX_SCALE2_TX;
if (os_msgq_put(&scale2->msgq, (uint32_t)&scale2->now_fb_msg[idx], 0)) {
if (scale2->now_fb_msg[idx] == scale2->now_fb) {
scale2->now_fb_msg[idx] = NULL;
}
msi_delete_fb(NULL, scale2->now_fb);
}
} else {
msi_delete_fb(NULL, scale2->now_fb);
}
}
scale2->now_fb = NULL;
scale2->mutex_count = 0;
return 0;
}
static int32_t scale2_stream_ov(uint32 irq_flag, uint32 irq_data, uint32 param1)
{
os_printf("%s:%d\n", __FUNCTION__, __LINE__);
return 0;
}
static int32 scale2_stream_work(struct os_work *work)
{
struct scale2_msi_s *scale2 = (struct scale2_msi_s *)work;
struct framebuff *fb;
struct scale2_yuv_arg_s *arg;
int32_t err = -1;
struct framebuff **slot = (struct framebuff **)os_msgq_get2(&scale2->msgq, 0, &err);
// 没有数据
if (err)
{
goto scale2_stream_work_end;
}
fb = NULL;
if (slot)
{
uint32 ie = disable_irq();
fb = *slot;
*slot = NULL;
enable_irq(ie);
}
arg = (struct scale2_yuv_arg_s*)fb->priv;
arg->yuv_arg.dispcnt++;
fb->mtype = F_YUV;
//fb->stype = scale2->type;
//_os_printf("scale2 fb:%X\ttype:%d\n",fb,fb->stype);
if (scale2->filter_type != ~0 && scale2->filter_type != fb->srcID) {
msi_delete_fb(scale2->msi, fb);
} else {
msi_output_fb(scale2->msi, fb);
}
scale2_stream_work_end:
// 过1ms就去轮询一遍,实际如果用信号量,可以改成任务形式,等待信号量,可以节约cpu(实际cache影响可能更大,cpu占用很少)
// 由于workqueue没有支持等待信号量,只能通过1ms轮询一下
os_run_work_delay(work, 1);
return 0;
}
static int32_t scale2_msi_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
{
int32_t ret = RET_OK;
struct scale2_msi_s *scale2 = (struct scale2_msi_s *)msi->priv;
//uint32_t ow_n,oh_n;
//uint32_t iw_n,ih_n;
uint8_t *yinaddr;
uint8_t *uinaddr;
uint8_t *vinaddr;
switch (cmd_id)
{
// 这里msi已经被删除,那么就要考虑tx_pool的资源释放了
// 能进来这里,就是代表所有fb都已经用完了
case MSI_CMD_POST_DESTROY:
{
struct framebuff *fb;
// 释放资源fb资源文件
while (1)
{
fb = fbpool_get(&scale2->tx_pool, 0, NULL);
if (!fb)
{
break;
}
// 预分配空间释放
if (fb->priv)
{
STREAM_LIBC_FREE(fb->priv);
}
if (fb->data)
{
STREAM_FREE(fb->data);
}
}
STREAM_LIBC_FREE(scaler2buf);
scaler2buf = NULL;
fbpool_destroy(&scale2->tx_pool);
STREAM_LIBC_FREE(scale2);
}
break;
// 停止硬件,移除没有必要的资源(但是fb的资源不能现在删除,这个时候fb可能外部还在调用)
case MSI_CMD_PRE_DESTROY:
{
struct framebuff *fb = NULL;
int32_t err = 0;
scale_close(scale2->scale_dev);
os_work_cancle2(&scale2->work, 1);
// os_printf("%s:%d MSI_CMD_PRE_DESTROY\n", __FUNCTION__, __LINE__);
// 移除信号量里面的数据
while (!err)
{
// 取出的是槽地址首先获取槽再释放其中的真实fb
struct framebuff **slot = (struct framebuff **)os_msgq_get2(&scale2->msgq, 0, &err);
if (slot)
{
uint32 ie = disable_irq();
fb = *slot;
*slot = NULL;
enable_irq(ie);
if (fb)
{
msi_delete_fb(NULL, fb);
}
}
fb = NULL;
}
os_msgq_del(&scale2->msgq);
}
break;
// 接收,判断是类型是否可以支持压缩
case MSI_CMD_TRANS_FB:
{
}
break;
// 预先分配的,默认不需要释放fb->data,除非是MSI_CMD_DESTROY后,就要释放
case MSI_CMD_FREE_FB:
{
struct framebuff *fb = (struct framebuff *)param1;
if (fb->data)
{
STREAM_FREE(fb->data);
fb->data = NULL;
}
fbpool_put(&scale2->tx_pool, fb);
// 不需要内核去释放fb
ret = RET_OK + 1;
}
break;
case MSI_CMD_SCALE2:
{
uint32_t cmd_self = (uint32_t)param1;
uint32 scale2_p1_w;
uint8_t *data;
uint8_t decfrom = param2;
// 自定义命令
switch (cmd_self)
{
case MSI_SCALE2_SET_FILTER_TYPE:
{
scale2->filter_type = param2;
}
break;
case MSI_SCALE2_START:
{
//注意,这里需要根据vpp那边配置来决定用哪个
//注意line buf的数量
// 暂时用同样的iw ih ow oh
//scale_from_h264_config(scale2->scale_dev,scale2->iw,scale2->ih,scale2->ow,scale2->oh,10);
//set_lcd_photo1_config(scale2->ow,scale2->oh,0);
scale2_p1_w = ((scale2->ow+3)/4)*4;
scale_close(scale2->scale_dev);
scale_set_input_stream(scale2->scale_dev,decfrom);
scale_set_output_sram_or_frame(scale2->scale_dev,1);
scale_set_in_out_size(scale2->scale_dev,scale2->iw,scale2->ih,scale2->ow,scale2->oh);
scale_set_step(scale2->scale_dev,scale2->iw,scale2->ih,scale2->stw,scale2->sth);
scale_set_start_addr(scale2->scale_dev,scale2->sx,scale2->sy);
if(scaler2buf == NULL){
if(scale2->ow <= scale2->iw){
scaler2buf = STREAM_LIBC_MALLOC(0x20+scale2_p1_w+20*SCALE2_SRAMBUF_WLEN*4+256 + 0x12+scale2_p1_w/2+11*SCALE2_SRAMBUF_WLEN*2+128+0x12+scale2_p1_w/2+11*SCALE2_SRAMBUF_WLEN*2+128+12);
memset(scaler2buf,0x55,0x20+scale2_p1_w+20*SCALE2_SRAMBUF_WLEN*4+256 + 0x12+scale2_p1_w/2+11*SCALE2_SRAMBUF_WLEN*2+128+0x12+scale2_p1_w/2+11*SCALE2_SRAMBUF_WLEN*2+128+12);
}else{
scaler2buf = STREAM_LIBC_MALLOC(0x20+scale2_p1_w+40*SCALE2_SRAMBUF_WLEN*4+256 + 0x12+scale2_p1_w/2+22*SCALE2_SRAMBUF_WLEN*2+128+0x12+scale2_p1_w/2+22*SCALE2_SRAMBUF_WLEN*2+128+12);
memset(scaler2buf,0x55,0x20+scale2_p1_w+40*SCALE2_SRAMBUF_WLEN*4+256 + 0x12+scale2_p1_w/2+22*SCALE2_SRAMBUF_WLEN*2+128+0x12+scale2_p1_w/2+22*SCALE2_SRAMBUF_WLEN*2+128+12);
}
if(scaler2buf == NULL){
os_printf("malloc scaler2 fail.......\r\n");
return RET_ERR;
}else{
os_printf("scaler 2 malloc finish\r\n");
}
scale2->scaler2buf = scaler2buf;
yinaddr = scaler2buf;
if(scale2->ow <= scale2->iw){
uinaddr = yinaddr+((0x20+scale2_p1_w+20*SCALE2_SRAMBUF_WLEN*4+256 + 3)/4)*4;
vinaddr = uinaddr+((0x12+scale2_p1_w/2+11*SCALE2_SRAMBUF_WLEN*2+128 + 3)/4)*4;
}else{
uinaddr = yinaddr+((0x20+scale2_p1_w+40*SCALE2_SRAMBUF_WLEN*4+256 + 3)/4)*4;
vinaddr = uinaddr+((0x12+scale2_p1_w/2+22*SCALE2_SRAMBUF_WLEN*2+128 + 3)/4)*4;
}
scale_linebuf_yuv_addr(scale2->scale_dev,(uint32)yinaddr,(uint32)uinaddr,(uint32)vinaddr);
}
scale_set_srambuf_wlen(scale2->scale_dev,SCALE2_SRAMBUF_WLEN);
scale_request_irq(scale2->scale_dev,FRAME_END,(scale_irq_hdl )&scale2_stream_done,(uint32)scale2);
scale_request_irq(scale2->scale_dev,INBUF_OV,(scale_irq_hdl )&scale2_stream_ov,(uint32)scale2);
// 这里分配一下scale2的空间,通过标准接口去分配吧,理论这里一定能获取到,这里就不判断异常情况了
struct framebuff *fb;
// 正常应该要获取到fb
fb = fbpool_get(&scale2->tx_pool, 0, scale2->msi);
uint8_t *p_buf;
if (!fb)
{
//os_printf("N scale2->now_fb:%X\r\n",scale2->now_fb);
// 找不到新的空间,则返回,使用旧空间
return 0;
}
fb->srcID = decfrom;
data = (uint8_t *)STREAM_MALLOC(scale2->ow * scale2->oh * 3 / 2);
if(data == NULL){
_os_printf("no scaler room\r\n");
return 0;
}
sys_dcache_invalid_range((uint32_t*)data, scale2->ow * scale2->oh * 3 / 2);
fb->data = data;
fb->len = (scale2->ow * scale2->oh * 3) / 2;
p_buf = fb->data;
scale2->now_fb = fb;
scale_set_out_yaddr(scale2->scale_dev, (uint32)p_buf);
scale_set_out_uaddr(scale2->scale_dev, (uint32)p_buf + scale2->ow * scale2->oh);
scale_set_out_vaddr(scale2->scale_dev, (uint32)p_buf + scale2->ow * scale2->oh + scale2->ow * scale2->oh / 4);
scale_open(scale2->scale_dev);
}
break;
}
}
break;
default:
break;
}
return ret;
}
void scale2_output_size_local_change(uint8_t id,uint8_t show_only,uint16 x,uint16 y,uint16 w,uint16 h){
uint32 ie;
ie = disable_irq();
scale2_msg[id].x = x;
scale2_msg[id].y = y;
scale2_msg[id].ow = w;
scale2_msg[id].oh = h;
scale2_msg[id].video_only = show_only;
enable_irq(ie);
}
void scale2_output_larger_local_change(uint8_t id, uint8_t larger)
{
uint32 ie;
ie = disable_irq();
scale2_msg[id].larger = larger;
enable_irq(ie);
}
// 参数分别是vpp的图像iw和ih,要scale的ow和oh,如果和屏有关,可以传入屏幕的宽高
struct msi *scale2_msi(const char *name, uint16_t iw, uint16_t ih, uint16_t ow, uint16_t oh, uint16_t type,uint8_t larger)
{
uint8_t itk;
struct msi *msi = msi_new(name, 0, NULL);
struct scale2_msi_s *scale2 = (struct scale2_msi_s *)msi->priv;
if(msi == NULL)
return NULL;
if (!scale2)
{
// os_printf("%s:%d new success\n", __FUNCTION__, __LINE__);
scale2 = (struct scale2_msi_s *)STREAM_LIBC_ZALLOC(sizeof(struct scale2_msi_s));
msi->action = scale2_msi_action;
msi->priv = (void *)scale2;
scale2->msi = msi;
scale2->scale_dev = (struct scale_device *)dev_get(HG_SCALE2_DEVID);
for(itk = 0;itk < 3;itk++){
scale2_msg[itk].iw = iw;
scale2_msg[itk].ih = ih;
scale2_msg[itk].ow = ow;
scale2_msg[itk].oh = oh;
}
scale2->filter_type = ~0;
scale2->ow = ow;
scale2->oh = oh;
scale2->iw = iw;
scale2->ih = ih;
scale2->stw = ow;
scale2->sth = oh;
scale2->x = 0;
scale2->y = 0;
scale2->type = type;
scale2->larger = larger;
// 初始化now_fb_msg槽位为NULL并重置索引
scale2->now_fb_msg_idx = 0;
for (itk = 0; itk < MAX_SCALE2_TX; itk++) {
scale2->now_fb_msg[itk] = NULL;
}
fbpool_init(&scale2->tx_pool, MAX_SCALE2_TX);
uint8_t init_count = 0;
//uint8_t *data;
// 初始化fb的一些默认信息
while (init_count < MAX_SCALE2_TX)
{
// 预分配framebuff的空间给到scale
//data = (uint8_t *)STREAM_MALLOC(ow * oh * 3 / 2);
// 先配置参数信息
//配置yuv信息,但是申请空间是申请scale3_yuv_arg_s,这里是特殊的,scale3_yuv_arg_s有自己的参数需要用到
struct yuv_arg_s *yuv = (struct yuv_arg_s *)STREAM_LIBC_ZALLOC(sizeof(struct scale2_yuv_arg_s));
// 由于创建流的时候,参数已经分配好了,所以这里可以确定参数
yuv->y_size = scale2->ow * scale2->oh;
yuv->uv_off = 0;
yuv->y_off = 0;
yuv->dispcnt = 0;
yuv->out_w = scale2->ow;
yuv->out_h = scale2->oh;
yuv->del = &scale2->del;
//os_printf("malloc data:%X\n",data);
FBPOOL_SET_INFO(&scale2->tx_pool, init_count, NULL, ow * oh * 3 / 2, (void *)yuv);
init_count++;
}
msi->enable = 1;
// msi_add_output(msi,NULL,R_VIDEO_P1);
// 发送自定义命令,启动scale3
//msi_do_cmd(msi, MSI_CMD_SCALE2, MSI_SCALE2_START, 0);
os_msgq_init(&scale2->msgq, MAX_SCALE2_TX);
OS_WORK_INIT(&scale2->work, scale2_stream_work, 0);
os_run_work_delay(&scale2->work, 1);
}
os_printf("%s:%d\tmsi:%X\n", __FUNCTION__, __LINE__, msi);
return msi;
}
int scale2_cfg_run(uint8_t streamfrom,uint8_t id){
uint32 ow_n,oh_n;
uint32_t w_start,h_start;
uint32 larger;
struct msi *scaler_msi = msi_find("scale2",0);
struct scale2_msi_s *scale2 = (struct scale2_msi_s *)scaler_msi->priv;
uint32 ie;
int ret = 0;
static uint32 last_cfg_time = 0;
if(scaler_msi) {
msi_put(scaler_msi);
}
#ifdef SYS_APP_WALKIE_TALKIE
if(scale2->mutex_count) {
if(os_jiffies() - last_cfg_time > 1000) {
os_printf("scale2_cfg_run timeout\n");
goto scale2_cfg_run_continue;
}
ret = 1;
return ret;
}
scale2_cfg_run_continue:
#endif
scale2->mutex_count = 1;
last_cfg_time = os_jiffies();
ie = disable_irq();
// 满屏保留所有的画面,不在意变形
#if SCALE2_MODE_SELECT == 0
scale2->ow = scale2_msg[id].ow;
scale2->oh = scale2_msg[id].oh;
scale2->iw = scale2_msg[id].iw;
scale2->ih = scale2_msg[id].ih;
scale2->stw = scale2_msg[id].ow;
scale2->sth = scale2_msg[id].oh;
scale2->x = scale2_msg[id].x;
scale2->y = scale2_msg[id].y;
scale2->sx = 0;
scale2->sy = 0;
#endif
//保证画面不变型,再进行缩放
#if SCALE2_MODE_SELECT == 1
scale2->ow = scale2_msg[id].ow;
scale2->oh = scale2_msg[id].oh;
scale2->iw = scale2_msg[id].iw;
scale2->ih = scale2_msg[id].ih;
scale2->x = scale2_msg[id].x;
scale2->y = scale2_msg[id].y;
scale2->larger = scale2_msg[id].larger;
larger = scale2->larger;
if(((scale2->iw*1000)/scale2->ow) > ((scale2->ih*1000)/scale2->oh)){
ow_n = (((scale2->iw*scale2->oh)/scale2->ih + 15)/16)*16 ;
oh_n = scale2->oh;
}else{
ow_n = scale2->ow;
oh_n = (((scale2->ih*scale2->ow)/scale2->iw + 15)/16)*16 ;
}
w_start = ow_n*larger/10;
h_start = oh_n*larger/10;
scale2->stw = w_start;
scale2->sth = h_start;
scale2->sx = (w_start - ow_n)/2;
scale2->sy = (h_start - oh_n)/2;
#endif
enable_irq(ie);
msi_do_cmd(scaler_msi, MSI_CMD_SCALE2, MSI_SCALE2_START, streamfrom);
return ret;
}
void scale2_recfg_input_size(uint16_t w,uint16_t h,uint8_t id){
uint32 ie;
ie = disable_irq();
scale2_msg[id].iw =w;
scale2_msg[id].ih = h;
enable_irq(ie);
}