// 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 #include #include #include #include #include "frame_buffer.h" #include "yuv_encode.h" #include #include "media_evt.h" #include "yuv_encode.h" #if CONFIG_HW_ROTATE_PFC #include #endif #include #include #include "modules/image_scale.h" #include #include #include #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; }