249 lines
8.7 KiB
C
249 lines
8.7 KiB
C
|
|
#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;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|