Initial commit: TXW82x FPV v2.7.0.7-42229 SDK + project sources
This commit is contained in:
249
sdk/app/video_app/video_app_csc_msi.c
Normal file
249
sdk/app/video_app/video_app_csc_msi.c
Normal file
@@ -0,0 +1,249 @@
|
||||
#include "basic_include.h"
|
||||
#include "video_app_csc_msi.h"
|
||||
#include "stream_define.h"
|
||||
#include "lib/heap/av_heap.h"
|
||||
#include "lib/heap/av_psram_heap.h"
|
||||
#include "lib/multimedia/msi.h"
|
||||
#include "user_work/user_work.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
|
||||
|
||||
#define CSC_MSI_RX_NUM 2
|
||||
#define CSC_MSI_TX_NUM 2
|
||||
|
||||
struct video_app_csc_priv
|
||||
{
|
||||
struct os_work work;
|
||||
struct csc_device* csc_dev;
|
||||
struct msi* msi;
|
||||
struct fbpool tx_pool;
|
||||
uint8_t hardware_ready : 1,
|
||||
wait_irq_done : 1,
|
||||
rev : 6;
|
||||
uint32_t input_format;
|
||||
uint32_t output_format;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
struct framebuff* current_rx_fb;
|
||||
struct framebuff* current_tx_fb;
|
||||
};
|
||||
typedef struct video_app_csc_priv* video_app_csc_priv_t;
|
||||
|
||||
static int32_t video_app_csc_msi_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
|
||||
{
|
||||
int32_t ret = RET_OK;
|
||||
video_app_csc_priv_t csc_priv = (video_app_csc_priv_t)msi->priv;
|
||||
switch (cmd_id)
|
||||
{
|
||||
case MSI_CMD_POST_DESTROY:
|
||||
{
|
||||
if(csc_priv) {
|
||||
struct framebuff *fb = NULL;
|
||||
while (1)
|
||||
{
|
||||
fb = fbpool_get(&csc_priv->tx_pool, 0, NULL);
|
||||
if (!fb) {
|
||||
break;
|
||||
}
|
||||
if (fb->data) {
|
||||
STREAM_FREE(fb->data);
|
||||
fb->data = NULL;
|
||||
}
|
||||
if (fb->priv) {
|
||||
STREAM_LIBC_FREE(fb->priv);
|
||||
fb->priv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fbpool_destroy(&csc_priv->tx_pool);
|
||||
STREAM_LIBC_FREE(csc_priv);
|
||||
msi->priv = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MSI_CMD_PRE_DESTROY:
|
||||
{
|
||||
os_work_cancle2(&csc_priv->work, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case MSI_CMD_TRANS_FB:
|
||||
{
|
||||
struct framebuff *fb = (struct framebuff *)param1;
|
||||
if (fb->srcID != FRAMEBUFF_SOURCE_CSC) {
|
||||
ret = RET_OK + 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MSI_CMD_FREE_FB:
|
||||
{
|
||||
struct framebuff *fb = (struct framebuff *)param1;
|
||||
fbpool_put(&csc_priv->tx_pool, fb);
|
||||
// 不需要内核去释放fb
|
||||
ret = RET_OK + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case MSI_CMD_CSC:
|
||||
{
|
||||
uint32_t cmd_self = (uint32_t)param1;
|
||||
uint32_t arg = param2;
|
||||
switch (cmd_self)
|
||||
{
|
||||
case MSI_CSC_MSI_ENABLE:
|
||||
{
|
||||
csc_priv->msi->enable = arg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void csc_irq_done(uint32 irq_flag, uint32 irq_data, uint32 param1)
|
||||
{
|
||||
video_app_csc_priv_t csc_priv = (video_app_csc_priv_t)irq_data;
|
||||
csc_priv->hardware_ready = 1;
|
||||
}
|
||||
|
||||
static int32 video_app_csc_msi_work(struct os_work *work)
|
||||
{
|
||||
video_app_csc_priv_t csc_priv = (video_app_csc_priv_t)work;
|
||||
|
||||
if (csc_priv->hardware_ready) {
|
||||
|
||||
if (csc_priv->wait_irq_done) {
|
||||
csc_priv->current_tx_fb->time = os_jiffies();
|
||||
msi_output_fb(csc_priv->msi, csc_priv->current_tx_fb);
|
||||
msi_delete_fb(csc_priv->msi, csc_priv->current_rx_fb);
|
||||
csc_priv->current_tx_fb = NULL;
|
||||
csc_priv->current_rx_fb = NULL;
|
||||
csc_priv->wait_irq_done = 0;
|
||||
}
|
||||
|
||||
if (!csc_priv->current_rx_fb) {
|
||||
csc_priv->current_rx_fb = msi_get_fb(csc_priv->msi, 0);
|
||||
if (!csc_priv->current_rx_fb) {
|
||||
goto __video_app_csc_msi_work_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (csc_priv->current_rx_fb) {
|
||||
|
||||
if (!csc_priv->current_tx_fb) {
|
||||
csc_priv->current_tx_fb = fbpool_get(&csc_priv->tx_pool, 0, csc_priv->msi);
|
||||
if (!csc_priv->current_tx_fb) {
|
||||
goto __video_app_csc_msi_work_end;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *csc_input_addr = csc_priv->current_rx_fb->data;
|
||||
uint8_t *csc_output_addr = csc_priv->current_tx_fb->data;
|
||||
|
||||
csc_priv->hardware_ready = 0;
|
||||
csc_priv->wait_irq_done = 1;
|
||||
csc_priv->current_tx_fb->mtype = F_YUV;
|
||||
csc_priv->current_tx_fb->stype = FSTYPE_YUV_P0;
|
||||
csc_priv->current_tx_fb->srcID = FRAMEBUFF_SOURCE_CSC;
|
||||
|
||||
struct yuv_arg_s * yuv_msg = csc_priv->current_tx_fb->priv;
|
||||
|
||||
yuv_msg->y_size = csc_priv->width*csc_priv->height;
|
||||
yuv_msg->uv_off = 0;
|
||||
yuv_msg->y_off = 0;
|
||||
yuv_msg->x = 0;
|
||||
yuv_msg->y = 0;
|
||||
yuv_msg->out_w = csc_priv->width;
|
||||
yuv_msg->out_h = csc_priv->height;
|
||||
|
||||
csc_init(csc_priv->csc_dev);
|
||||
csc_set_type(csc_priv->csc_dev, 2); /* RGB -> YUV */
|
||||
csc_set_photo_size(csc_priv->csc_dev, csc_priv->width, csc_priv->height);
|
||||
csc_set_format(csc_priv->csc_dev, csc_priv->input_format, csc_priv->output_format); /* RGB565 -> YUV420P */
|
||||
csc_set_input_addr(csc_priv->csc_dev, (uint32_t)csc_input_addr, 0, 0);
|
||||
csc_set_output_addr(csc_priv->csc_dev, \
|
||||
(uint32_t)(csc_output_addr), \
|
||||
(uint32_t)(csc_output_addr + csc_priv->width * csc_priv->height), \
|
||||
(uint32_t)(csc_output_addr + csc_priv->width * csc_priv->height + csc_priv->width * csc_priv->height / 4));
|
||||
csc_start_run(csc_priv->csc_dev);
|
||||
}
|
||||
} else {
|
||||
/* 转换未完成,直接退出 */
|
||||
}
|
||||
|
||||
__video_app_csc_msi_work_end:
|
||||
os_run_work_delay(&csc_priv->work, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 目前 CSC 数据流仅用在 LVGL 由 RGB565 -> YUV420P -> VIDEO P0 的通路上 */
|
||||
void video_app_csc_msi_init(const char* csc_msi_name, uint32_t input_format, uint32_t output_format, uint32_t width, uint32_t height)
|
||||
{
|
||||
struct msi *msi = NULL;
|
||||
|
||||
video_app_csc_msi_init_start:
|
||||
msi = msi_new(csc_msi_name, CSC_MSI_RX_NUM, NULL);
|
||||
if (!msi) {
|
||||
return ;
|
||||
}
|
||||
|
||||
video_app_csc_priv_t csc_priv = (video_app_csc_priv_t)msi->priv;
|
||||
|
||||
if (!csc_priv)
|
||||
{
|
||||
csc_priv = (video_app_csc_priv_t)STREAM_LIBC_ZALLOC(sizeof(struct video_app_csc_priv));
|
||||
msi->priv = (void *)csc_priv;
|
||||
msi->action = (msi_action)video_app_csc_msi_action;
|
||||
|
||||
csc_priv->csc_dev = (struct csc_device *)dev_get(HG_CSC_DEVID);
|
||||
csc_priv->msi = msi;
|
||||
csc_priv->input_format = input_format;
|
||||
csc_priv->output_format = output_format;
|
||||
csc_priv->width = width;
|
||||
csc_priv->height = height;
|
||||
csc_priv->hardware_ready = 1;
|
||||
fbpool_init(&csc_priv->tx_pool, CSC_MSI_TX_NUM);
|
||||
|
||||
for(int i = 0; i < CSC_MSI_TX_NUM; i++) {
|
||||
/* 预分配 CSC 输出的 YUV420P 格式的空间 */
|
||||
uint8_t *csc_output_addr = (uint8_t*)STREAM_MALLOC(csc_priv->width*csc_priv->height*3/2);
|
||||
if (!csc_output_addr) {
|
||||
return ;
|
||||
}
|
||||
sys_dcache_invalid_range((uint32_t*)csc_output_addr, csc_priv->width*csc_priv->height*3/2);
|
||||
|
||||
struct yuv_arg_s * yuv_msg = (struct yuv_arg_s *)STREAM_LIBC_ZALLOC(sizeof(struct yuv_arg_s));
|
||||
if (!yuv_msg) {
|
||||
return ;
|
||||
}
|
||||
|
||||
FBPOOL_SET_INFO(&csc_priv->tx_pool, i, csc_output_addr, csc_priv->width*csc_priv->height*3/2, yuv_msg);
|
||||
}
|
||||
|
||||
csc_request_irq(csc_priv->csc_dev, CSC_DONE_IRQ, (csc_irq_hdl )&csc_irq_done, (uint32)csc_priv);
|
||||
|
||||
OS_WORK_INIT(&csc_priv->work, video_app_csc_msi_work, 0);
|
||||
os_run_work_delay(&csc_priv->work, 1);
|
||||
|
||||
msi->enable = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
msi->name = NULL;
|
||||
msi_destroy(msi);
|
||||
os_sleep_ms(1);
|
||||
goto video_app_csc_msi_init_start;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user