#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