2025-02-27 17:59:18 +08:00

1262 lines
33 KiB
C
Executable File

// Copyright 2023-2024 Beken
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <os/os.h>
#include <os/mem.h>
#include <os/str.h>
#include <driver/int.h>
#include <driver/rott_driver.h>
#include "frame_buffer.h"
#include "yuv_encode.h"
#include <driver/gpio.h>
#include "media_evt.h"
#include "yuv_encode.h"
#if CONFIG_HW_ROTATE_PFC
#include <driver/rott_driver.h>
#endif
#include <driver/media_types.h>
#include <lcd_rotate.h>
#include "modules/image_scale.h"
#include <driver/dma2d.h>
#include <driver/dma2d_types.h>
#include <driver/psram.h>
#include "modules/image_scale.h"
#include "dma2d_ll_macro_def.h"
#include "bk_list.h"
#include "mux_pipeline.h"
#define TAG "rot_pipline"
#define LOGI(...) BK_LOGI(TAG, ##__VA_ARGS__)
#define LOGW(...) BK_LOGW(TAG, ##__VA_ARGS__)
#define LOGE(...) BK_LOGE(TAG, ##__VA_ARGS__)
#define LOGD(...) BK_LOGD(TAG, ##__VA_ARGS__)
#if CONFIG_LVGL
uint8_t lvgl_disp_enable = 0;
#endif
#ifdef ROTATE_DIAG_DEBUG
#define ROTATE_LINE_START() do { GPIO_UP(GPIO_DVP_D3); } while (0)
#define ROTATE_LINE_END() do { GPIO_DOWN(GPIO_DVP_D3); } while (0)
#define DMA2D_LINE_START() do { GPIO_UP(GPIO_DVP_D4); } while (0)
#define DMA2D_LINE_END() do { GPIO_DOWN(GPIO_DVP_D4); } while (0)
#else
#define ROTATE_LINE_START()
#define ROTATE_LINE_END()
#define DMA2D_LINE_START()
#define DMA2D_LINE_END()
#endif
typedef enum {
BUF_IDLE = 0,
BUF_READY = 1,
BUF_ROTATING = 2,
BUF_ROTATED = 3,
BUF_COPYING = 4,
BUF_COPY_READY,
}buf_status_t;
typedef enum
{
ROTATE_STATE_IDLE = 0,
ROTATE_STATE_ENCODING,
} rotate_state_t;
typedef struct {
complex_buffer_t *rotate_buf;
LIST_HEADER_T list;
} rotate_copy_request_t;
typedef struct {
uint8_t enable;
uint8_t task_running : 1;
uint8_t err_frame : 1;
uint8_t reset_status : 1;
uint8_t psram_overwrite_id;
frame_buffer_t *rotate_frame;
beken_semaphore_t rot_sem;
beken_queue_t rotate_queue;
beken_thread_t rotate_thread;
uint16_t jpeg_width; /**< memcpy or pfc src image width */
uint16_t jpeg_height; /**< imemcpy or pfc src image height */
media_rotate_t rot_angle;
media_rotate_mode_t rot_mode;
pixel_format_t fmt;
complex_buffer_t *decoder_buffer;
complex_buffer_t buf[2];
LIST_HEADER_T rotate_pedding_list;
LIST_HEADER_T copy_pedding_list;
rotate_state_t state;
complex_buffer_t * rotate_buffer;
complex_buffer_t direct_copy_buffer;
uint16_t dma2d_isr_cnt;
uint8_t dma2d_copy;
uint8_t rotate_ena;
mux_callback_t decoder_free_cb;
mux_callback_t reset_cb;
} rotate_config_t;
typedef struct {
beken_mutex_t lock;
} rotate_info_t;
static rotate_config_t *rotate_config = NULL;
static rotate_info_t *rotate_info = NULL;
beken2_timer_t rotate_timer;
bk_err_t rotate_task_send_msg(uint8_t type, uint32_t param)
{
bk_err_t ret = BK_FAIL;
media_msg_t msg;
if (rotate_config && rotate_config->enable)
{
msg.event = type;
msg.param = param;
ret = rtos_push_to_queue(&rotate_config->rotate_queue, &msg, BEKEN_WAIT_FOREVER);
}
if (BK_OK != ret)
{
LOGE("%s failed, type:%d\r\n", __func__, type);
}
return ret;
}
static void rotate_watermark_cb(void)
{
LOGD("rotate_watermark_cb\r\n");
}
static void rotate_cfg_err_cb(void)
{
LOGI("rotate_cfg_err_cb\r\n");
}
static void rotate_complete_cb(void)
{
if (rotate_config)
{
rotate_task_send_msg(ROTATE_FINISH, (uint32_t)rotate_config->rotate_buffer);
}
}
static void dma2d_config_error(void)
{
LOGE("%s \n", __func__);
}
static void dma2d_transfer_error(void)
{
LOGE("%s %d %p\n", __func__, rotate_config->rotate_buffer->index, rotate_config->rotate_frame->frame);
}
static complex_buffer_t *rotate_get_idle_buf(void)
{
if (rotate_config->buf[0].state == BUF_IDLE)
return &rotate_config->buf[0];
else if (rotate_config->buf[1].state == BUF_IDLE)
return &rotate_config->buf[1];
else
return NULL;
}
static void dma2d_transfer_complete(void)
{
int ret = BK_OK;
DMA2D_LINE_END();
uint32_t rot_buf = dma2d_ll_get_dma2d_fg_address_value();
//rotate_config->dma2d_isr_cnt++;
if (rotate_config->dma2d_isr_cnt == (rotate_config->jpeg_height / PIPELINE_DECODE_LINE))
{
rotate_config->dma2d_isr_cnt = 0;
rotate_config->rotate_frame->fmt = rotate_config->fmt;
if ((rotate_config->rot_angle == ROTATE_90) || (rotate_config->rot_angle == ROTATE_270))
{
rotate_config->rotate_frame->width = rotate_config->jpeg_height;
rotate_config->rotate_frame->height = rotate_config->jpeg_width;
}
else
{
rotate_config->rotate_frame->width = rotate_config->jpeg_width;
rotate_config->rotate_frame->height = rotate_config->jpeg_height;
}
bk_psram_disable_write_through(rotate_config->psram_overwrite_id);
if (rotate_config->err_frame || rotate_config->reset_status)
{
frame_buffer_display_free(rotate_config->rotate_frame);
rotate_config->rotate_frame = NULL;
rotate_config->err_frame = false;
}
else
{
#if CONFIG_LVGL
if (lvgl_disp_enable) {
frame_buffer_display_free(rotate_config->rotate_frame);
}
else
#endif
{
if (lcd_display_frame_request(rotate_config->rotate_frame) != BK_OK)
{
frame_buffer_display_free(rotate_config->rotate_frame);
}
}
rotate_config->rotate_frame = NULL;
}
ROTATE_LINE_END();
#if (PIPELINE_ROTATE_CONTINUE == 0)
rotate_config->buf[0].state = BUF_IDLE;
rotate_config->buf[1].state = BUF_IDLE;
rotate_config->decoder_free_cb(rotate_config->decoder_buffer);
rotate_config->decoder_buffer = NULL;
#endif
}
if (rot_buf == (uint32_t)rotate_config->buf[0].data)
{
rotate_config->buf[0].state = BUF_IDLE;
}
else if(rot_buf == (uint32_t)rotate_config->buf[1].data)
{
rotate_config->buf[1].state = BUF_IDLE;
}
if (!list_empty(&rotate_config->copy_pedding_list))
{
LIST_HEADER_T *pos, *n, *list = &rotate_config->copy_pedding_list;
rotate_copy_request_t *request = NULL;
list_for_each_safe(pos, n, list)
{
request = list_entry(pos, rotate_copy_request_t, list);
if (request != NULL)
{
ret = rotate_task_send_msg(ROTATE_LINE_COPY_START, (uint32_t)request);
if (ret == BK_OK)
{
list_del(pos);
}
break;
}
}
}
if ((rotate_config->state == ROTATE_STATE_IDLE)
&& (!list_empty(&rotate_config->rotate_pedding_list)))
{
LIST_HEADER_T *pos, *n, *list = &rotate_config->rotate_pedding_list;
pipeline_encode_request_t *request = NULL;
list_for_each_safe(pos, n, list)
{
request = list_entry(pos, pipeline_encode_request_t, list);
if (request != NULL)
{
ret = rotate_task_send_msg(ROTATE_DEC_LINE_NOTIFY, (uint32_t)request);
if (ret == BK_OK)
{
list_del(pos);
}
break;
}
}
}
if ((rotate_config->rot_mode == SW_ROTATE) && (rotate_config->rot_angle == ROTATE_NONE))
{
rotate_config->decoder_free_cb(rotate_config->decoder_buffer);
rotate_config->decoder_buffer = NULL;
rotate_config->state = ROTATE_STATE_IDLE;
}
rotate_config->dma2d_copy = false;
}
#if CONFIG_SOFTWARE_DECODE_SRAM_MAPPING
void rotate_set_dma2d_cb(void)
{
bk_dma2d_register_int_callback_isr(DMA2D_CFG_ERROR_ISR, dma2d_config_error);
bk_dma2d_register_int_callback_isr(DMA2D_TRANS_ERROR_ISR, dma2d_transfer_error);
bk_dma2d_register_int_callback_isr(DMA2D_TRANS_COMPLETE_ISR, dma2d_transfer_complete);
}
#endif
static void rotate_finish_handler(uint32_t param)
{
ROTATE_LINE_END();
int ret = BK_OK;
complex_buffer_t *rotate_buf = (complex_buffer_t*)param;
if (rtos_is_oneshot_timer_running(&rotate_timer))
{
rtos_stop_oneshot_timer(&rotate_timer);
}
if (!list_empty(&rotate_config->rotate_pedding_list))
{
LIST_HEADER_T *pos, *n, *list = &rotate_config->rotate_pedding_list;
pipeline_encode_request_t *request = NULL;
list_for_each_safe(pos, n, list)
{
request = list_entry(pos, pipeline_encode_request_t, list);
if (request != NULL)
{
ret = rotate_task_send_msg(ROTATE_DEC_LINE_NOTIFY, (uint32_t)request);
list_del(pos);
if (ret != BK_OK)
{
os_free(request);
request = NULL;
}
}
}
}
rotate_copy_request_t *rotate_copy_request = (rotate_copy_request_t*)os_malloc(sizeof(rotate_copy_request_t));
rotate_copy_request->rotate_buf = rotate_buf;
#if (PIPELINE_ROTATE_CONTINUE == 0)
if (rotate_buf->index < (rotate_config->jpeg_height / PIPELINE_DECODE_LINE))
#endif
{
rotate_config->decoder_free_cb(rotate_config->decoder_buffer);
rotate_config->decoder_buffer = NULL;
}
if (BK_OK != rotate_task_send_msg(ROTATE_LINE_COPY_START, (uint32_t)rotate_copy_request))
{
os_free(rotate_copy_request);
}
rotate_config->rotate_ena = 0;
rotate_config->state = ROTATE_STATE_IDLE;
}
static bk_err_t rotate_memcopy_handler(uint32_t param)
{
bk_err_t ret = BK_OK;
rotate_copy_request_t *rotate_copy_request = (rotate_copy_request_t*)param;
complex_buffer_t *rotate_buf = rotate_copy_request->rotate_buf;
GLOBAL_INT_DECLARATION();
GLOBAL_INT_DISABLE();
if (rotate_config->dma2d_copy)
{
LOGD("===add copy_pedding_list===>>>>%s %d\n", __func__, __LINE__);
list_add_tail(&rotate_copy_request->list, &rotate_config->copy_pedding_list);
GLOBAL_INT_RESTORE();
return ret;
}
else
{
rotate_config->dma2d_copy = true;
}
GLOBAL_INT_RESTORE();
if ((rotate_config->dma2d_isr_cnt != (rotate_buf->index - 1)) && (rotate_config->dma2d_isr_cnt != (rotate_config->jpeg_height / PIPELINE_DECODE_LINE)))
{
LOGD("%s %d %d %d %d \n", __func__, __LINE__, rotate_config->dma2d_isr_cnt, rotate_buf->index, rotate_config->rotate_buffer->index);
}
rotate_config->dma2d_isr_cnt = rotate_buf->index;
if (rotate_buf->index == 1)
{
if (rotate_config->rotate_frame)
{
frame_buffer_display_free(rotate_config->rotate_frame);
rotate_config->rotate_frame = NULL;
}
if (rotate_config->fmt == PIXEL_FMT_RGB888)
rotate_config->rotate_frame = frame_buffer_display_malloc(rotate_config->jpeg_width * rotate_config->jpeg_height * 3);
else //RGB565 YUYV
rotate_config->rotate_frame = frame_buffer_display_malloc(rotate_config->jpeg_width * rotate_config->jpeg_height * 2);
if (rotate_config->rotate_frame != NULL)
{
rotate_config->rotate_frame->fmt = rotate_config->fmt;
bk_psram_enable_write_through(rotate_config->psram_overwrite_id, (uint32_t)rotate_config->rotate_frame->frame,
(uint32_t)(rotate_config->rotate_frame->frame + rotate_config->rotate_frame->size));
}
else
{
LOGE("%s, malloc rotate psram buffer failed\r\n", __func__);
}
}
if (rotate_config->rotate_frame == NULL)
{
goto error;
}
DMA2D_LINE_START();
dma2d_memcpy_pfc_t dma2d_memcpy_pfc = {0};
rotate_buf->state = BUF_COPYING;
dma2d_memcpy_pfc.input_addr = (char *)rotate_buf->data;
dma2d_memcpy_pfc.output_addr = (char *)rotate_config->rotate_frame->frame;
if (rotate_config->fmt == PIXEL_FMT_RGB888)
{
dma2d_memcpy_pfc.mode = DMA2D_M2M_PFC;
dma2d_memcpy_pfc.input_color_mode = DMA2D_INPUT_YUYV;
dma2d_memcpy_pfc.src_pixel_byte = TWO_BYTES;
dma2d_memcpy_pfc.output_color_mode = DMA2D_OUTPUT_RGB888;
dma2d_memcpy_pfc.dst_pixel_byte = THREE_BYTES;
}
else if(rotate_config->fmt == PIXEL_FMT_YUYV) //RGB565 / RGB565_LE
{
dma2d_memcpy_pfc.mode = DMA2D_M2M;
dma2d_memcpy_pfc.input_color_mode = DMA2D_INPUT_YUYV;
dma2d_memcpy_pfc.src_pixel_byte = TWO_BYTES;
dma2d_memcpy_pfc.output_color_mode = DMA2D_OUTPUT_YUYV;
dma2d_memcpy_pfc.dst_pixel_byte = TWO_BYTES;
}
else //RGB565
{
dma2d_memcpy_pfc.mode = DMA2D_M2M;
dma2d_memcpy_pfc.input_color_mode = DMA2D_INPUT_RGB565;
dma2d_memcpy_pfc.src_pixel_byte = TWO_BYTES;
dma2d_memcpy_pfc.output_color_mode = DMA2D_OUTPUT_RGB565;
dma2d_memcpy_pfc.dst_pixel_byte = TWO_BYTES;
}
dma2d_memcpy_pfc.src_frame_xpos = 0;
dma2d_memcpy_pfc.src_frame_ypos = 0;
if (rotate_config->rot_angle == ROTATE_90)
{
dma2d_memcpy_pfc.dma2d_width = PIPELINE_DECODE_LINE; //rotate_config->dma2d_width;
dma2d_memcpy_pfc.dma2d_height = rotate_config->jpeg_width ; // 800
dma2d_memcpy_pfc.src_frame_width = PIPELINE_DECODE_LINE;
dma2d_memcpy_pfc.src_frame_height = rotate_config->jpeg_width;
dma2d_memcpy_pfc.dst_frame_width = rotate_config->jpeg_height; //480
dma2d_memcpy_pfc.dst_frame_height = rotate_config->jpeg_width; //800
dma2d_memcpy_pfc.dst_frame_xpos = rotate_config->jpeg_height - (PIPELINE_DECODE_LINE * (rotate_config->dma2d_isr_cnt));
dma2d_memcpy_pfc.dst_frame_ypos = 0;
}
else if (rotate_config->rot_angle == ROTATE_270)
{
dma2d_memcpy_pfc.dma2d_width = PIPELINE_DECODE_LINE; //rotate_config->dma2d_width;
dma2d_memcpy_pfc.dma2d_height = rotate_config->jpeg_width ; // 800
dma2d_memcpy_pfc.src_frame_width = PIPELINE_DECODE_LINE;
dma2d_memcpy_pfc.src_frame_height = rotate_config->jpeg_width;
dma2d_memcpy_pfc.dst_frame_width = rotate_config->jpeg_height; //480
dma2d_memcpy_pfc.dst_frame_height = rotate_config->jpeg_width; //800
dma2d_memcpy_pfc.dst_frame_xpos = PIPELINE_DECODE_LINE * (rotate_config->dma2d_isr_cnt - 1);
dma2d_memcpy_pfc.dst_frame_ypos = 0;
}
else if (rotate_config->rot_angle == ROTATE_NONE)
{
dma2d_memcpy_pfc.dma2d_width = rotate_config->jpeg_width;
dma2d_memcpy_pfc.dma2d_height = PIPELINE_DECODE_LINE;
dma2d_memcpy_pfc.src_frame_width = rotate_config->jpeg_width;
dma2d_memcpy_pfc.src_frame_height = PIPELINE_DECODE_LINE;
dma2d_memcpy_pfc.dst_frame_width = rotate_config->jpeg_width;
dma2d_memcpy_pfc.dst_frame_height = rotate_config->jpeg_height;
dma2d_memcpy_pfc.dst_frame_xpos = 0;
dma2d_memcpy_pfc.dst_frame_ypos = PIPELINE_DECODE_LINE * (rotate_config->dma2d_isr_cnt - 1);
}
else //180
{
dma2d_memcpy_pfc.dma2d_width = rotate_config->jpeg_width;
dma2d_memcpy_pfc.dma2d_height = PIPELINE_DECODE_LINE;
dma2d_memcpy_pfc.src_frame_width = rotate_config->jpeg_width;
dma2d_memcpy_pfc.src_frame_height = PIPELINE_DECODE_LINE;
dma2d_memcpy_pfc.dst_frame_width = rotate_config->jpeg_width;
dma2d_memcpy_pfc.dst_frame_height = rotate_config->jpeg_height;
dma2d_memcpy_pfc.dst_frame_xpos = 0;
dma2d_memcpy_pfc.dst_frame_ypos = (rotate_config->jpeg_height - (rotate_config->dma2d_isr_cnt* PIPELINE_DECODE_LINE));
}
bk_dma2d_memcpy_or_pixel_convert(&dma2d_memcpy_pfc);
bk_dma2d_start_transfer();
os_free(rotate_copy_request);
return ret;
error:
if ((rotate_config->rot_mode == SW_ROTATE) && (rotate_config->rot_angle == ROTATE_NONE))
{
rotate_config->decoder_free_cb(rotate_config->decoder_buffer);
rotate_config->decoder_buffer = NULL;
rotate_config->state = ROTATE_STATE_IDLE;
}
else
{
rotate_buf->state = BUF_IDLE;
}
rotate_config->dma2d_copy = false;
os_free(rotate_copy_request);
return BK_FAIL;
}
bk_err_t rotate_clear_status(void)
{
bk_err_t ret= BK_FAIL;
LOGI("%s, set reset\n", __func__);
rotate_config->reset_status = true;
if(rotate_config->reset_cb)
rotate_config->reset_cb(NULL);
return ret;
}
bk_err_t bk_rotate_reset_request(mux_callback_t cb)
{
rtos_lock_mutex(&rotate_info->lock);
rotate_config->reset_cb = cb;
if (BK_OK != rotate_task_send_msg(ROTATE_RESET, 0))
{
LOGI("%s send failed\n", __func__);
goto error;
}
rtos_unlock_mutex(&rotate_info->lock);
return BK_OK;
error:
if (rotate_config
&& rotate_config->reset_cb)
{
rotate_config->reset_cb = NULL;
}
rtos_unlock_mutex(&rotate_info->lock);
LOGE("%s failed\n", __func__);
return BK_FAIL;
}
static void rotate_timer_handle(void *arg1, void *arg2)
{
LOGI("%s, timeout, rotate: %d, %p, %p\n", __func__, rotate_config->rotate_ena,
rotate_config->decoder_buffer, rotate_config->decoder_buffer->data);
//decoder_mux_dump();
rotate_config->reset_status = true;
if(rotate_config->rot_mode == HW_ROTATE)
{
int ret = bk_rott_enable();
if (ret != BK_OK)
{
LOGE("rotate enable fail again\n");
}
else
{
rotate_config->rotate_ena = 1;
}
if (!rtos_is_oneshot_timer_running(&rotate_timer))
{
rtos_start_oneshot_timer(&rotate_timer);
}
if (rotate_config->rotate_buffer != &rotate_config->buf[0])
{
rotate_config->buf[0].state = BUF_IDLE;
}
if (rotate_config->rotate_buffer != &rotate_config->buf[1])
{
rotate_config->buf[1].state = BUF_IDLE;
}
}
else
{
LOGE("SW rotate Timeout\n");
}
}
static bk_err_t rotate_no_rotate_direct_copy_handler(uint32_t param)
{
if (rtos_is_oneshot_timer_running(&rotate_timer))
{
rtos_stop_oneshot_timer(&rotate_timer);
}
//1:dma2d memcopy, rotate_buf = decode buffer
complex_buffer_t *dec_buf = (complex_buffer_t *)param;
rotate_copy_request_t *rotate_copy_request = (rotate_copy_request_t*)os_malloc(sizeof(rotate_copy_request_t));
complex_buffer_t *rotate_buf = &rotate_config->direct_copy_buffer;
if(rotate_copy_request == NULL)
{
LOGE("%s, malloc fail \n", __func__);
return BK_FAIL;
}
rotate_copy_request->rotate_buf = rotate_buf;
rotate_copy_request->rotate_buf->data = dec_buf->data;
rotate_copy_request->rotate_buf->index = dec_buf->index;
if (BK_OK != rotate_task_send_msg(ROTATE_LINE_COPY_START, (uint32_t)rotate_copy_request))
{
LOGE("%s, malloc fail \n", __func__);
os_free(rotate_copy_request);
}
return BK_OK;
//2:dma2d isr finish send to decode notify
//3:get dma2d pendding list to memcopy
}
//decode complete, start to rotate
static bk_err_t rotate_dec_line_complete_handler(uint32_t param)
{
bk_err_t ret= BK_FAIL;
pipeline_encode_request_t *rotate_notify = (pipeline_encode_request_t*)param;
complex_buffer_t *temp_buf = rotate_get_idle_buf();
GLOBAL_INT_DECLARATION();
GLOBAL_INT_DISABLE();
if (rotate_config->state != ROTATE_STATE_IDLE
|| temp_buf == NULL)
{
LOGD("===add rotate_pedding_list===>>>>>%s %d %d %p \n", __func__, __LINE__, rotate_config->state, temp_buf);
list_add_tail(&rotate_notify->list, &rotate_config->rotate_pedding_list);
GLOBAL_INT_RESTORE();
return ret;
}
else
{
rotate_config->state = ROTATE_STATE_ENCODING;
}
GLOBAL_INT_RESTORE();
if(rotate_notify->buffer->index == 1)
{
rotate_config->jpeg_width = rotate_notify->width;
rotate_config->jpeg_height = rotate_notify->height;
rotate_config->reset_status = false;
}
if (rotate_notify->buffer->index == (rotate_config->jpeg_height / PIPELINE_DECODE_LINE))
{
rotate_config->err_frame = !(rotate_notify->buffer->ok);
}
rotate_config->rotate_buffer = temp_buf;
rotate_config->rotate_buffer->index = rotate_notify->buffer->index;
rotate_config->rotate_buffer->state = BUF_ROTATING;
rotate_config->rotate_buffer->index = rotate_notify->buffer->index;
if (rotate_config->decoder_buffer)
{
LOGE("%s decoder_buffer error NOT NULL\n", __func__);
goto out;
}
else
{
rotate_config->decoder_buffer = (complex_buffer_t*)os_malloc(sizeof(complex_buffer_t));
if (rotate_config->decoder_buffer == NULL)
{
LOGE("%s decoder_buffer malloc failed\n", __func__);
goto out;
}
os_memcpy(rotate_config->decoder_buffer, rotate_notify->buffer, sizeof(complex_buffer_t));
}
ROTATE_LINE_START();
if (!rtos_is_oneshot_timer_running(&rotate_timer))
{
rtos_start_oneshot_timer(&rotate_timer);
}
int (*func)(unsigned char *vuyy, unsigned char *rotatedVuyy, int width, int height);
switch (rotate_config->rot_angle)
{
case ROTATE_90:
default:
func = yuyv_rotate_degree90_to_yuyv;
break;
case ROTATE_270:
func = yuyv_rotate_degree270_to_yuyv;
break;
case ROTATE_180:
yuyv_rotate_degree180_to_yuyv(rotate_notify->buffer->data, rotate_config->rotate_buffer->data, rotate_config->jpeg_width, PIPELINE_DECODE_LINE);
rotate_task_send_msg(ROTATE_FINISH, (uint32_t)rotate_config->rotate_buffer);
goto out;
}
if (rotate_config->rot_mode == SW_ROTATE) //sw rotate
{
if (rotate_config->rot_angle == ROTATE_NONE)
{
rotate_config->rotate_buffer->state = BUF_IDLE;
//yuv-->DMA2D-->rgb888 or yuv-->copy to psram-->yuv
rotate_task_send_msg(ROTATE_NO_ROTATE_DIRECT_COPY, (uint32_t)rotate_config->decoder_buffer);
}
else
{
func(rotate_notify->buffer->data, rotate_config->rotate_buffer->data, rotate_config->jpeg_width, PIPELINE_DECODE_LINE);
rotate_task_send_msg(ROTATE_FINISH, (uint32_t)rotate_config->rotate_buffer);
}
}
else
{
rott_config_t rott_cfg = {0};
rott_cfg.input_addr = rotate_notify->buffer->data;
rott_cfg.output_addr = rotate_config->rotate_buffer->data;
rott_cfg.rot_mode = rotate_config->rot_angle;
rott_cfg.input_fmt = PIXEL_FMT_YUYV;
rott_cfg.input_flow = ROTT_INPUT_NORMAL;
rott_cfg.output_flow = ROTT_OUTPUT_NORMAL;
rott_cfg.picture_xpixel = rotate_notify->width;
rott_cfg.picture_ypixel = PIPELINE_DECODE_LINE;
/* config twice for register sync */
ret = rott_config(&rott_cfg);
if (ret != BK_OK)
{
LOGE(" rott_config ERR\n");
}
ret = bk_rott_enable();
rotate_config->rotate_ena = 1;
if (ret != BK_OK)
{
LOGE("rotate enable failed\n");
}
}
out:
os_free(rotate_notify);
rotate_notify = NULL;
return ret;
}
bk_err_t rotate_task_deinit(void)
{
int ret =BK_OK;
LOGI("%s\n", __func__);
bk_dma2d_driver_deinit();
bk_rott_driver_deinit();
LOGI("%s complete\n", __func__);
return ret;
}
static void rotate_main(beken_thread_arg_t data)
{
int ret = BK_OK;
rotate_config->task_running = true;
LOGI("%s %d\n", __func__, __LINE__);
rtos_set_semaphore(&rotate_config->rot_sem);
while (rotate_config->task_running)
{
media_msg_t msg;
ret = rtos_pop_from_queue(&rotate_config->rotate_queue, &msg, BEKEN_WAIT_FOREVER);
if (ret == BK_OK)
{
switch (msg.event)
{
case ROTATE_DEC_LINE_NOTIFY:
{
rotate_dec_line_complete_handler(msg.param);
break;
}
case ROTATE_FINISH:
rotate_finish_handler(msg.param); //send to dma2d/DECODE
break;
case ROTATE_NO_ROTATE_DIRECT_COPY:
rotate_no_rotate_direct_copy_handler(msg.param);
break;
case ROTATE_LINE_COPY_START:
rotate_memcopy_handler(msg.param);
break;
case ROTATE_RESET:
rotate_clear_status();
break;
case ROTATE_STOP:
{
LOGI("%s exit\n", __func__);
rotate_config->task_running = 0;
if (rtos_is_oneshot_timer_running(&rotate_timer))
{
rtos_stop_oneshot_timer(&rotate_timer);
}
if (rtos_is_oneshot_timer_init(&rotate_timer))
{
rtos_deinit_oneshot_timer(&rotate_timer);
}
beken_semaphore_t *beken_semaphore = (beken_semaphore_t*)msg.param;
rtos_deinit_queue(&rotate_config->rotate_queue);
rotate_config->rotate_queue = NULL;
rotate_config->rotate_thread = NULL;
rtos_set_semaphore(beken_semaphore);
rtos_delete_thread(NULL);
}
break;
default:
break;
}
}
}
}
static bk_err_t rotate_init(media_rotate_mode_t mode)
{
LOGI("%s %d\n", __func__, __LINE__);
if (mode == HW_ROTATE)
{
bk_rott_driver_init();
bk_rott_int_enable(ROTATE_COMPLETE_INT | ROTATE_CFG_ERR_INT | ROTATE_WARTERMARK_INT, 1);
bk_rott_isr_register(ROTATE_COMPLETE_INT, rotate_complete_cb);
bk_rott_isr_register(ROTATE_WARTERMARK_INT, rotate_watermark_cb);
bk_rott_isr_register(ROTATE_CFG_ERR_INT, rotate_cfg_err_cb);
}
bk_dma2d_driver_init();
// dma2d_driver_transfes_ability(TRANS_128BYTES);
bk_dma2d_int_enable(DMA2D_CFG_ERROR | DMA2D_TRANS_ERROR | DMA2D_TRANS_COMPLETE,1);
bk_dma2d_register_int_callback_isr(DMA2D_CFG_ERROR_ISR, dma2d_config_error);
bk_dma2d_register_int_callback_isr(DMA2D_TRANS_ERROR_ISR, dma2d_transfer_error);
bk_dma2d_register_int_callback_isr(DMA2D_TRANS_COMPLETE_ISR, dma2d_transfer_complete);
return BK_OK;
}
bool check_rotate_task_is_open(void)
{
if (rotate_config == NULL)
{
return false;
}
else
{
return rotate_config->task_running;
}
}
/**
* @brief rotate select
* params: rotate mode
* rotate angle
* rotate_fmt (d:default)
* __________________________________
* | Lcd Input | SW | HW |
* |———————————|———————————|——————————|
* | | RGB888 | |
* | rot 0 | YUYV(d) | RGB565 |
* |———————————|———————————|——————————|
* | rot 90 | RGB888 | |
* | rot 270 | YUYV(d) | RGB565 |
* |___________|___________|__________|
*/
bk_err_t rotate_task_open(rot_open_t *rot_open)
{
int ret = BK_OK;
rtos_lock_mutex(&rotate_info->lock);
LOGI("%s %d\n", __func__, __LINE__);
if (rotate_config != NULL && rotate_config->task_running)
{
LOGE("%s, rotate task have been opened!\r\n", __func__);
rtos_unlock_mutex(&rotate_info->lock);
return ret;
}
rotate_config = (rotate_config_t *)os_malloc(sizeof(rotate_config_t));
if (rotate_config == NULL)
{
LOGE("%s, malloc rotate_config failed\r\n", __func__);
rtos_unlock_mutex(&rotate_info->lock);
return BK_FAIL;
}
os_memset(rotate_config, 0, sizeof(rotate_config_t));
INIT_LIST_HEAD(&rotate_config->rotate_pedding_list);
INIT_LIST_HEAD(&rotate_config->copy_pedding_list);
rotate_config->psram_overwrite_id = bk_psram_alloc_write_through_channel();
if (!rtos_is_oneshot_timer_init(&rotate_timer))
{
ret = rtos_init_oneshot_timer(&rotate_timer, 1 * 1000, rotate_timer_handle, NULL, NULL);
if (ret != BK_OK)
{
LOGE("create rotate timer failed\n");
}
}
rotate_config->buf[0].data = mux_sram_buffer->rotate;
rotate_config->buf[1].data = mux_sram_buffer->rotate + ROTATE_MAX_PIPELINE_LINE_SIZE;
LOGI("%s rot_sram (%p, %p, %p)\n", __func__, mux_sram_buffer->rotate, rotate_config->buf[0].data, rotate_config->buf[1].data);
ROTATE_LINE_END();
DMA2D_LINE_END();
ret = rotate_init(rot_open->mode);
if(ret != BK_OK)
{
LOGE("%s, rotate pipeline init fail\r\n", __func__);
return ret;
}
///APK select LCD out format is RGB888
if (rot_open->angle == ROTATE_180)
{
rotate_config->fmt = PIXEL_FMT_YUYV;
}
else if (rot_open->mode == SW_ROTATE)
{
rotate_config->rot_mode = SW_ROTATE;
if (rot_open->angle == ROTATE_NONE)
{
///yuyv-->dma2d-->yuyv
rotate_config->fmt = PIXEL_FMT_YUYV;
///yuyv-->dma2d-->rgb888
// rotate_config->fmt = PIXEL_FMT_RGB888;
}
else
{
#if CONFIG_SW_ROTATE_TO_YUYV_AND_DMA2D_TO_YUYV_NOT_RGB888
///yuyv -->sw rotate-->yuyv-->DMA2D -->yuyv-->DISPLAY==>rgb888
rotate_config->fmt = PIXEL_FMT_YUYV; //5
#else
///(dafault) yuyv -->sw rotate-->yuyv-->DMA2D -->RGB888-->DISPLAY==>rgb888
rotate_config->fmt = PIXEL_FMT_RGB888; //25
#endif
}
}
else
{
rotate_config->rot_mode = HW_ROTATE;
///yuyv-->hw rotate-->RGB565
rotate_config->fmt = rot_open->fmt; //RGB656_LE 22
}
LOGI("%s, mode %d(1:sw, 2:hw) angle(0:0, 1:90,2:180,3:270) %d, fmt:%d(5:yuv, 22:rgb565_LE, 25:rgb888)\r\n", __func__, rotate_config->rot_mode, rot_open->angle, rotate_config->fmt);
rotate_config->rot_angle = rot_open->angle;
ret = rtos_init_semaphore(&rotate_config->rot_sem, 1);
if (ret != BK_OK)
{
LOGE("%s, init jdec_config->rot_sem failed\r\n", __func__);
goto error;
}
if (rotate_config->rotate_queue != NULL)
{
LOGE("%s, rotate_config->rotate_queue already init, exit!\n", __func__);
goto error;
}
if (rotate_config->rotate_thread != NULL)
{
LOGE("%s, rotate_config->rotate_thread already init, exit!\n", __func__);
goto error;
}
ret = rtos_init_queue(&rotate_config->rotate_queue,
"rotate_queue",
sizeof(media_msg_t),
10);
if (ret != BK_OK)
{
LOGE("%s, init rot_queue failed\r\n", __func__);
goto error;
}
ret = rtos_create_thread(&rotate_config->rotate_thread,
BEKEN_DEFAULT_WORKER_PRIORITY,
"rotate_thread",
(beken_thread_function_t)rotate_main,
1024 * 2,
NULL);
if (ret != BK_OK)
{
LOGE("%s, create rotate thread failed\r\n", __func__);
goto error;
}
rtos_get_semaphore(&rotate_config->rot_sem, BEKEN_NEVER_TIMEOUT);
rotate_config->enable = true;
LOGI("%s complete\n", __func__);
rtos_unlock_mutex(&rotate_info->lock);
return ret;
error:
LOGE("%s error\n", __func__);
if (rotate_config->rotate_queue)
{
rtos_deinit_queue(&rotate_config->rotate_queue);
rotate_config->rotate_queue = NULL;
}
if (rotate_config)
{
os_free(rotate_config);
rotate_config = NULL;
}
rtos_unlock_mutex(&rotate_info->lock);
return BK_FAIL;
}
void rotate_task_stop(void)
{
beken_semaphore_t sem;
media_msg_t msg;
msg.event = ROTATE_STOP;
msg.param = (uint32_t)&sem;
int ret = rtos_init_semaphore(&sem, 1);
if (ret != BK_OK)
{
LOGE("%s, init sem faild, %d\n", __func__, ret);
return;
}
ret = rtos_push_to_queue(&rotate_config->rotate_queue, &msg, BEKEN_WAIT_FOREVER);
rtos_get_semaphore(&sem, BEKEN_NEVER_TIMEOUT);
rtos_deinit_semaphore(&sem);
}
bk_err_t rotate_task_close(void)
{
LOGI("%s \n", __func__);
rtos_lock_mutex(&rotate_info->lock);
if (rotate_config == NULL || !rotate_config->task_running)
{
rtos_unlock_mutex(&rotate_info->lock);
return BK_FAIL;
}
GLOBAL_INT_DECLARATION();
GLOBAL_INT_DISABLE();
rotate_config->enable = false;
GLOBAL_INT_RESTORE();
rotate_task_stop();
rtos_deinit_semaphore(&rotate_config->rot_sem);
rotate_config->rot_sem = NULL;
rotate_task_deinit();
if (!list_empty(&rotate_config->rotate_pedding_list))
{
LOGI("%s, clear rotate_pedding_list\n", __func__);
LIST_HEADER_T *pos, *n, *list = &rotate_config->rotate_pedding_list;
pipeline_encode_request_t *request = NULL;
list_for_each_safe(pos, n, list)
{
request = list_entry(pos, pipeline_encode_request_t, list);
if (request != NULL)
{
complex_buffer_t *decoder_buffer = (complex_buffer_t*)os_malloc(sizeof(complex_buffer_t));
os_memcpy(decoder_buffer, request->buffer, sizeof(complex_buffer_t));
rotate_config->decoder_free_cb(decoder_buffer);
list_del(pos);
os_free(request);
}
}
}
if (rotate_config->decoder_buffer)
{
rotate_config->decoder_free_cb(rotate_config->decoder_buffer);
rotate_config->decoder_buffer = NULL;
}
if (!list_empty(&rotate_config->copy_pedding_list))
{
LOGI("%s, clear copy_pedding_list\n", __func__);
LIST_HEADER_T *pos, *n, *list = &rotate_config->copy_pedding_list;
rotate_copy_request_t *request = NULL;
list_for_each_safe(pos, n, list)
{
request = list_entry(pos, rotate_copy_request_t, list);
if (request != NULL)
{
list_del(pos);
os_free(request);
}
}
}
if (rotate_config->rotate_frame)
{
frame_buffer_display_free(rotate_config->rotate_frame);
rotate_config->rotate_frame = NULL;
LOGI("%s free rotate_frame\n", __func__);
}
bk_psram_disable_write_through(rotate_config->psram_overwrite_id);
bk_psram_free_write_through_channel(rotate_config->psram_overwrite_id);
os_free(rotate_config);
rotate_config = NULL;
LOGI("%s complete\n", __func__);
rtos_unlock_mutex(&rotate_info->lock);
return BK_OK;
}
bk_err_t bk_rotate_encode_request(pipeline_encode_request_t *request, mux_callback_t cb)
{
pipeline_encode_request_t *rotate_request = NULL;
rtos_lock_mutex(&rotate_info->lock);
if (rotate_config == NULL || rotate_config->enable == false)
{
LOGI("%s not open\n", __func__);
goto error;
}
rotate_request = (pipeline_encode_request_t *)os_malloc(sizeof(pipeline_encode_request_t));
if (rotate_request == NULL)
{
LOGI("%s malloc failed\n", __func__);
goto error;
}
os_memcpy(rotate_request, request, sizeof(pipeline_encode_request_t));
rotate_config->decoder_free_cb = cb;
if (BK_OK != rotate_task_send_msg(ROTATE_DEC_LINE_NOTIFY, (uint32_t)rotate_request))
{
LOGI("%s send failed\n", __func__);
goto error;
}
rtos_unlock_mutex(&rotate_info->lock);
return BK_OK;
error:
if (rotate_config
&& rotate_config->decoder_free_cb)
{
rotate_config->decoder_free_cb = NULL;
}
if (rotate_request)
{
os_free(rotate_request);
rotate_request = NULL;
}
rtos_unlock_mutex(&rotate_info->lock);
return BK_FAIL;
}
bk_err_t bk_rotate_pipeline_init(void)
{
bk_err_t ret = BK_FAIL;
if(rotate_info != NULL)
{
os_free(rotate_info);
rotate_info = NULL;
}
rotate_info = (rotate_info_t*)os_malloc(sizeof(rotate_info_t));
if (rotate_info == NULL)
{
LOGE("%s malloc rotates_info failed\n", __func__);
return BK_FAIL;
}
os_memset(rotate_info, 0, sizeof(rotate_info_t));
ret = rtos_init_mutex(&rotate_info->lock);
if (ret != BK_OK)
{
LOGE("%s, init mutex failed\r\n", __func__);
return BK_FAIL;
}
return ret;
}