Files
TAIXIN/sdk/lib/video/dvp/jpeg/jpg_v3_msi.c

1589 lines
53 KiB
C
Raw Normal View History

#include "basic_include.h"
#include "lib/multimedia/msi.h"
#include "stream_define.h"
#include "lib/video/dvp/jpeg/jpg.h"
#include "dev/jpg/hgjpg.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
#include "lib/video/vpp/vpp_dev.h"
#include "jpg_concat_msi.h"
#include "user_work/user_work.h"
#include "hal/scale.h"
#if JPG_EN
#define HARDWARE_JPG_NUM 2
// jpg中断记录的msg,通过jpg_node预留空间来及记录
struct jpg_isr_msg
{
uint8_t stype;
uint8_t src_from;
uint8_t srcID;
uint8_t datatag;
uint16_t w, h;
uint32_t time;
uint32_t len;
};
enum
{
MSI_JPG_DONE_ERR = BIT(0), // done的时候报错
MSI_JPG_BUF_FULL_ERR = BIT(1), // buf full的时候报错
MSI_JPG_BUF_ERR = BIT(2), // 硬件直接报错
MSI_SCALE1_DATA0_DATA1_CLOSE = BIT(3),
};
// 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
struct msi *g_jpg_msi[HARDWARE_JPG_NUM] = {NULL, NULL};
// 采用默认jpg方式,如果遇到频繁切换mjpg模式,会变慢
#ifndef FAST_JPG
int jpg_quality_pidCtrl(struct jpg_V3_msi_s *jpg_msg, int diff, int p, int i, int d)
{
int32_t res = p * diff + i * jpg_msg->diff_sum + d * (diff - jpg_msg->diff_prev);
jpg_msg->diff_sum += diff;
jpg_msg->diff_prev = diff;
res = res >> 16;
res = LIMITING(res, 120, -120);
jpg_msg->diff_sum = LIMITING(jpg_msg->diff_sum, 2000, -2000);
//_os_printf("diff_sum:%d\n",diff_sum);
return res;
}
static uint8_t jpg_msi_quality_tidy(struct jpg_V3_msi_s *jpg_msg, uint32_t cur_len, uint8_t *dqt_index_diff)
{
uint8_t updata_dqt = 0;
int32_t jpg_len_diff = cur_len - jpg_msg->target_len;
int32_t res = jpg_quality_pidCtrl(jpg_msg, jpg_len_diff, QUALITY_CTRL_P, QUALITY_CTRL_I, QUALITY_CTRL_D);
uint8_t qt_diff = os_abs(res) % 0x10;
uint8_t qt_index_diff = os_abs(res) / 0x10;
*dqt_index_diff = qt_index_diff;
if (res > 0)
{
if (qt_diff + (jpg_msg->qt) > 0xf)
{
if ((jpg_msg->dqtable_index + qt_index_diff + 1 + (qt_diff - (0xf - jpg_msg->qt)) / 8) > DQT_MAX_INDEX)
{
*dqt_index_diff = DQT_MAX_INDEX - jpg_msg->dqtable_index;
jpg_msg->qt = 0xf;
}
else
{
jpg_msg->qt = 0x8 + (qt_diff - (0xf - jpg_msg->qt)) % 8;
*dqt_index_diff = qt_index_diff + 1 + (qt_diff - (0xf - jpg_msg->qt)) / 8;
}
}
else
{
jpg_msg->qt += qt_diff;
}
if ((*dqt_index_diff) >= 1 && jpg_msg->dqtable_index < DQT_MAX_INDEX)
{
*dqt_index_diff = ((*dqt_index_diff) > (DQT_MAX_INDEX - jpg_msg->dqtable_index)) ? (DQT_MAX_INDEX - jpg_msg->dqtable_index) : (*dqt_index_diff);
updata_dqt = 2;
}
}
else if (res < 0)
{
if (jpg_msg->qt - qt_diff < 0)
{
if ((jpg_msg->dqtable_index - (qt_index_diff + 1 + (qt_diff - jpg_msg->qt) / 8)) < 0)
{
*dqt_index_diff = jpg_msg->dqtable_index;
jpg_msg->qt = 0;
}
else
{
jpg_msg->qt = 0x8 - (qt_diff - jpg_msg->qt) % 8; //(qt_diff-(*qt)) maybe > 0x8
*dqt_index_diff = qt_index_diff + 1 + (qt_diff - jpg_msg->qt) / 8;
}
}
else
{
jpg_msg->qt -= qt_diff;
}
if ((*dqt_index_diff) >= 1 && jpg_msg->dqtable_index > 0)
{
*dqt_index_diff = ((*dqt_index_diff) > (jpg_msg->dqtable_index)) ? jpg_msg->dqtable_index : (*dqt_index_diff);
updata_dqt = 1;
}
}
if (updata_dqt == 0)
{
*dqt_index_diff = 0;
}
return updata_dqt;
}
static void jpg_msi_DQT_updata(struct jpg_V3_msi_s *jpg_msg, uint8_t upOdown, uint8_t diff)
{
uint32_t *ptable = NULL;
int8_t pdqt_tab = jpg_msg->dqtable_index;
if (upOdown == 1)
{
pdqt_tab -= diff;
if (pdqt_tab < 0)
{
pdqt_tab = 0;
}
}
else
{
pdqt_tab += diff;
if (pdqt_tab > DQT_MAX_INDEX)
{
pdqt_tab = DQT_MAX_INDEX;
}
}
jpg_msg->dqtable_index = pdqt_tab;
ptable = (uint32 *) quality_tab[pdqt_tab];
jpg_updata_dqt(jpg_msg->jpg, ptable);
}
static int32 jpg_msi_done_isr(uint32 irq_flag, uint32 irq_data, uint32 param1, uint32 param2)
{
uint8 dqt_index_diff = 0;
int8_t err = RET_OK;
struct msi *msi = (struct msi *) irq_data;
struct jpg_V3_msi_s *jpg_msg = (struct jpg_V3_msi_s *) msi->priv;
// 如果没有异常,send_fb应该通过信号量发出去
struct framebuff *send_fb = jpg_msg->now_fb;
struct framebuff *fb;
uint32_t jpg_len = param1;
uint8_t last_qt = jpg_msg->qt;
// 如果数据不对,需要处理异常情况(需要将fb->now_fb里面的链表全部放回到pool中)
// 如果异常,这里关闭jpg,workqueue去清理资源,重新启动mjpg
if (jpg_msg->err)
{
err = RET_ERR;
goto jpg_msi_done_isr_end;
}
jpg_set_ready(jpg_msg->jpg);
// 最后配置的fb,这个是没有被用的,可以重复利用
fb = jpg_msg->last_fb;
// 这里不应该进来,进来后,需要检查是否正常
if (!fb)
{
err = RET_ERR;
goto jpg_msi_done_isr_end;
}
jpg_set_addr(jpg_msg->jpg, (uint32) fb->data, fb->len);
// 先将fb记录在last_fb
jpg_msg->last_fb = fb;
fb = fbpool_get(&jpg_msg->pool, 0, NULL);
// 空间不够,则通知workqueue检查或者重新启动mjpg
if (!fb)
{
err = RET_ERR;
goto jpg_msi_done_isr_end;
}
// 这里确认足够空间重新启动jpg,可以将now_fb重新赋值
jpg_msg->now_fb = jpg_msg->last_fb;
jpg_msg->use_last_fb = jpg_msg->last_fb;
// 配置第二次的寄存器
jpg_set_addr(jpg_msg->jpg, (uint32) fb->data, fb->len);
jpg_msg->last_fb = fb;
// jpg_open(jpg_msg->jpg);
send_fb->datatag = jpg_msg->datatag;
if (os_msgq_put(&jpg_msg->msgq, (uint32_t) send_fb, 0))
{
struct framebuff *tmp_fb = send_fb;
// 发送失败,应该将fb全部放回pool池
while (tmp_fb)
{
tmp_fb = send_fb->next;
fbpool_put(&jpg_msg->pool, send_fb);
send_fb = tmp_fb;
}
}
else
{
uint32_t time = 0;
// send_fb->mtype = F_JPG_NODE;
if (jpg_msg->src_from == GEN420_DATA)
{
// 配置这个是从gen420来的数据,后续要考虑是否要独立配置类型(因为gen420来源数据可能是内存或者其他来源),或者说由其他回调接口去配置吧
// 这里需要调用msi命令去配置
send_fb->stype = jpg_msg->gen420_type;
send_fb->srcID = FRAMEBUFF_SOURCE_JPG_GEN420;
time = jpg_msg->set_time;
}
else if (jpg_msg->src_from == SCALER_DATA)
{
send_fb->stype = jpg_msg->scale1_type ? jpg_msg->scale1_type : (FSTYPE_VIDEO_VPP_DATA0 + jpg_msg->src_from);
send_fb->srcID = FRAMEBUFF_SOURCE_JPG_SCALER;
time = jpg_msg->set_time;
}
else
{
// send_fb->stype = FSTYPE_JPG_CAMERA0+video_msg.video_type_cur;
send_fb->srcID = FRAMEBUFF_SOURCE_CAMERA0 + video_msg.video_type_cur;
send_fb->stype = FSTYPE_VIDEO_VPP_DATA0 + jpg_msg->src_from;
}
if (!time)
{
time = os_jiffies();
}
// 配置子类型
send_fb->datatag = jpg_msg->datatag;
// 这里是特殊赋值,为了不每一个send_fb申请空间,所以这里利用指针去保存
send_fb->priv = (void *) (jpg_msg->w << 16 | jpg_msg->h);
// 利用mtype来保存低位的时间戳,在msi_output_fb重新计算时间戳(因为不应该存在65s错过)
send_fb->mtype = F_JPG_NODE;
// 利用time的结构体保存图片长度,msi_output_fb后将数据保存到结构体再恢复
send_fb->time = time;
send_fb->msi = (void *) jpg_len;
// 唤醒workqueue去处理fb
os_run_work(&jpg_msg->work);
}
// os_printf("jpglen:%d %d %d\n", jpg_len, jpg_msg->qt, jpg_msg->dqtable_index);
uint8_t update = jpg_msi_quality_tidy(jpg_msg, jpg_len, &dqt_index_diff);
// os_printf("quality res:%d %s%d\n", jpg_msg->qt, ((update>1)?"+":"-"),dqt_index_diff);
if (last_qt != jpg_msg->qt)
{
jpg_set_qt(jpg_msg->jpg, jpg_msg->qt);
}
if (update)
{
jpg_msi_DQT_updata(jpg_msg, update, dqt_index_diff);
}
jpg_msi_done_isr_end:
if (err == RET_OK)
{
_os_printf(KERN_DEBUG "JD");
}
else
{
jpg_msg->err |= MSI_JPG_DONE_ERR;
jpg_close(jpg_msg->jpg);
os_event_set(&jpg_msg->evt, MSI_JPG_DONE_ERR, NULL);
os_run_work(&jpg_msg->work);
_os_printf(KERN_DEBUG "JDE");
}
return 0;
}
static int32 jpg_msi_outbuff_full_isr(uint32 irq_flag, uint32 irq_data, uint32 param1, uint32 param2)
{
int8_t err = RET_OK;
struct msi *msi = (struct msi *) irq_data;
struct jpg_V3_msi_s *jpg_msg = (struct jpg_V3_msi_s *) msi->priv;
if (jpg_msg->err)
{
_os_printf(KERN_ERR "JO");
goto jpg_msi_outbuff_full_isr_end;
}
struct framebuff *fb = fbpool_get(&jpg_msg->pool, 0, NULL);
if (!fb)
{
err = RET_ERR;
goto jpg_msi_outbuff_full_isr_end;
}
jpg_set_addr(jpg_msg->jpg, (uint32) fb->data, fb->len);
ASSERT(jpg_msg->last_fb);
// 放到链表里面(now_fb为head)
jpg_msg->use_last_fb->next = jpg_msg->last_fb;
// 记录当前的配置的最后fb
jpg_msg->use_last_fb = jpg_msg->last_fb;
// 最后配置jpg地址的fb(尚未添加到链表)
jpg_msg->last_fb = fb;
jpg_msi_outbuff_full_isr_end:
if (err != RET_OK)
{
jpg_msg->err |= MSI_JPG_BUF_FULL_ERR;
os_event_set(&jpg_msg->evt, MSI_JPG_BUF_FULL_ERR, NULL);
_os_printf(KERN_ERR "JU");
}
return 0;
}
static int32 jpg_msi_buf_err(uint32 irq_flag, uint32 irq_data, uint32 param1, uint32 param2)
{
struct msi *msi = (struct msi *) irq_data;
struct jpg_V3_msi_s *jpg_msg = (struct jpg_V3_msi_s *) msi->priv;
// 关闭jpg
jpg_close(jpg_msg->jpg);
// 唤醒workqueue?然后workqueue检查是不是有异常?有异常重新启动jpg?统一由外部线程去重新启动
os_event_set(&jpg_msg->evt, MSI_JPG_BUF_ERR, NULL);
os_run_work(&jpg_msg->work);
jpg_msg->err |= MSI_JPG_BUF_ERR;
_os_printf(KERN_ERR "JE");
return 0;
}
static int32 jpg_msi_work(struct os_work *work)
{
struct jpg_V3_msi_s *jpg_msg = (struct jpg_V3_msi_s *) work;
struct framebuff *fb;
int32 err = -1;
uint32 jpg_err = 0;
os_event_wait(&jpg_msg->evt, MSI_JPG_DONE_ERR | MSI_JPG_BUF_FULL_ERR | MSI_JPG_BUF_ERR, &jpg_err, OS_EVENT_WMODE_OR | OS_EVENT_WMODE_CLEAR, 0);
fb = (struct framebuff *) os_msgq_get2(&jpg_msg->msgq, 0, &err);
if (err)
{
goto jpg_msi_work_end;
}
// 测试,删除fb(正常是添加msi,然后get_msi,发送出去)
struct framebuff *tmp_fb = fb;
uint32_t len = (uint32_t) fb->msi;
while (tmp_fb)
{
tmp_fb->msi = jpg_msg->msi;
// 这个模块是特殊处理
msi_get(tmp_fb->msi);
tmp_fb = tmp_fb->next;
}
// 申请结构体,这里是比较特殊的使用
// w和h保存在priv结构体
// 时间低位保存在mtype
// time保存的是图片的size
// 最后还原到结构体
struct jpg_node_s *jpg_priv = (struct jpg_node_s *) STREAM_LIBC_MALLOC(sizeof(struct jpg_node_s));
if (jpg_priv)
{
uint32_t w_h = (uint32_t) fb->priv;
jpg_priv->w = (w_h) >> 16;
jpg_priv->h = (w_h) & 0xffff;
jpg_priv->jpg_len = len;
fb->time = fb->time;
fb->mtype = F_JPG_NODE;
fb->priv = jpg_priv;
}
else
{
fb->priv = NULL;
}
// 为了不添加新结构,使用time作为w和h保存,priv用于保存总长度(仅仅用于这个msi)
msi_output_fb(jpg_msg->msi, fb);
jpg_msi_work_end:
// jpg异常,那么去重新启动一下jpg
// 需要先清除对应资源才行
if (jpg_err)
{
os_printf(KERN_ERR "jpg_err:%X\twhich:%d\n", jpg_err, jpg_msg->which);
struct framebuff *tmp_fb, *now_fb, *fb;
now_fb = tmp_fb = jpg_msg->now_fb;
while (now_fb)
{
tmp_fb = now_fb;
now_fb = now_fb->next;
fbpool_put(&jpg_msg->pool, tmp_fb);
}
// 最后一次配置寄存器的fb(没有链接到now_fb)
if (jpg_msg->last_fb)
{
fbpool_put(&jpg_msg->pool, jpg_msg->last_fb);
}
jpg_msg->last_fb = NULL;
jpg_msg->now_fb = NULL;
// 重新配置jpg的地址,启动
fb = fbpool_get(&jpg_msg->pool, 0, NULL);
ASSERT(fb);
jpg_set_addr(jpg_msg->jpg, (uint32) fb->data, fb->len);
jpg_msg->now_fb = fb;
jpg_msg->use_last_fb = fb;
fb = fbpool_get(&jpg_msg->pool, 0, NULL);
ASSERT(fb);
jpg_set_addr(jpg_msg->jpg, (uint32) fb->data, fb->len);
jpg_msg->last_fb = fb;
jpg_msg->err = 0;
jpg_msg->running = 1;
jpg_set_ready(jpg_msg->jpg);
jpg_set_data_from(jpg_msg->jpg, jpg_msg->src_from);
jpg_open(jpg_msg->jpg);
}
return 0;
}
static int jpg_msi_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
{
int ret = RET_OK;
struct jpg_V3_msi_s *jpg_msg = (struct jpg_V3_msi_s *) msi->priv;
switch (cmd_id)
{
case MSI_CMD_POST_DESTROY:
{
fbpool_destroy(&jpg_msg->pool);
os_msgq_del(&jpg_msg->msgq);
os_event_del(&jpg_msg->evt);
msi->name = NULL; // 这里比较特殊,正常不能清空的
// 释放节点
uint32_t jpg_node_count = jpg_msg->jpg_node_count;
uint32_t m_size = 0;
while (m_size < jpg_node_count)
{
if (jpg_msg->jpg_node_buf[m_size])
{
ASSERT(jpg_msg->jpg_node_buf[m_size]);
STREAM_FREE((uint8_t *) jpg_msg->jpg_node_buf[m_size]);
}
m_size++;
}
STREAM_LIBC_FREE(jpg_msg);
}
break;
case MSI_CMD_PRE_DESTROY:
{
// 先关闭workqueue(防止有报错,将jpg重新启动)
os_work_cancle2(&jpg_msg->work, 1);
// 关闭jpg
if (jpg_msg->running)
{
jpg_close(jpg_msg->jpg);
jpg_msg->running = 0;
}
g_jpg_msi[jpg_msg->which] = NULL;
// 清除资源,理论队列的内容已经没有用了,不需要管理
// 清理一些临时资源,检查一下now_fb是否有数据?(正常流程是去释放,时间不释放也不影响,应为没有对msi进行引用)
struct framebuff *tmp_fb, *now_fb;
now_fb = tmp_fb = jpg_msg->now_fb;
while (now_fb)
{
tmp_fb = now_fb;
now_fb = now_fb->next;
fbpool_put(&jpg_msg->pool, tmp_fb);
}
// 最后一次配置寄存器的fb(没有链接到now_fb)
if (jpg_msg->last_fb)
{
fbpool_put(&jpg_msg->pool, jpg_msg->last_fb);
}
jpg_msg->last_fb = NULL;
jpg_msg->now_fb = NULL;
}
break;
case MSI_CMD_GET_RUNNING:
{
if (param1)
{
uint32_t running = 0;
if (jpg_msg->running && !jpg_msg->err)
{
running = 1;
}
else
{
os_printf(KERN_INFO"jpg_msg:%X\tjpg_msg_err:%d\n",jpg_msg,jpg_msg->err);
os_printf("jpg_msg->running:%d\n",jpg_msg->running);
os_printf("jpg_msg->err:%d\n",jpg_msg->err);
}
*(uint32_t *) param1 = running;
}
}
break;
case MSI_CMD_HARDWARE_JPEG:
{
uint32_t cmd_self = (uint32_t) param1;
uint32_t arg = param2;
switch (cmd_self)
{
// 如果需要实现多个编码size,可能需要保存,然后通过中断自动切换
case MSI_JPEG_HARDWARE_MSG:
{
uint16_t w, h;
w = arg >> 16;
h = arg & 0xffff;
jpg_msg->w = w;
jpg_msg->h = h;
// jpg_set_size(jpg_msg->jpg, h, w);
}
break;
case MSI_JPEG_HARDWARE_START:
{
if (!jpg_msg->running)
{
OS_WORK_REINIT(&jpg_msg->work);
struct framebuff *fb;
// 硬件初始化
jpg_init(jpg_msg->jpg, jpg_msg->dqtable_index, jpg_msg->qt);
jpg_set_size(jpg_msg->jpg, jpg_msg->h, jpg_msg->w);
if (jpg_msg->src_from == VPP_DATA0 || jpg_msg->src_from == VPP_DATA1)
{
jpg_msg->vpp_close_flag = 1;
}
jpg_set_data_from(jpg_msg->jpg, jpg_msg->src_from);
jpg_set_hw_check(jpg_msg->jpg, 1);
// 注册中断
jpg_request_irq(jpg_msg->jpg, jpg_msi_outbuff_full_isr, JPG_IRQ_FLAG_JPG_BUF_FULL, msi);
jpg_request_irq(jpg_msg->jpg, jpg_msi_buf_err, JPG_IRQ_FLAG_ERROR, msi);
jpg_request_irq(jpg_msg->jpg, jpg_msi_done_isr, JPG_IRQ_FLAG_JPG_DONE, msi);
jpg_set_ready(jpg_msg->jpg);
jpg_set_vsync_dly(jpg_msg->jpg, 1);
jpg_select_oe_using(jpg_msg->jpg, 0, 1);
fb = fbpool_get(&jpg_msg->pool, 0, NULL);
ASSERT(fb);
jpg_set_addr(jpg_msg->jpg, (uint32) fb->data, fb->len);
jpg_msg->now_fb = fb;
jpg_msg->use_last_fb = fb;
fb = fbpool_get(&jpg_msg->pool, 0, NULL);
ASSERT(fb);
jpg_set_addr(jpg_msg->jpg, (uint32) fb->data, fb->len);
// 记录最后一个配置链表
jpg_msg->last_fb = fb;
jpg_msg->running = 1;
jpg_open(jpg_msg->jpg);
}
else
{
}
}
break;
case MSI_JPEG_HARDWARE_STOP:
{
if (jpg_msg->running)
{
os_work_cancle2(&jpg_msg->work, 1);
if (jpg_msg->scale1_flag)
{
jpg_msg->scale1_flag = 0;
scale_close(jpg_msg->scale_dev);
jpg_close(jpg_msg->jpg);
}
else if (jpg_msg->vpp_close_flag)
{
jpg_msg->vpp_close_flag = 0;
jpg_close(jpg_msg->jpg);
}
else
{
jpg_close(jpg_msg->jpg);
}
jpg_msg->running = 0;
jpg_msg->err = 0;
// 清除异常
os_event_wait(&jpg_msg->evt, MSI_JPG_DONE_ERR | MSI_JPG_BUF_FULL_ERR | MSI_JPG_BUF_ERR, NULL, OS_EVENT_WMODE_OR | OS_EVENT_WMODE_CLEAR, 0);
// 需要清理一下队列?这个时候队列的数据应该是不需要了以及now_fb的数据也要清除
{
struct framebuff *fb;
int32 err = 0;
// 将队列的数据帮忙发送出去
while (!err)
{
fb = (struct framebuff *) os_msgq_get2(&jpg_msg->msgq, 0, &err);
if (!err)
{
struct framebuff *tmp_fb = fb;
// 中断将长度记录在msi的结构体中
uint32_t len = (uint32_t) fb->msi;
while (tmp_fb)
{
tmp_fb->msi = jpg_msg->msi;
// 这个模块是特殊处理
msi_get(tmp_fb->msi);
tmp_fb = tmp_fb->next;
}
// 申请结构体,这里是比较特殊的使用
// w和h保存在priv结构体
// 时间低位保存在mtype
// time保存的是图片的size
// 最后还原到结构体
struct jpg_node_s *jpg_priv = (struct jpg_node_s *) STREAM_LIBC_MALLOC(sizeof(struct jpg_node_s));
if (jpg_priv)
{
uint32_t w_h = (uint32_t) fb->priv;
jpg_priv->w = (w_h) >> 16;
jpg_priv->h = (w_h) & 0xffff;
jpg_priv->jpg_len = len;
fb->time = fb->time;
fb->mtype = F_JPG_NODE;
fb->priv = jpg_priv;
}
else
{
fb->priv = NULL;
}
msi_output_fb(jpg_msg->msi, fb);
}
}
}
// 中断的临时资源清除
{
struct framebuff *tmp_fb, *now_fb;
now_fb = tmp_fb = jpg_msg->now_fb;
while (now_fb)
{
tmp_fb = now_fb;
now_fb = now_fb->next;
fbpool_put(&jpg_msg->pool, tmp_fb);
}
// 最后一次配置寄存器的fb(没有链接到now_fb)
if (jpg_msg->last_fb)
{
fbpool_put(&jpg_msg->pool, jpg_msg->last_fb);
}
jpg_msg->last_fb = NULL;
jpg_msg->now_fb = NULL;
}
}
else
{
os_work_cancle2(&jpg_msg->work, 1);
}
}
break;
case MSI_JPEG_HARDWARE_FROM:
{
if (arg >= VPP_DATA0 && arg <= SOFT_DATA)
{
jpg_msg->src_from = arg;
// jpg_set_data_from(jpg_msg->jpg, arg);
}
else
{
os_printf(KERN_ERR "jpg set data from err:%d\n", arg);
}
}
break;
// 配置gen42的类型
case MSI_JPEG_HARDWARE_SET_GEN420_TYPE:
{
jpg_msg->gen420_type = arg;
}
break;
case MSI_JPEG_HARDWARE_SET_SCALE1_TYPE:
{
jpg_msg->scale1_type = arg;
}
break;
case MSI_JPEG_SET_TIME:
{
jpg_msg->set_time = arg;
}
break;
case MSI_JPEG_SET_LEN:
{
jpg_msg->target_len = arg;
}
break;
case MSI_JPEG_SET_SCALE1_FLAG:
{
jpg_msg->scale1_flag = arg;
}
break;
default:
break;
}
}
break;
case MSI_CMD_FREE_FB:
{
struct framebuff *fb = (struct framebuff *) param1;
if (fb->data)
{
sys_dcache_invalid_range((uint32_t *) fb->data, fb->len);
}
if (fb->priv)
{
STREAM_LIBC_FREE(fb->priv);
fb->priv = NULL;
}
fbpool_put(&jpg_msg->pool, fb);
// 不需要内核去释放fb
ret = RET_OK + 1;
}
break;
case MSI_CMD_SET_DATATAG:
{
uint8_t datatag = (uint8_t) param1;
jpg_msg->datatag = datatag;
}
break;
}
return ret;
}
// 这个接口尽量不在外部调用,因为硬件只有一个
// 所以由中间流对这个硬件控制
struct msi *hardware_jpg_msi(uint8_t which_jpg, uint8_t src_from, uint16_t jpg_node_len, uint16_t jpg_node_count)
{
if (which_jpg >= HARDWARE_JPG_NUM)
{
return NULL;
}
// 硬件只有一个,所以只能启动一次,外部显式调用一次msi_destroy才可以
if (g_jpg_msi[which_jpg])
{
return NULL;
}
struct jpg_V3_msi_s *jpg_msg = (struct jpg_V3_msi_s *) STREAM_LIBC_ZALLOC(sizeof(struct jpg_V3_msi_s) + jpg_node_count * sizeof(uint32_t));
if (jpg_msg)
{
jpg_msg->jpg_node_buf = (uint32_t *) (jpg_msg + 1);
}
// 先去分配空间,如果空间不够,则不启动硬件,分配节点不足4个也会退出
uint32_t m_size = 0;
while (m_size < jpg_node_count)
{
uint8_t *buff = (uint8_t *) STREAM_MALLOC(jpg_node_len);
sys_dcache_invalid_range((uint32_t *) buff, jpg_node_len);
if (!buff)
{
break;
}
jpg_msg->jpg_node_buf[m_size] = (uint32_t) buff;
m_size++;
}
if (m_size != jpg_node_count)
{
os_printf(KERN_WARNING "%s:%d jpg[%d]not enought mem,m_size:%d\n", __FUNCTION__, __LINE__, which_jpg, m_size);
}
os_printf(KERN_INFO "JPG[%d] jpg_node_count:%d\tm_size:%d\n", which_jpg, jpg_node_count, m_size);
jpg_node_count = m_size;
struct msi *msi = NULL;
uint8_t isnew = 0;
if (jpg_msg && jpg_node_count >= 4)
{
os_sprintf(jpg_msg->msi_name, "H_JPG%d_%08X", which_jpg, (uint32) os_jiffies() & 0xFFFFFFFF);
msi = msi_new(jpg_msg->msi_name, 0, &isnew);
ASSERT(msi);
// 这里一定是新创建
ASSERT(isnew);
msi->priv = (void *) jpg_msg;
jpg_msg->which = which_jpg;
jpg_msg->src_from = src_from;
jpg_msg->qt = 0xf;
// 这里式分配多少帧,如果分配1帧,就是应用要快速去处理,否则可能来不及
// 如果帧数据量大,就可能出现最后节点不够的可能
os_msgq_init(&jpg_msg->msgq, 1);
os_event_init(&jpg_msg->evt);
if (msi)
{
fbpool_init(&jpg_msg->pool, jpg_node_count);
jpg_msg->msi = msi;
// 固定输出,外部尽量不要用这个msi,统一给到RS_JPG_CONCAT这个msi去管理
jpg_msg->jpg_node_len = jpg_node_len;
jpg_msg->jpg_node_count = jpg_node_count;
jpg_msg->jpg = (struct jpg_device *) dev_get(which_jpg + HG_JPG0_DEVID);
jpg_msg->scale_dev = (struct scale_device *) dev_get(HG_SCALE1_DEVID);
jpg_close(jpg_msg->jpg);
// 预分配buf空间到各个fb中
uint16_t init_count = 0;
uint8_t *m_buff;
// 初始化framebuffer节点数量空间?最后由workqueue去从ringbuf去获取一个节点
while (init_count < jpg_node_count)
{
m_buff = (uint8_t *) jpg_msg->jpg_node_buf[init_count];
FBPOOL_SET_INFO(&jpg_msg->pool, init_count, m_buff, jpg_node_len, NULL);
init_count++;
}
jpg_msg->dqtable_index = DQT_DEF;
jpg_msg->target_len = TARGET_JPG_LEN;
jpg_msg->qt = 0xf;
msi->action = jpg_msi_action;
msi->enable = 1;
// 启动一个workqueue,去将fb发送出去,中断唤醒一次,workqueue执行一次
OS_WORK_INIT(&jpg_msg->work, jpg_msi_work, 0);
}
}
if (!msi)
{
m_size = 0;
while (m_size < jpg_node_count)
{
if (jpg_msg->jpg_node_buf[m_size])
{
ASSERT(jpg_msg->jpg_node_buf[m_size]);
STREAM_FREE((uint8_t *) jpg_msg->jpg_node_buf[m_size]);
}
m_size++;
}
if (jpg_msg)
{
STREAM_LIBC_FREE(jpg_msg);
}
}
else
{
g_jpg_msi[which_jpg] = msi;
}
return msi;
}
void jpg_mem_init(int num)
{
return;
}
// 减少频繁申请空间,使用mjpg自己的内存池,暂时只是支持了预先分配
#else
int jpg_quality_pidCtrl(struct jpg_V3_msi_s *jpg_msg, int diff, int p, int i, int d)
{
int32_t res = p * diff + i * jpg_msg->diff_sum + d * (diff - jpg_msg->diff_prev);
jpg_msg->diff_sum += diff;
jpg_msg->diff_prev = diff;
res = res >> 16;
res = LIMITING(res, 120, -120);
jpg_msg->diff_sum = LIMITING(jpg_msg->diff_sum, 2000, -2000);
//_os_printf("diff_sum:%d\n",diff_sum);
return res;
}
static uint8_t jpg_msi_quality_tidy(struct jpg_V3_msi_s *jpg_msg, uint32_t cur_len, uint8_t *dqt_index_diff)
{
uint8_t updata_dqt = 0;
int32_t jpg_len_diff = cur_len - jpg_msg->target_len;
int32_t res = jpg_quality_pidCtrl(jpg_msg, jpg_len_diff, QUALITY_CTRL_P, QUALITY_CTRL_I, QUALITY_CTRL_D);
uint8_t qt_diff = os_abs(res) % 0x10;
uint8_t qt_index_diff = os_abs(res) / 0x10;
*dqt_index_diff = qt_index_diff;
if (res > 0)
{
if (qt_diff + (jpg_msg->qt) > 0xf)
{
if ((jpg_msg->dqtable_index + qt_index_diff + 1 + (qt_diff - (0xf - jpg_msg->qt)) / 8) > DQT_MAX_INDEX)
{
*dqt_index_diff = DQT_MAX_INDEX - jpg_msg->dqtable_index;
jpg_msg->qt = 0xf;
}
else
{
jpg_msg->qt = 0x8 + (qt_diff - (0xf - jpg_msg->qt)) % 8;
*dqt_index_diff = qt_index_diff + 1 + (qt_diff - (0xf - jpg_msg->qt)) / 8;
}
}
else
{
jpg_msg->qt += qt_diff;
}
if ((*dqt_index_diff) >= 1 && jpg_msg->dqtable_index < DQT_MAX_INDEX)
{
*dqt_index_diff = ((*dqt_index_diff) > (DQT_MAX_INDEX - jpg_msg->dqtable_index)) ? (DQT_MAX_INDEX - jpg_msg->dqtable_index) : (*dqt_index_diff);
updata_dqt = 2;
}
}
else if (res < 0)
{
if (jpg_msg->qt - qt_diff < 0)
{
if ((jpg_msg->dqtable_index - (qt_index_diff + 1 + (qt_diff - jpg_msg->qt) / 8)) < 0)
{
*dqt_index_diff = jpg_msg->dqtable_index;
jpg_msg->qt = 0;
}
else
{
jpg_msg->qt = 0x8 - (qt_diff - jpg_msg->qt) % 8; //(qt_diff-(*qt)) maybe > 0x8
*dqt_index_diff = qt_index_diff + 1 + (qt_diff - jpg_msg->qt) / 8;
}
}
else
{
jpg_msg->qt -= qt_diff;
}
if ((*dqt_index_diff) >= 1 && jpg_msg->dqtable_index > 0)
{
*dqt_index_diff = ((*dqt_index_diff) > (jpg_msg->dqtable_index)) ? jpg_msg->dqtable_index : (*dqt_index_diff);
updata_dqt = 1;
}
}
if (updata_dqt == 0)
{
*dqt_index_diff = 0;
}
return updata_dqt;
}
static void jpg_msi_DQT_updata(struct jpg_V3_msi_s *jpg_msg, uint8_t upOdown, uint8_t diff)
{
uint32_t *ptable = NULL;
int8_t pdqt_tab = jpg_msg->dqtable_index;
if (upOdown == 1)
{
pdqt_tab -= diff;
if (pdqt_tab < 0)
{
pdqt_tab = 0;
}
}
else
{
pdqt_tab += diff;
if (pdqt_tab > DQT_MAX_INDEX)
{
pdqt_tab = DQT_MAX_INDEX;
}
}
jpg_msg->dqtable_index = pdqt_tab;
ptable = (uint32 *) quality_tab[pdqt_tab];
jpg_updata_dqt(jpg_msg->jpg, ptable);
}
static uint32_t jpg_node_free(void *node)
{
void *tmp_node, *now_node;
if (node)
{
now_node = tmp_node = node;
while (now_node)
{
tmp_node = now_node;
now_node = pop_node(now_node);
// 释放tmp_node
free_jpg_node(tmp_node);
}
}
return 0;
}
static uint32_t jpg_free_res(struct jpg_V3_msi_s *jpg_msg)
{
jpg_node_free(jpg_msg->now_node);
if (jpg_msg->last_node)
{
free_jpg_node(jpg_msg->last_node);
}
jpg_msg->now_node = NULL;
jpg_msg->last_node = NULL;
return 0;
}
static int32 jpg_msi_done_isr(uint32 irq_flag, uint32 irq_data, uint32 param1, uint32 param2)
{
struct msi *msi = (struct msi *) irq_data;
struct jpg_V3_msi_s *jpg_msg = (struct jpg_V3_msi_s *) msi->priv;
uint8 dqt_index_diff = 0;
int8_t err = RET_OK;
void *send_node = jpg_msg->now_node;
uint32_t jpg_len = param1;
uint8_t last_qt = jpg_msg->qt;
void *node;
uint16_t len;
// 如果异常,这里关闭jpg,workqueue去清理资源,重新启动mjpg
if (jpg_msg->err)
{
err = RET_ERR;
goto jpg_msi_done_isr_end;
}
jpg_set_ready(jpg_msg->jpg);
node = jpg_msg->last_node;
// 这里不应该进来,进来后,需要检查是否正常
if (!node)
{
err = RET_ERR;
goto jpg_msi_done_isr_end;
}
len = get_node_len(node);
jpg_set_addr(jpg_msg->jpg, (uint32) node, len);
jpg_msg->last_node = node;
node = get_jpg_node(&len);
if (!node)
{
err = RET_ERR;
goto jpg_msi_done_isr_end;
}
// 这里确认足够空间重新启动jpg,可以将now_fb重新赋值
jpg_msg->now_node = jpg_msg->last_node;
jpg_msg->use_last_node = jpg_msg->last_node;
// 配置第二次的寄存器
jpg_set_addr(jpg_msg->jpg, (uint32) node, len);
jpg_msg->last_node = node;
if (os_msgq_put(&jpg_msg->msgq, (uint32_t) send_node, 0))
{
jpg_node_free(send_node);
}
else
{
// 检查是否有足够保留空间使用
struct jpg_isr_msg *msg = get_node_rev(send_node, sizeof(struct jpg_isr_msg));
if (msg)
{
uint32_t time = 0;
if (jpg_msg->src_from == GEN420_DATA)
{
// 配置这个是从gen420来的数据,后续要考虑是否要独立配置类型(因为gen420来源数据可能是内存或者其他来源),或者说由其他回调接口去配置吧
// 这里需要调用msi命令去配置
msg->stype = jpg_msg->gen420_type;
msg->srcID = FRAMEBUFF_SOURCE_JPG_GEN420;
time = jpg_msg->set_time;
}
else if (jpg_msg->src_from == SCALER_DATA)
{
msg->stype = jpg_msg->scale1_type ? jpg_msg->scale1_type : (FSTYPE_VIDEO_VPP_DATA0 + jpg_msg->src_from);
msg->srcID = FRAMEBUFF_SOURCE_JPG_SCALER;
time = jpg_msg->set_time;
}
else
{
msg->srcID = FRAMEBUFF_SOURCE_CAMERA0 + video_msg.video_type_cur;
msg->stype = FSTYPE_VIDEO_VPP_DATA0 + jpg_msg->src_from;
}
if (!time)
{
time = os_jiffies();
}
// 配置子类型
msg->datatag = jpg_msg->datatag;
msg->w = jpg_msg->w;
msg->h = jpg_msg->h;
// 利用time的结构体保存图片长度,msi_output_fb后将数据保存到结构体再恢复
msg->time = time;
msg->len = (void *) jpg_len;
}
os_run_work(&jpg_msg->work);
}
#if 1
// os_printf("jpglen:%d %d %d\ttartget:%d\n", jpg_len, jpg_msg->qt, jpg_msg->dqtable_index,jpg_msg->target_len);
uint8_t update = jpg_msi_quality_tidy(jpg_msg, jpg_len, &dqt_index_diff);
// os_printf("quality res:%d %s%d\n", jpg_msg->qt, ((update>1)?"+":"-"),dqt_index_diff);
if (last_qt != jpg_msg->qt)
{
jpg_set_qt(jpg_msg->jpg, jpg_msg->qt);
}
if (update)
{
jpg_msi_DQT_updata(jpg_msg, update, dqt_index_diff);
}
#endif
jpg_msi_done_isr_end:
if (err == RET_OK)
{
_os_printf(KERN_DEBUG "JD");
}
else
{
jpg_msg->err |= MSI_JPG_DONE_ERR;
jpg_close(jpg_msg->jpg);
os_event_set(&jpg_msg->evt, MSI_JPG_DONE_ERR, NULL);
os_run_work(&jpg_msg->work);
}
return 0;
}
static int32 jpg_msi_outbuff_full_isr(uint32 irq_flag, uint32 irq_data, uint32 param1, uint32 param2)
{
int8_t err = RET_OK;
struct msi *msi = (struct msi *) irq_data;
struct jpg_V3_msi_s *jpg_msg = (struct jpg_V3_msi_s *) msi->priv;
void *node;
uint16_t len;
if (jpg_msg->err)
{
goto jpg_msi_outbuff_full_isr_end;
}
node = get_jpg_node(&len);
if (!node)
{
err = RET_ERR;
goto jpg_msi_outbuff_full_isr_end;
}
jpg_set_addr(jpg_msg->jpg, (uint32) node, len);
ASSERT(jpg_msg->last_node);
// 放到链表里面(now_fb为head)
jpg_msg->use_last_node = push_node(jpg_msg->use_last_node, jpg_msg->last_node);
jpg_msg->last_node = node;
jpg_msi_outbuff_full_isr_end:
if (err != RET_OK)
{
jpg_msg->err |= MSI_JPG_BUF_FULL_ERR;
os_event_set(&jpg_msg->evt, MSI_JPG_BUF_FULL_ERR, NULL);
}
return 0;
}
static int32 jpg_msi_buf_err(uint32 irq_flag, uint32 irq_data, uint32 param1, uint32 param2)
{
struct msi *msi = (struct msi *) irq_data;
struct jpg_V3_msi_s *jpg_msg = (struct jpg_V3_msi_s *) msi->priv;
// 关闭jpg
jpg_close(jpg_msg->jpg);
// 唤醒workqueue?然后workqueue检查是不是有异常?有异常重新启动jpg?统一由外部线程去重新启动
os_event_set(&jpg_msg->evt, MSI_JPG_BUF_ERR, NULL);
os_run_work(&jpg_msg->work);
jpg_msg->err |= MSI_JPG_BUF_ERR;
_os_printf(KERN_ERR "JE");
return 0;
}
static uint32_t jpg_start_set_addr(struct jpg_V3_msi_s *jpg_msg)
{
uint16_t node_len;
void *node;
node = get_jpg_node(&node_len);
ASSERT(node);
jpg_set_addr(jpg_msg->jpg, (uint32) node, node_len);
jpg_msg->now_node = node;
jpg_msg->use_last_node = node;
node = get_jpg_node(&node_len);
ASSERT(node);
jpg_set_addr(jpg_msg->jpg, (uint32) node, node_len);
// 记录最后一个配置链表
jpg_msg->last_node = node;
return 0;
}
static uint8_t jpg_output(struct jpg_V3_msi_s *jpg_msg, void *node)
{
uint8_t ret = 0;
struct jpg_isr_msg *msg = (struct jpg_isr_msg *) get_node_rev(node, sizeof(struct jpg_isr_msg));
struct framebuff *fb = NULL;
struct framebuff *last_fb = NULL;
void *next_node = node;
struct framebuff *output_fb = NULL;
if (msg)
{
uint32_t jpg_len = msg->len;
uint32_t fb_len;
ASSERT(next_node);
while (next_node)
{
// 将node节点给到fb
next_node = pop_node(node);
fb_len = jpg_len > get_node_len(node) ? get_node_len(node) : jpg_len;
fb = fb_alloc(node, fb_len, F_JPG_NODE << 8 | msg->stype, jpg_msg->msi);
ASSERT(fb);
if (last_fb)
{
last_fb->next = fb;
}
else
{
output_fb = fb;
}
jpg_len -= fb_len;
last_fb = fb;
node = next_node;
}
struct jpg_node_s *jpg_priv = (struct jpg_node_s *) STREAM_LIBC_MALLOC(sizeof(struct jpg_node_s));
if (jpg_priv)
{
jpg_priv->w = msg->w;
jpg_priv->h = msg->h;
jpg_priv->jpg_len = msg->len;
output_fb->time = msg->time;
output_fb->datatag = msg->datatag;
output_fb->mtype = F_JPG_NODE;
output_fb->priv = jpg_priv;
output_fb->srcID = msg->srcID;
}
else
{
output_fb->priv = NULL;
}
msi_output_fb(jpg_msg->msi, output_fb);
}
else
{
return 1;
}
return ret;
}
static int32 jpg_msi_work(struct os_work *work)
{
struct jpg_V3_msi_s *jpg_msg = (struct jpg_V3_msi_s *) work;
void *node;
int32 err = -1;
uint32 jpg_err = 0;
os_event_wait(&jpg_msg->evt, MSI_JPG_DONE_ERR | MSI_JPG_BUF_FULL_ERR | MSI_JPG_BUF_ERR, &jpg_err, OS_EVENT_WMODE_OR | OS_EVENT_WMODE_CLEAR, 0);
node = (void *) os_msgq_get2(&jpg_msg->msgq, 0, &err);
if (err)
{
goto jpg_msi_work_end;
}
if (!jpg_output(jpg_msg, node))
{
}
// 异常,没有保留信息,只能释放
else
{
jpg_node_free(node);
}
jpg_msi_work_end:
// jpg异常,那么去重新启动一下jpg
// 需要先清除对应资源才行
if (jpg_err)
{
os_printf(KERN_ERR "jpg_err:%X\twhich:%d\n", jpg_err, jpg_msg->which);
jpg_free_res(jpg_msg);
jpg_start_set_addr(jpg_msg);
jpg_msg->err = 0;
jpg_msg->running = 1;
jpg_set_ready(jpg_msg->jpg);
jpg_open(jpg_msg->jpg);
}
return 0;
}
static int jpg_msi_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
{
int ret = RET_OK;
struct jpg_V3_msi_s *jpg_msg = (struct jpg_V3_msi_s *) msi->priv;
switch (cmd_id)
{
case MSI_CMD_POST_DESTROY:
{
os_msgq_del(&jpg_msg->msgq);
os_event_del(&jpg_msg->evt);
msi->name = NULL; // 这里比较特殊,正常不能清空的
STREAM_LIBC_FREE(jpg_msg);
}
break;
case MSI_CMD_PRE_DESTROY:
{
// 先关闭workqueue(防止有报错,将jpg重新启动)
os_work_cancle2(&jpg_msg->work, 1);
// 关闭jpg
if (jpg_msg->running)
{
jpg_close(jpg_msg->jpg);
jpg_msg->running = 0;
}
g_jpg_msi[jpg_msg->which] = NULL;
jpg_free_res(jpg_msg);
}
break;
case MSI_CMD_GET_RUNNING:
{
if (param1)
{
uint32_t running = 0;
if (jpg_msg->running && !jpg_msg->err)
{
running = 1;
}
*(uint32_t *) param1 = running;
}
}
break;
case MSI_CMD_HARDWARE_JPEG:
{
uint32_t cmd_self = (uint32_t) param1;
uint32_t arg = param2;
switch (cmd_self)
{
// 如果需要实现多个编码size,可能需要保存,然后通过中断自动切换
case MSI_JPEG_HARDWARE_MSG:
{
uint16_t w, h;
w = arg >> 16;
h = arg & 0xffff;
jpg_msg->w = w;
jpg_msg->h = h;
// jpg_set_size(jpg_msg->jpg, h, w);
}
break;
case MSI_JPEG_HARDWARE_START:
{
if (!jpg_msg->running)
{
OS_WORK_REINIT(&jpg_msg->work);
// 硬件初始化
jpg_init(jpg_msg->jpg, jpg_msg->dqtable_index, jpg_msg->qt);
jpg_set_size(jpg_msg->jpg, jpg_msg->h, jpg_msg->w);
if (jpg_msg->src_from == VPP_DATA0 || jpg_msg->src_from == VPP_DATA1)
{
jpg_msg->vpp_close_flag = 1;
}
jpg_set_data_from(jpg_msg->jpg, jpg_msg->src_from);
jpg_set_hw_check(jpg_msg->jpg, 1);
// 注册中断
jpg_request_irq(jpg_msg->jpg, jpg_msi_outbuff_full_isr, JPG_IRQ_FLAG_JPG_BUF_FULL, msi);
jpg_request_irq(jpg_msg->jpg, jpg_msi_buf_err, JPG_IRQ_FLAG_ERROR, msi);
jpg_request_irq(jpg_msg->jpg, jpg_msi_done_isr, JPG_IRQ_FLAG_JPG_DONE, msi);
jpg_set_ready(jpg_msg->jpg);
jpg_set_vsync_dly(jpg_msg->jpg, 1);
jpg_select_oe_using(jpg_msg->jpg, 0, 1);
jpg_start_set_addr(jpg_msg);
os_event_wait(&jpg_msg->evt, MSI_SCALE1_DATA0_DATA1_CLOSE, NULL, OS_EVENT_WMODE_OR | OS_EVENT_WMODE_CLEAR, 0);
jpg_msg->running = 1;
jpg_open(jpg_msg->jpg);
}
else
{
}
}
break;
case MSI_JPEG_HARDWARE_STOP:
{
if (jpg_msg->running)
{
os_work_cancle2(&jpg_msg->work, 1);
if (jpg_msg->scale1_flag)
{
jpg_msg->scale1_flag = 0;
scale_close(jpg_msg->scale_dev);
jpg_close(jpg_msg->jpg);
}
else if (jpg_msg->vpp_close_flag)
{
jpg_msg->vpp_close_flag = 0;
jpg_close(jpg_msg->jpg);
}
else
{
jpg_close(jpg_msg->jpg);
}
jpg_msg->running = 0;
jpg_msg->err = 0;
// 清除异常
os_event_wait(&jpg_msg->evt, MSI_JPG_DONE_ERR | MSI_JPG_BUF_FULL_ERR | MSI_JPG_BUF_ERR, NULL, OS_EVENT_WMODE_OR | OS_EVENT_WMODE_CLEAR, 0);
// 需要清理一下队列?这个时候队列的数据应该是不需要了以及now_fb的数据也要清除
{
void *node;
int32 err = 0;
// 将队列的数据帮忙发送出去
while (!err)
{
node = (struct framebuff *) os_msgq_get2(&jpg_msg->msgq, 0, &err);
if (!err)
{
if (!jpg_output(jpg_msg, node))
{
}
// 异常,没有保留信息,只能释放
else
{
jpg_node_free(node);
}
}
}
}
jpg_free_res(jpg_msg);
}
else
{
os_work_cancle2(&jpg_msg->work, 1);
}
}
break;
case MSI_JPEG_HARDWARE_FROM:
{
if (arg >= VPP_DATA0 && arg <= SOFT_DATA)
{
jpg_msg->src_from = arg;
// jpg_set_data_from(jpg_msg->jpg, arg);
}
else
{
os_printf(KERN_ERR "jpg set data from err:%d\n", arg);
}
}
break;
// 配置gen42的类型
case MSI_JPEG_HARDWARE_SET_GEN420_TYPE:
{
jpg_msg->gen420_type = arg;
}
break;
case MSI_JPEG_HARDWARE_SET_SCALE1_TYPE:
{
jpg_msg->scale1_type = arg;
}
break;
case MSI_JPEG_SET_TIME:
{
jpg_msg->set_time = arg;
}
break;
case MSI_JPEG_SET_LEN:
{
jpg_msg->target_len = arg;
}
break;
case MSI_JPEG_SET_SCALE1_FLAG:
{
jpg_msg->scale1_flag = arg;
}
break;
default:
break;
}
}
break;
case MSI_CMD_FREE_FB:
{
struct framebuff *fb = (struct framebuff *) param1;
if (fb->data)
{
free_jpg_node((void *) fb->data);
fb->data = NULL;
}
if (fb->priv)
{
STREAM_LIBC_FREE(fb->priv);
fb->priv = NULL;
}
}
break;
case MSI_CMD_SET_DATATAG:
{
uint8_t datatag = (uint8_t) param1;
jpg_msg->datatag = datatag;
}
break;
}
return ret;
}
// 这个接口尽量不在外部调用,因为硬件只有一个
// 所以由中间流对这个硬件控制
struct msi *hardware_jpg_msi(uint8_t which_jpg, uint8_t src_from, uint16_t jpg_node_len, uint16_t jpg_node_count)
{
if (which_jpg >= HARDWARE_JPG_NUM)
{
return NULL;
}
// 硬件只有一个,所以只能启动一次,外部显式调用一次msi_destroy才可以
if (g_jpg_msi[which_jpg])
{
// 先将硬件关闭,然后重新创建吧
// struct msi *old_msi = g_jpg_msi[which_jpg];
// msi_destroy(old_msi);
return NULL;
}
struct jpg_V3_msi_s *jpg_msg = (struct jpg_V3_msi_s *) STREAM_LIBC_ZALLOC(sizeof(struct jpg_V3_msi_s));
struct msi *msi = NULL;
uint8_t isnew = 0;
if (jpg_msg)
{
os_sprintf(jpg_msg->msi_name, "H_JPG%d_%08X", which_jpg, (uint32) os_jiffies() & 0xFFFFFFFF);
msi = msi_new(jpg_msg->msi_name, 0, &isnew);
ASSERT(msi);
// 这里一定是新创建
ASSERT(isnew);
msi->priv = (void *) jpg_msg;
jpg_msg->which = which_jpg;
jpg_msg->src_from = src_from;
jpg_msg->qt = 0xf;
// 这里式分配多少帧,如果分配1帧,就是应用要快速去处理,否则可能来不及
// 如果帧数据量大,就可能出现最后节点不够的可能
os_msgq_init(&jpg_msg->msgq, 1);
os_event_init(&jpg_msg->evt);
if (msi)
{
jpg_msg->msi = msi;
// 固定输出,外部尽量不要用这个msi,统一给到RS_JPG_CONCAT这个msi去管理
jpg_msg->jpg = (struct jpg_device *) dev_get(which_jpg + HG_JPG0_DEVID);
jpg_msg->scale_dev = (struct scale_device *) dev_get(HG_SCALE1_DEVID);
jpg_close(jpg_msg->jpg);
jpg_msg->dqtable_index = DQT_DEF;
jpg_msg->target_len = TARGET_JPG_LEN;
jpg_msg->qt = 0xf;
msi->action = jpg_msi_action;
msi->enable = 1;
// 启动一个workqueue,去将fb发送出去,中断唤醒一次,workqueue执行一次
OS_WORK_INIT(&jpg_msg->work, jpg_msi_work, 0);
}
}
if (!msi)
{
if (jpg_msg)
{
STREAM_LIBC_FREE(jpg_msg);
}
}
else
{
g_jpg_msi[which_jpg] = msi;
}
return msi;
}
void jpg_mem_init(int num)
{
add_jpg_block(num);
return;
}
#endif
#else
struct msi *hardware_jpg_msi(uint8_t which_jpg, uint8_t src_from, uint16_t jpg_node_len, uint16_t jpg_node_count)
{
return NULL;
}
#endif