// Copyright 2022-2023 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 #include "clock_driver.h" #include "gpio_driver.h" #include "sys_driver.h" #include "sys_hal.h" #include "h264_hal.h" #include "h264_driver.h" #include "h264_default_config.h" typedef struct { h264_isr_t isr_handler; void *param; } h264_isr_handler_t; typedef struct { h264_hal_t hal; h264_isr_handler_t h264_isr_handler[H264_ISR_MAX]; } h264_driver_t; #define H264_QUALITY_LOW (1) #define H264_QUALITY_MIDDLE (2) #define H264_QUALITY_HIGH (3) #define H264_RETURN_ON_DRIVER_NOT_INIT() do {\ if (!s_h264_driver_is_init) {\ return BK_ERR_H264_DRIVER_NOT_INIT;\ }\ } while (0) extern void delay(int num); static h264_driver_t s_h264 = {0}; static uint8_t h264_dma_rx_id = 0; static bool s_h264_driver_is_init = false; static uint32_t h264_int_count[H264_ISR_MAX] = {0}; static compress_ratio_t h264_compress = {0}; static void h264_isr(void); bk_err_t h264_int_enable(void) { uint32_t int_level = rtos_disable_int(); sys_drv_int_group2_enable(H264_INTERRUPT_CTRL_BIT); h264_hal_int_config(&s_h264.hal, H264_INT_ENABLE); rtos_enable_int(int_level); return BK_OK; } bk_err_t h264_int_disable(void) { uint32_t int_level = rtos_disable_int(); h264_hal_int_config(&s_h264.hal, H264_CPU_INT_DISABLE); sys_drv_int_group2_disable(H264_INTERRUPT_CTRL_BIT); rtos_enable_int(int_level); return BK_OK; } static void h264_init_common(void) { // h264 power enable //sys_drv_h264_power_en(1); bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_VIDP_H264, PM_POWER_MODULE_STATE_ON); /* h264 clock set */ sys_drv_set_clk_div_mode1_clkdiv_h264(1); sys_drv_set_h264_clk_sel(H264_CLK_SEL_480M); // h264 clk enable sys_drv_set_h264_clk_en(1); /* h264 global ctrl set */ h264_hal_set_global_ctrl(&s_h264.hal); h264_hal_enable_external_clk_en(&s_h264.hal); } static void h264_deinit_common(void) { // h264 stop h264_hal_encode_disable(&s_h264.hal); // h264 soft reset bk_h264_soft_reset(); // h264 config reset h264_hal_reset(&s_h264.hal); // h264 int disable h264_int_disable(); // h264 clk disable sys_drv_set_h264_clk_en(0); // h264 power disable //sys_drv_h264_power_en(0); bk_pm_module_vote_power_ctrl(PM_POWER_SUB_MODULE_NAME_VIDP_H264, PM_POWER_MODULE_STATE_OFF); // h264 isr unregister for (uint8_t i = 0; i < H264_ISR_MAX; i++) { bk_h264_unregister_isr(i); } } bk_err_t bk_h264_pingpong_in_psram_clk_set(void) { h264_hal_enable_external_clk_en(&s_h264.hal); return BK_OK; } bk_err_t bk_h264_dma_rx_init(h264_dma_config_t *config) { if((config->rx_buf == NULL) || (config->transfer_len <= 0)) { return BK_ERR_DMA_INVALID_ADDR; } dma_config_t dma_config = {0}; dma_config.mode = DMA_WORK_MODE_REPEAT; dma_config.chan_prio = 0; dma_config.src.dev = DMA_DEV_H264; dma_config.src.width = DMA_DATA_WIDTH_32BITS; dma_config.src.start_addr = H264_R_RX_FIFO; dma_config.dst.dev = DMA_DEV_DTCM; dma_config.dst.width = DMA_DATA_WIDTH_32BITS; dma_config.dst.addr_inc_en = DMA_ADDR_INC_ENABLE; dma_config.dst.addr_loop_en = DMA_ADDR_LOOP_DISABLE; dma_config.dst.start_addr = (uint32_t)config->rx_buf; h264_dma_rx_id = bk_dma_alloc(DMA_DEV_H264); if(h264_dma_rx_id >= DMA_ID_MAX) { return BK_ERR_DMA_ID; } BK_LOG_ON_ERR(bk_dma_init(h264_dma_rx_id, &dma_config)); BK_LOG_ON_ERR(bk_dma_set_transfer_len(h264_dma_rx_id, config->transfer_len)); #if (CONFIG_SPE) BK_LOG_ON_ERR(bk_dma_set_dest_sec_attr(h264_dma_rx_id, DMA_ATTR_SEC)); BK_LOG_ON_ERR(bk_dma_set_src_sec_attr(h264_dma_rx_id, DMA_ATTR_SEC)); #endif BK_LOG_ON_ERR(bk_dma_start(h264_dma_rx_id)); return BK_OK; } bk_err_t bk_h264_enc_lcd_dma_cpy(void *out, const void *in, uint32_t len, dma_id_t cpy_chnl) { dma_config_t dma_config = {0}; os_memset(&dma_config, 0, sizeof(dma_config_t)); dma_config.mode = DMA_WORK_MODE_SINGLE; dma_config.chan_prio = 1; dma_config.src.dev = DMA_DEV_DTCM; dma_config.src.width = DMA_DATA_WIDTH_32BITS; dma_config.src.addr_inc_en = DMA_ADDR_INC_ENABLE; dma_config.src.start_addr = (uint32_t)in; dma_config.src.end_addr = (uint32_t)(in + len); dma_config.dst.dev = DMA_DEV_DTCM; dma_config.dst.width = DMA_DATA_WIDTH_32BITS; dma_config.dst.addr_inc_en = DMA_ADDR_INC_ENABLE; dma_config.dst.start_addr = (uint32_t)out; dma_config.dst.end_addr = (uint32_t)(out + len); BK_LOG_ON_ERR(bk_dma_init(cpy_chnl, &dma_config)); BK_LOG_ON_ERR(bk_dma_set_transfer_len(cpy_chnl, len)); #if (CONFIG_SPE && CONFIG_GDMA_HW_V2PX) BK_LOG_ON_ERR(bk_dma_set_src_burst_len(cpy_chnl, 3)); BK_LOG_ON_ERR(bk_dma_set_dest_burst_len(cpy_chnl, 3)); BK_LOG_ON_ERR(bk_dma_set_dest_sec_attr(cpy_chnl, DMA_ATTR_SEC)); BK_LOG_ON_ERR(bk_dma_set_src_sec_attr(cpy_chnl, DMA_ATTR_SEC)); #endif return BK_OK; } bk_err_t bk_h264_dma_rx_deinit(void) { BK_LOG_ON_ERR(bk_dma_stop(h264_dma_rx_id)); BK_LOG_ON_ERR(bk_dma_deinit(h264_dma_rx_id)); BK_LOG_ON_ERR(bk_dma_free(DMA_DEV_H264, h264_dma_rx_id)); h264_dma_rx_id = 0; return BK_OK; } bk_err_t bk_h264_driver_init(void) { if (s_h264_driver_is_init) { return BK_OK; } os_memset(&s_h264, 0, sizeof(s_h264)); bk_int_isr_register(INT_SRC_H264, h264_isr, NULL); h264_hal_init(&s_h264.hal); s_h264_driver_is_init = true; return BK_OK; } bk_err_t bk_h264_driver_deinit(void) { if (!s_h264_driver_is_init) { return BK_OK; } bk_int_isr_unregister(INT_SRC_H264); h264_int_disable(); h264_hal_reset(&s_h264.hal); os_memset(&s_h264, 0, sizeof(s_h264)); s_h264_driver_is_init = false; return BK_OK; } bk_err_t bk_h264_config_init(const h264_config_t *config, uint16_t media_width, uint16_t media_height) { if(config == NULL) { return BK_ERR_H264_INVALID_CONFIG_PARAM; } h264_init_common(); if(h264_hal_set_img_width(&s_h264.hal, media_width, media_height)) { return BK_ERR_H264_INVALID_RESOLUTION_TYPE; } h264_hal_gop_config(&s_h264.hal, config); h264_hal_qp_config(&s_h264.hal, config); h264_hal_idc_config(&s_h264.hal, config); h264_hal_mb_config(&s_h264.hal, config); h264_hal_scale_factor_config(&s_h264.hal); h264_hal_vui_config(&s_h264.hal, config); h264_hal_cpb_vui_config(&s_h264.hal, config); h264_hal_frame_cbr_config(&s_h264.hal, config); h264_int_enable(); return BK_OK; } bk_err_t bk_h264_init(media_ppi_t media_ppi) { int ret = BK_OK; H264_RETURN_ON_DRIVER_NOT_INIT(); uint16_t media_width = ppi_to_pixel_x(media_ppi); uint16_t media_height = ppi_to_pixel_y(media_ppi); if (media_height % 16 != 0) { H264_LOGE("h264 input pixel height is not n times of 16!! \r\n"); return BK_ERR_H264_INVALID_PIXEL_HEIGHT; } ret = bk_h264_config_init(&h264_commom_config, media_width, media_height); if (ret != BK_OK) { H264_LOGE("%s, set commom config error!\r\n", __func__); return ret; } if (CONFIG_H264_QUALITY_LEVEL == H264_QUALITY_HIGH) { h264_compress.qp.init_qp = 25; h264_compress.qp.i_max_qp = 25; h264_compress.qp.p_max_qp = 25; h264_compress.imb_bits = 200; h264_compress.pmb_bits = 80; h264_compress.enable = true; } else if (CONFIG_H264_QUALITY_LEVEL == H264_QUALITY_MIDDLE) { h264_compress.qp.init_qp = 40; h264_compress.qp.i_max_qp = 40; h264_compress.qp.p_max_qp = 25; h264_compress.imb_bits = 160; h264_compress.pmb_bits = 60; h264_compress.enable = true; } else if (CONFIG_H264_QUALITY_LEVEL == H264_QUALITY_LOW) { h264_compress.qp.init_qp = 40; h264_compress.qp.i_max_qp = 40; h264_compress.qp.p_max_qp = 25; h264_compress.imb_bits = 130; h264_compress.pmb_bits = 50; h264_compress.enable = true; } if (h264_compress.enable) { ret = bk_h264_set_qp(&h264_compress.qp); if (ret != BK_OK) { H264_LOGE("%s, set qp config error!\r\n", __func__); return ret; } bk_h264_set_quality(h264_compress.imb_bits, h264_compress.pmb_bits); h264_compress.enable = false; } return ret; } bk_err_t bk_h264_set_base_config(compress_ratio_t *config) { int ret = BK_OK; if (h264_compress.enable) { H264_LOGE("%s, already enable!!!\r\n", __func__); ret = BK_FAIL; goto error; } if(config->imb_bits > MAX_IFRAME_BITS || config->imb_bits < MIN_FRAME_BITS) { ret = BK_ERR_H264_INVALID_IMB_BITS; goto error; } if(config->pmb_bits > MAX_PFRAME_BITS || config->pmb_bits < MIN_FRAME_BITS) { ret = BK_ERR_H264_INVALID_PMB_BITS; goto error; } if(config->qp.init_qp > MAX_QP || config->qp.init_qp < MIN_QP) { ret = BK_ERR_H264_INVALID_QP; goto error; } if (config->qp.i_min_qp >= config->qp.i_max_qp || config->qp.p_min_qp >= config->qp.p_max_qp) { ret = BK_ERR_H264_INVALID_QP; goto error; } if (config->qp.i_max_qp > MAX_QP || config->qp.p_max_qp > MAX_QP) { ret = BK_ERR_H264_INVALID_QP; goto error; } os_memcpy(&h264_compress, config, sizeof(compress_ratio_t)); return ret; error: H264_LOGE("%s, %d\r\n", __func__, ret); return ret; } bk_err_t bk_h264_deinit(void) { H264_RETURN_ON_DRIVER_NOT_INIT(); h264_deinit_common(); return BK_OK; } bk_err_t bk_h264_set_pframe_num(uint32_t pframe_number) { H264_RETURN_ON_DRIVER_NOT_INIT(); if(pframe_number > MAX_PFRAME || pframe_number < MIN_PFRAME) { return BK_ERR_H264_INVALID_PFRAME_NUMBER; } h264_config_t param_set = {0}; param_set.skip_mode = DEFAULT_SKIP_MODE; param_set.num_pframe = pframe_number; const h264_config_t *para = ¶m_set; h264_hal_gop_config(&s_h264.hal, para); return BK_OK; } bk_err_t bk_h264_set_qp(h264_qp_t *qp) { H264_RETURN_ON_DRIVER_NOT_INIT(); if(qp->init_qp > MAX_QP || qp->init_qp < MIN_QP) { return BK_ERR_H264_INVALID_QP; } if (qp->i_min_qp >= qp->i_max_qp || qp->p_min_qp >= qp->p_max_qp) { return BK_ERR_H264_INVALID_QP; } if (qp->i_max_qp > MAX_QP || qp->p_max_qp > MAX_QP) { return BK_ERR_H264_INVALID_QP; } h264_config_t param_set = {0}; param_set.qp = qp->init_qp; param_set.cqp_off = h264_commom_config.cqp_off; param_set.tqp = h264_commom_config.tqp; param_set.iframe_max_qp = qp->i_max_qp; param_set.iframe_min_qp = h264_commom_config.iframe_min_qp; param_set.pframe_max_qp = qp->p_max_qp; param_set.pframe_min_qp = h264_commom_config.pframe_min_qp; const h264_config_t *para = ¶m_set; h264_hal_qp_config(&s_h264.hal,para); return BK_OK; } bk_err_t bk_h264_set_quality(uint32_t imb_bits, uint32_t pmb_bits) { H264_RETURN_ON_DRIVER_NOT_INIT(); if(imb_bits > MAX_IFRAME_BITS || imb_bits < MIN_FRAME_BITS) { return BK_ERR_H264_INVALID_IMB_BITS; } if(pmb_bits > MAX_PFRAME_BITS || pmb_bits < MIN_FRAME_BITS) { return BK_ERR_H264_INVALID_PMB_BITS; } h264_config_t param_set = {0}; param_set.imb_bits = imb_bits; param_set.pmb_bits = pmb_bits; const h264_config_t *para = ¶m_set; h264_hal_mb_bits_config(&s_h264.hal, para); return BK_OK; } bk_err_t bk_h264_deblocking_filter_config_init(const h264_config_t *config, uint32_t alpha_off, uint32_t beta_off) { H264_RETURN_ON_DRIVER_NOT_INIT(); return h264_hal_filter_config(&s_h264.hal, config, alpha_off, beta_off); } bk_err_t bk_h264_encode_enable() { H264_RETURN_ON_DRIVER_NOT_INIT(); h264_hal_encode_enable(&s_h264.hal); return BK_OK; } bk_err_t bk_h264_encode_disable() { H264_RETURN_ON_DRIVER_NOT_INIT(); h264_hal_encode_disable(&s_h264.hal); return BK_OK; } bk_err_t bk_h264_camera_gpio_set(void) { h264_gpio_map_t h264_gpio_map_table[] = H264_GPIO_MAP; for (uint32_t i = 0; i < 10; i++) { gpio_dev_unmap(h264_gpio_map_table[i].gpio_id); gpio_dev_map(h264_gpio_map_table[i].gpio_id, h264_gpio_map_table[i].dev); } return BK_OK; } bk_err_t bk_h264_camera_clk_enhance(void) { h264_gpio_map_t h264_gpio_map_table[] = H264_GPIO_MAP; for (uint32_t i = 10; i < 12; i++) { gpio_dev_unmap(h264_gpio_map_table[i].gpio_id); gpio_dev_map(h264_gpio_map_table[i].gpio_id, h264_gpio_map_table[i].dev); } bk_gpio_disable_output(h264_gpio_map_table[0].gpio_id); bk_gpio_set_capacity(h264_gpio_map_table[0].gpio_id,1); return BK_OK; } uint32_t bk_h264_get_encode_count() { H264_RETURN_ON_DRIVER_NOT_INIT(); return h264_hal_get_encode_count(&s_h264.hal); } uint32_t bk_h264_get_p_frame_number(void) { H264_RETURN_ON_DRIVER_NOT_INIT(); return h264_hal_get_num_pframe(&s_h264.hal); } bk_err_t bk_h264_get_fifo_addr(uint32_t *fifo_addr) { *fifo_addr = H264_R_RX_FIFO; return BK_OK; } bk_err_t bk_h264_register_isr(h264_isr_type_t type_id, h264_isr_t isr, void *param) { if(type_id >= H264_ISR_MAX) { return BK_ERR_H264_ISR_INVALID_ID; } uint32_t int_level = rtos_disable_int(); s_h264.h264_isr_handler[type_id].isr_handler = isr; s_h264.h264_isr_handler[type_id].param = param; rtos_enable_int(int_level); return BK_OK; } bk_err_t bk_h264_unregister_isr(h264_isr_type_t type_id) { if(type_id >= H264_ISR_MAX) { return BK_ERR_H264_ISR_INVALID_ID; } uint32_t int_level = rtos_disable_int(); s_h264.h264_isr_handler[type_id].isr_handler = NULL; s_h264.h264_isr_handler[type_id].param = NULL; rtos_enable_int(int_level); return BK_OK; } bk_err_t bk_h264_get_h264_base_config(h264_base_config_t *config) { H264_RETURN_ON_DRIVER_NOT_INIT(); if (config == NULL) { H264_LOGE("%s, config is null ptr\r\n"); return BK_FAIL; } config->h264_state = s_h264.hal.hw->enc_ctrl.enc_en; config->profile_id = s_h264.hal.hw->profile_idc & 0x1; config->p_frame_cnt = bk_h264_get_p_frame_number() & 0xFF; config->qp = s_h264.hal.hw->qp & 0xFF; config->num_imb_bits = s_h264.hal.hw->iframe_bit_ctrl.num_imb_bits & 0xFFF; config->num_pmb_bits = s_h264.hal.hw->num_pmb_bits & 0xFFFF; config->width = s_h264.hal.hw->img_width & 0xFFFF; config->height = s_h264.hal.hw->img_height & 0xFFFF; return BK_OK; } static void h264_isr(void) { uint32_t int_status = h264_hal_get_int_stat(&s_h264.hal); h264_hal_int_clear(&s_h264.hal, int_status); H264_LOGD("h264 int status: %x \r\n ", int_status); if (int_status & INT_SKIP_FRAME) { H264_INT_INC(h264_int_count,H264_SKIP_FRAME); if (s_h264.h264_isr_handler[H264_SKIP_FRAME].isr_handler) { s_h264.h264_isr_handler[H264_SKIP_FRAME].isr_handler(0, s_h264.h264_isr_handler[H264_SKIP_FRAME].param); } } if (int_status & INT_FINAL_OUT) { H264_INT_INC(h264_int_count,H264_FINAL_OUT); if (s_h264.h264_isr_handler[H264_FINAL_OUT].isr_handler) { s_h264.h264_isr_handler[H264_FINAL_OUT].isr_handler(0, s_h264.h264_isr_handler[H264_FINAL_OUT].param); } if (h264_compress.enable) { bk_h264_set_qp(&h264_compress.qp); bk_h264_set_quality(h264_compress.imb_bits, h264_compress.pmb_bits); h264_compress.enable = 0; } } if (int_status & INT_LINE_DONE) { H264_INT_INC(h264_int_count,H264_LINE_DONE); if (s_h264.h264_isr_handler[H264_LINE_DONE].isr_handler) { s_h264.h264_isr_handler[H264_LINE_DONE].isr_handler(0, s_h264.h264_isr_handler[H264_LINE_DONE].param); } } } bk_err_t bk_h264_int_count_show(void) { H264_LOGI("h264 int SKIP_FRAME count: %d \r\n ", h264_int_count[H264_SKIP_FRAME]); H264_LOGI("h264 int FINAL_OUT count: %d \r\n ", h264_int_count[H264_FINAL_OUT]); H264_LOGI("h264 int LINE_DONE count: %d \r\n ", h264_int_count[H264_LINE_DONE]); return BK_OK; } bk_err_t bk_h264_config_reset(void) { int ret = BK_OK; uint32_t fps = 0; const h264_config_t *config = &h264_commom_config; compress_ratio_t ratio = {0}; H264_RETURN_ON_DRIVER_NOT_INIT(); uint16_t width = s_h264.hal.hw->img_width & 0xFFFF; uint16_t height = s_h264.hal.hw->img_height & 0xFFFF; ratio.qp.init_qp = s_h264.hal.hw->qp & 0xFF; ratio.qp.i_max_qp = s_h264.hal.hw->iframe_qp_boundary.v & 0x3F; ratio.qp.p_max_qp = s_h264.hal.hw->pframe_qp_boudary.v & 0x3F; ratio.imb_bits = s_h264.hal.hw->iframe_bit_ctrl.v & 0xFFF; ratio.pmb_bits = s_h264.hal.hw->num_pmb_bits & 0xFFFF; fps = s_h264.hal.hw->vui_time_scale_L & 0xFFFF; h264_hal_reset(&s_h264.hal); /* h264 global ctrl set */ h264_hal_set_global_ctrl(&s_h264.hal); h264_hal_enable_external_clk_en(&s_h264.hal); if(h264_hal_set_img_width(&s_h264.hal, width, height)) { return BK_ERR_H264_INVALID_RESOLUTION_TYPE; } h264_hal_gop_config(&s_h264.hal, config); h264_hal_qp_config(&s_h264.hal, config); h264_hal_idc_config(&s_h264.hal, config); h264_hal_mb_config(&s_h264.hal, config); h264_hal_scale_factor_config(&s_h264.hal); h264_hal_vui_config(&s_h264.hal, config); h264_hal_cpb_vui_config(&s_h264.hal, config); h264_hal_frame_cbr_config(&s_h264.hal, config); bk_h264_set_qp(&ratio.qp); bk_h264_set_quality(ratio.imb_bits, ratio.pmb_bits); bk_h264_updata_encode_fps(fps); h264_int_enable(); return ret; } bk_err_t bk_h264_soft_reset(void) { H264_RETURN_ON_DRIVER_NOT_INIT(); h264_hal_soft_reset_active(&s_h264.hal); h264_hal_soft_reset_deactive(&s_h264.hal); return BK_OK; } bk_err_t bk_h264_updata_encode_fps(uint32 fps) { H264_RETURN_ON_DRIVER_NOT_INIT(); h264_hal_set_vui_fps(&s_h264.hal, fps); return BK_OK; }