Files
TAIXIN/sdk/app/video_app/auto_jpg_msi.c

232 lines
8.2 KiB
C

#include "basic_include.h"
#include "lib/multimedia/msi.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 "stream_define.h"
#include "user_work/user_work.h"
#include "lib/video/dvp/jpeg/jpg_common.h"
#include "lib/video/vpp/vpp_dev.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
#ifdef JPG_NODE_COUNT
#define AUTO_JPG_COUNT JPG_NODE_COUNT
#else
#define AUTO_JPG_COUNT 10
#endif
extern uint8_t get_vpp_scale_w_h(uint16_t *w, uint16_t *h);
struct auto_jpg_msi_s
{
struct os_work work;
struct msi *msi;
struct msi *register_jpg_msi; // 注册的jpg的msi
uint16_t w, h;
uint8_t src_from : 3, stop : 1, which_jpg : 1, rev : 3;
};
static int32 auto_jpg_work(struct os_work *work)
{
uint8_t last_value;
int32_t ret;
uint8_t delay_time = 40;
uint8_t stop = 0;
struct auto_jpg_msi_s *auto_jpg = (struct auto_jpg_msi_s *) work;
// 这里尝试发送数据?检查一下是否有接收的msi,如果有接收的msi,则启动mjpeg,如果没有,则将硬件停下来?
uint32_t send_count = msi_output_fb(auto_jpg->msi, NULL);
// 代表有需要接收的数据流,那么就要启动硬件,尝试获取锁,然后启动mjpg,如果上一次锁是mjpg,就不需要重新启动
if (send_count)
{
// 尝试查看是否已经停止过
ret = jpg_mutex_lock(auto_jpg->which_jpg, JPG_LOCK_ENCODE, &last_value);
// 获取到锁,并且锁的值不一致,则要重新去启动mjpeg
if (ret == 0)
{
// 如果锁的值不一致,代表该mjpg被其他地方使用过了,需要重新启动
// 如果锁的值一致,但是stop == 1,代表已经停止过了,也需要重新启动
if (last_value != JPG_LOCK_ENCODE || auto_jpg->stop == 1)
{
// 关闭mjpeg
if (auto_jpg->src_from == SCALER_DATA)
{
ret = get_vpp_scale_w_h(&auto_jpg->w, &auto_jpg->h);
if (!ret)
{
msi_do_cmd(auto_jpg->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_START, 0);
msi_do_cmd(auto_jpg->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_NODE_COUNT, AUTO_JPG_COUNT);
set_vpp_scale_w_h(1, auto_jpg->w, auto_jpg->h);
msi_do_cmd(auto_jpg->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_SET_SCALE1_TYPE, 0);
msi_do_cmd(auto_jpg->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_SET_SCALE1_AUTO_FLAG, 1);
msi_do_cmd(auto_jpg->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_MSG, auto_jpg->w << 16 | auto_jpg->h);
}
else
{
stop = 1;
}
}
else
{
msi_do_cmd(auto_jpg->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_START, 0);
msi_do_cmd(auto_jpg->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_NODE_COUNT, AUTO_JPG_COUNT);
}
if (!stop)
{
// 切回到默认源头
msi_do_cmd(auto_jpg->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_FROM, auto_jpg->src_from);
// 重新启动mjpg
msi_do_cmd(auto_jpg->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_START, 1);
auto_jpg->stop = 0;
}
}
// 解锁,可以被其他线程打断使用,因为这个是从VPP_DATA0,可以被其他线程打断使用完再恢复,
// 这样只是丢部分帧,但是可以复用mjpg
jpg_mutex_unlock(auto_jpg->which_jpg, JPG_LOCK_ENCODE);
}
// 没有获取到锁,就延时一点时间后,继续获取
else
{
delay_time = 5;
}
}
else if (send_count == 0)
{
if (auto_jpg->stop == 0)
{
ret = jpg_mutex_lock(auto_jpg->which_jpg, JPG_LOCK_ENCODE, &last_value);
if (ret == 0)
{
// 如果锁的值一致,那么就要主动停止,因为已经在启动了
if (last_value == JPG_LOCK_ENCODE)
{
msi_do_cmd(auto_jpg->register_jpg_msi, MSI_CMD_JPEG_CONCAT, MSI_JPEG_START, 0);
}
jpg_mutex_unlock_check(auto_jpg->which_jpg, JPG_LOCK_ENCODE);
}
auto_jpg->stop = 1;
}
}
os_run_work_delay(work, delay_time);
return 0;
}
static int32_t auto_jpg_msi_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
{
int32_t ret = RET_OK;
struct auto_jpg_msi_s *auto_jpg = (struct auto_jpg_msi_s *) msi->priv;
switch (cmd_id)
{
case MSI_CMD_POST_DESTROY:
{
os_work_cancle2(&auto_jpg->work, 1);
STREAM_LIBC_FREE(auto_jpg);
}
break;
case MSI_CMD_PRE_DESTROY:
{
os_work_cancle2(&auto_jpg->work, 1);
if (auto_jpg->register_jpg_msi)
{
msi_destroy(auto_jpg->register_jpg_msi);
auto_jpg->register_jpg_msi = NULL;
}
}
break;
case MSI_CMD_AUTO_JPG:
{
uint32_t cmd_self = (uint32_t) param1;
uint32_t arg = param2;
switch (cmd_self)
{
// 切换数据源
case MSI_AUTO_JPG_SWITCH_ENCODE_SRC:
{
auto_jpg->src_from = arg;
auto_jpg->stop = 1;
}
break;
default:
break;
}
}
break;
case MSI_CMD_TRANS_FB:
{
struct framebuff *fb = (struct framebuff *) param1;
// 如果是mjpeg,帮忙转发到其他数据流
// 如果需要支持264,也要帮忙转发
if (fb->mtype == F_JPG)
{
// 类型匹配才可以转发
if (fb->stype == FSTYPE_VIDEO_VPP_DATA0 + auto_jpg->src_from)
{
_os_printf("+");
struct framebuff *fb = (struct framebuff *) param1;
fb_get(fb);
msi_output_fb(msi, fb);
}
ret = RET_OK + 1;
break;
}
}
break;
default:
break;
}
return ret;
}
struct msi *auto_jpg_msi_init(const char *auto_jpg_name, uint8_t which_jpg, uint8_t src_from)
{
uint8_t isnew;
struct msi *msi = NULL;
msi = msi_new(auto_jpg_name, 0, &isnew);
struct auto_jpg_msi_s *auto_jpg = (struct auto_jpg_msi_s *) msi->priv;
if (isnew)
{
auto_jpg = (struct auto_jpg_msi_s *) STREAM_LIBC_ZALLOC(sizeof(struct auto_jpg_msi_s));
msi->priv = (void *) auto_jpg;
msi->action = auto_jpg_msi_action;
auto_jpg->msi = msi;
auto_jpg->src_from = src_from;
auto_jpg->stop = 1;
auto_jpg->which_jpg = which_jpg;
auto_jpg->w = 0;
auto_jpg->h = 0;
// w和h在vpp_data0和vpp_data1的时候是没有作用的
auto_jpg->register_jpg_msi = jpg_concat_msi_init_start(auto_jpg->which_jpg, 0, 0, NULL, auto_jpg->src_from, 0);
if (auto_jpg->register_jpg_msi)
{
msi_add_output(auto_jpg->register_jpg_msi, NULL, msi->name);
}
else
{
msi_destroy(msi);
msi = NULL;
goto auto_jpg_msi_init_end;
}
msi->enable = 1;
// 启动workqueue
OS_WORK_INIT(&auto_jpg->work, auto_jpg_work, 0);
os_run_work(&auto_jpg->work);
}
auto_jpg_msi_init_end:
return msi;
}