344 lines
10 KiB
C
344 lines
10 KiB
C
/*******************************************************************************************************
|
|
* 该文件主要是为了给jpeg配置需要解码的信息,然后传递给到硬件解码
|
|
******************************************************************************************************/
|
|
#include "sys_config.h"
|
|
#include "typesdef.h"
|
|
#include "dev.h"
|
|
#include "devid.h"
|
|
#include "stream_frame.h"
|
|
#include "utlist.h"
|
|
#include "osal/task.h"
|
|
#include "osal/string.h"
|
|
#include "osal/work.h"
|
|
#include "osal_file.h"
|
|
#include "jpgdef.h"
|
|
#include "utlist.h"
|
|
#include "basic_include.h"
|
|
#include "lib/multimedia/msi.h"
|
|
#include "stream_define.h"
|
|
#include "lib/heap/av_heap.h"
|
|
#include "lib/heap/av_psram_heap.h"
|
|
#include "user_work/user_work.h"
|
|
|
|
// 获取jpeg的w和h,没有做太多容错,所以尽量给的是正确的jpeg,否则可能异常
|
|
#define GET_16(p) (((p)[0] << 8) | (p)[1])
|
|
|
|
static int parse_SOF(uint8_t *d, uint32_t *w, uint32_t *h)
|
|
{
|
|
if (d[0] != 8)
|
|
{
|
|
printf("Invalid precision %d in SOF0\n", d[0]);
|
|
return -1;
|
|
}
|
|
*h = GET_16(d + 1);
|
|
*w = GET_16(d + 3);
|
|
return 0;
|
|
}
|
|
|
|
static int parse_jpg(uint8_t *jpg_buf, uint32_t maxsize, uint32_t *w, uint32_t *h)
|
|
{
|
|
uint8_t *buf = jpg_buf;
|
|
uint8_t EOI_flag = 0;
|
|
uint32_t i = 0;
|
|
int res = 1;
|
|
int blen = 0;
|
|
for (i = 0; i < maxsize; i += blen + 2)
|
|
{
|
|
if (buf[i] != 0xFF)
|
|
{
|
|
printf("Found %02X at %d, expecting FF\n", buf[i], i);
|
|
goto parse_jpg_end;
|
|
}
|
|
while (buf[i + 1] == 0xFF)
|
|
{
|
|
++i;
|
|
}
|
|
if (buf[i + 1] == 0xD8)
|
|
{
|
|
blen = 0;
|
|
}
|
|
else
|
|
{
|
|
blen = GET_16(buf + i + 2);
|
|
}
|
|
|
|
switch (buf[i + 1])
|
|
{
|
|
case 0xDB: /* Quantization Table */
|
|
break;
|
|
case 0xC0: /* Start of Frame */
|
|
parse_SOF(buf + i + 4, w, h);
|
|
res = 0;
|
|
// printf("w:%d\th:%d\n",*w,*h);
|
|
break;
|
|
case 0xC4: /* Huffman Table */
|
|
|
|
break;
|
|
case 0xDD: /* DRI */
|
|
break;
|
|
case 0xDA: /* Start of Scan */
|
|
goto parse_jpg_end;
|
|
}
|
|
}
|
|
|
|
parse_jpg_end:
|
|
|
|
if (!res)
|
|
{
|
|
for (i = maxsize - 1; i >= maxsize - 16; i--)
|
|
{
|
|
if (buf[i] != 0xFF)
|
|
{
|
|
// os_printf("EOI Found %02X at %d, expecting FF\n", buf[i], i);
|
|
continue;
|
|
}
|
|
|
|
if ((i < maxsize - 1) && (buf[i + 1] == 0xD9))
|
|
{
|
|
EOI_flag = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((!res) && (!EOI_flag))
|
|
{
|
|
res = 1;
|
|
os_printf("EOI No found FF D9\n");
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
int ex_parse_jpg(uint8_t *jpg_buf, uint32_t maxsize, uint32_t *w, uint32_t *h)
|
|
{
|
|
return parse_jpg(jpg_buf, maxsize, w, 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
|
|
|
|
struct jpg_decode_msg_s
|
|
{
|
|
struct os_work work;
|
|
struct msi *msi;
|
|
struct framebuff *rfb;
|
|
uint32_t magic; // 会赋值到对应参数,用于后续msi的识别,如果为0,就是没有任何处理
|
|
uint16_t out_w;
|
|
uint16_t out_h;
|
|
uint16_t step_w;
|
|
uint16_t step_h;
|
|
uint16_t x, y; // 解码配置的x和y,如果没有可以不配置
|
|
uint16_t force_type; // 强转类型(统一将解码的类型修改,不按照filter,0是无效)
|
|
uint8_t filter; // 过滤解码的类型
|
|
uint8_t ish264;
|
|
};
|
|
|
|
static int32 jpg_decode_msg_work(struct os_work *work)
|
|
{
|
|
struct jpg_decode_msg_s *decode_msg = (struct jpg_decode_msg_s *) work;
|
|
struct framebuff *rfb;
|
|
struct framebuff *fb;
|
|
int res;
|
|
if (decode_msg->rfb)
|
|
{
|
|
rfb = decode_msg->rfb;
|
|
// 这里可以考虑用自己的内存管理,后续看情况修改接口
|
|
fb = fb_alloc(NULL, sizeof(struct jpg_decode_arg_s), 0, decode_msg->msi);
|
|
// 申请不到就等下次进来再去尝试解码吧
|
|
if (fb)
|
|
{
|
|
fb_ref(fb, rfb);
|
|
fb->datatag = rfb->datatag;
|
|
fb->stype = rfb->stype;
|
|
fb->srcID = rfb->srcID;
|
|
struct jpg_decode_arg_s *msg = (struct jpg_decode_arg_s *) fb->data;
|
|
struct yuv_arg_s *yuv_msg = &msg->yuv_arg;
|
|
memset(msg, 0, sizeof(struct jpg_decode_arg_s));
|
|
yuv_msg->out_w = decode_msg->out_w;
|
|
yuv_msg->out_h = decode_msg->out_h;
|
|
yuv_msg->x = decode_msg->x;
|
|
yuv_msg->y = decode_msg->y;
|
|
yuv_msg->magic = decode_msg->magic;
|
|
yuv_msg->dispcnt = fb->datatag;
|
|
// os_printf("yuv_msg->dispcnt:%d\n",yuv_msg->dispcnt);
|
|
msg->step_w = decode_msg->step_w;
|
|
msg->step_h = decode_msg->step_h;
|
|
|
|
if (rfb->mtype == F_H264)
|
|
{
|
|
struct fb_h264_s *h264_priv = (struct fb_h264_s *) rfb->priv;
|
|
res = 0;
|
|
msg->decode_w = h264_priv->w;
|
|
msg->decode_h = h264_priv->h;
|
|
}
|
|
else if (rfb->mtype == F_JPG)
|
|
{
|
|
res = parse_jpg(rfb->data, rfb->len, &msg->decode_w, &msg->decode_h);
|
|
}
|
|
else
|
|
{
|
|
res = 1;
|
|
}
|
|
if (!res)
|
|
{
|
|
fb->mtype = F_JPG_DECODE_MSG;
|
|
fb->stype = decode_msg->force_type ? decode_msg->force_type : rfb->stype;
|
|
fb->time = rfb->time;
|
|
msi_output_fb(decode_msg->msi, fb);
|
|
msi_delete_fb(NULL, rfb);
|
|
decode_msg->rfb = NULL;
|
|
}
|
|
else
|
|
{
|
|
msi_delete_fb(NULL, fb);
|
|
msi_delete_fb(NULL, rfb);
|
|
decode_msg->rfb = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
decode_msg->rfb = msi_get_fb(decode_msg->msi, 0);
|
|
}
|
|
os_run_work_delay(work, 1);
|
|
return 0;
|
|
}
|
|
|
|
static int32_t decode_msg_msi_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
|
|
{
|
|
int32_t ret = RET_OK;
|
|
struct jpg_decode_msg_s *decode_msg = (struct jpg_decode_msg_s *) msi->priv;
|
|
switch (cmd_id)
|
|
{
|
|
|
|
// 这里msi已经被删除,那么就要考虑tx_pool的资源释放了
|
|
// 能进来这里,就是代表所有fb都已经用完了
|
|
case MSI_CMD_POST_DESTROY:
|
|
{
|
|
os_work_cancle2(&decode_msg->work, 1);
|
|
STREAM_LIBC_FREE(decode_msg);
|
|
}
|
|
break;
|
|
|
|
case MSI_CMD_PRE_DESTROY:
|
|
{
|
|
os_work_cancle2(&decode_msg->work, 1);
|
|
}
|
|
break;
|
|
|
|
case MSI_CMD_DECODE_JPEG_MSG:
|
|
{
|
|
uint32_t cmd_self = (uint32_t) param1;
|
|
uint32_t arg = param2;
|
|
switch (cmd_self)
|
|
{
|
|
case MSI_JPEG_DECODE_X_Y:
|
|
{
|
|
decode_msg->x = arg >> 16;
|
|
decode_msg->y = arg & 0xffff;
|
|
}
|
|
break;
|
|
|
|
// 配置强转类型
|
|
case MSI_JPEG_DECODE_FORCE_TYPE:
|
|
{
|
|
decode_msg->force_type = arg;
|
|
}
|
|
break;
|
|
|
|
case MSI_JPEG_DECODE_MAGIC:
|
|
{
|
|
decode_msg->magic = arg;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case MSI_CMD_TRANS_FB:
|
|
{
|
|
struct framebuff *fb = (struct framebuff *) param1;
|
|
|
|
if (decode_msg->ish264)
|
|
{
|
|
if (fb->mtype != F_H264)
|
|
{
|
|
ret = RET_OK + 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (fb->mtype != F_JPG)
|
|
{
|
|
ret = RET_OK + 1;
|
|
}
|
|
}
|
|
if (decode_msg->filter && !(decode_msg->filter == fb->stype))
|
|
{
|
|
ret = RET_OK + 1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
struct msi *jpg_decode_msg_msi(const char *name, uint16_t out_w, uint16_t out_h, uint16_t step_w, uint16_t step_h, uint32_t filter)
|
|
{
|
|
struct msi *msi = msi_new(name, 8, NULL);
|
|
struct jpg_decode_msg_s *decode_msg = (struct jpg_decode_msg_s *) msi->priv;
|
|
if (!decode_msg)
|
|
{
|
|
decode_msg = (struct jpg_decode_msg_s *) STREAM_LIBC_ZALLOC(sizeof(struct jpg_decode_msg_s));
|
|
msi->priv = (void *) decode_msg;
|
|
msi->action = decode_msg_msi_action;
|
|
decode_msg->msi = msi;
|
|
decode_msg->out_w = out_w;
|
|
decode_msg->out_h = out_h;
|
|
decode_msg->step_w = step_w;
|
|
decode_msg->step_h = step_h;
|
|
decode_msg->filter = filter;
|
|
decode_msg->rfb = NULL;
|
|
decode_msg->ish264 = 0;
|
|
msi->enable = 1;
|
|
// 启动workqueue
|
|
OS_WORK_INIT(&decode_msg->work, jpg_decode_msg_work, 0);
|
|
os_run_work_delay(&decode_msg->work, 1);
|
|
}
|
|
|
|
return msi;
|
|
}
|
|
|
|
struct msi *h264_decode_msg_msi(const char *name, uint16_t out_w, uint16_t out_h, uint16_t step_w, uint16_t step_h, uint32_t filter)
|
|
{
|
|
struct msi *msi = msi_new(name, 8, NULL);
|
|
struct jpg_decode_msg_s *decode_msg = (struct jpg_decode_msg_s *) msi->priv;
|
|
if (!decode_msg)
|
|
{
|
|
decode_msg = (struct jpg_decode_msg_s *) STREAM_LIBC_ZALLOC(sizeof(struct jpg_decode_msg_s));
|
|
msi->priv = (void *) decode_msg;
|
|
msi->action = decode_msg_msi_action;
|
|
decode_msg->msi = msi;
|
|
decode_msg->out_w = out_w;
|
|
decode_msg->out_h = out_h;
|
|
decode_msg->step_w = step_w;
|
|
decode_msg->step_h = step_h;
|
|
decode_msg->filter = filter;
|
|
decode_msg->rfb = NULL;
|
|
decode_msg->ish264 = 0;
|
|
decode_msg->ish264 = 1;
|
|
msi->enable = 1;
|
|
// 启动workqueue
|
|
OS_WORK_INIT(&decode_msg->work, jpg_decode_msg_work, 0);
|
|
os_run_work_delay(&decode_msg->work, 1);
|
|
}
|
|
|
|
return msi;
|
|
} |