From 46539beba2d6702e7cb0eae44f0be1ac2c375c6c Mon Sep 17 00:00:00 2001 From: Hui Zhang Date: Wed, 25 Jul 2018 16:52:14 +0800 Subject: [PATCH] PD#170564: optimize mpeg4 decoedr Change-Id: I3499150842ece14f4a6302840aff65c5414e29e1 Signed-off-by: Hui Zhang --- .../common/firmware/firmware_type.c | 6 +- .../frame_provider/decoder/mpeg4/vmpeg4.c | 54 ++++------- .../decoder/mpeg4/vmpeg4_multi.c | 90 ++++++++++-------- firmware/video/video_ucode.bin | Bin 870144 -> 826880 bytes 4 files changed, 72 insertions(+), 78 deletions(-) diff --git a/drivers/amlogic/media_modules/common/firmware/firmware_type.c b/drivers/amlogic/media_modules/common/firmware/firmware_type.c index b2d9f17d6572..d17defc35957 100644 --- a/drivers/amlogic/media_modules/common/firmware/firmware_type.c +++ b/drivers/amlogic/media_modules/common/firmware/firmware_type.c @@ -4,9 +4,9 @@ static const struct format_name_s format_name[] = { {VIDEO_DEC_MPEG12, "mpeg12"}, {VIDEO_DEC_MPEG12_MULTI, "mpeg12_multi"}, - {VIDEO_DEC_MPEG4_3, "divx311"}, - {VIDEO_DEC_MPEG4_4, "divx4x"}, - {VIDEO_DEC_MPEG4_4_MULTI, "divx4x_multi"}, + {VIDEO_DEC_MPEG4_3, "mpeg4_3"}, + {VIDEO_DEC_MPEG4_4, "mpeg4_4"}, + {VIDEO_DEC_MPEG4_4_MULTI, "mpeg4_4_multi"}, {VIDEO_DEC_MPEG4_5, "xvid"}, {VIDEO_DEC_MPEG4_5_MULTI, "xvid_multi"}, {VIDEO_DEC_H263, "h263"}, diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4.c b/drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4.c index f6a5910316b4..1947be1dbed6 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4.c @@ -740,6 +740,8 @@ static void vmpeg_put_timer_func(unsigned long arg) int vmpeg4_dec_status(struct vdec_s *vdec, struct vdec_info *vstatus) { + if (NULL == gvs) + return -1; vstatus->frame_width = vmpeg4_amstream_dec_info.width; vstatus->frame_height = vmpeg4_amstream_dec_info.height; if (0 != vmpeg4_amstream_dec_info.rate) @@ -1017,38 +1019,19 @@ static s32 vmpeg4_init(void) if (IS_ERR_OR_NULL(buf)) return -ENOMEM; - - query_video_status(0, &trickmode_fffb); - amlog_level(LOG_LEVEL_INFO, "vmpeg4_init\n"); - init_timer(&recycle_timer); - stat |= STAT_TIMER_INIT; - - amvdec_enable(); - - vmpeg4_local_init(); - - if (vmpeg4_amstream_dec_info.format == VIDEO_DEC_FORMAT_MPEG4_3) { - size = get_firmware_data(VIDEO_DEC_MPEG4_3, buf); - - amlog_level(LOG_LEVEL_INFO, "load VIDEO_DEC_FORMAT_MPEG4_3\n"); - } else if (vmpeg4_amstream_dec_info.format == - VIDEO_DEC_FORMAT_MPEG4_4) { - size = get_firmware_data(VIDEO_DEC_MPEG4_4, buf); - - amlog_level(LOG_LEVEL_INFO, "load VIDEO_DEC_FORMAT_MPEG4_4\n"); - } else if (vmpeg4_amstream_dec_info.format == + if (vmpeg4_amstream_dec_info.format == VIDEO_DEC_FORMAT_MPEG4_5) { size = get_firmware_data(VIDEO_DEC_MPEG4_5, buf); - - amlog_level(LOG_LEVEL_INFO, "load VIDEO_DEC_FORMAT_MPEG4_5\n"); + pr_info("load VIDEO_DEC_FORMAT_MPEG4_5\n"); } else if (vmpeg4_amstream_dec_info.format == VIDEO_DEC_FORMAT_H263) { size = get_firmware_data(VIDEO_DEC_H263, buf); - amlog_level(LOG_LEVEL_INFO, "load VIDEO_DEC_FORMAT_H263\n"); + pr_info("load VIDEO_DEC_FORMAT_H263\n"); } else - amlog_level(LOG_LEVEL_ERROR, "not supported MPEG4 format\n"); + pr_err("not supported MPEG4 format %d\n", + vmpeg4_amstream_dec_info.format); if (size < 0) { pr_err("get firmware fail."); @@ -1059,29 +1042,34 @@ static s32 vmpeg4_init(void) if (size == 1) pr_info ("tee load ok"); else if (amvdec_loadmc_ex(VFORMAT_MPEG4, NULL, buf) < 0) { - amvdec_disable(); vfree(buf); return -EBUSY; } vfree(buf); - stat |= STAT_MC_LOAD; + query_video_status(0, &trickmode_fffb); - /* enable AMRISC side protocol */ - r = vmpeg4_prot_init(); - if (r < 0) - return r; + init_timer(&recycle_timer); + stat |= STAT_TIMER_INIT; if (vdec_request_irq(VDEC_IRQ_1, vmpeg4_isr, "vmpeg4-irq", (void *)vmpeg4_dec_id)) { - amvdec_disable(); - amlog_level(LOG_LEVEL_ERROR, "vmpeg4 irq register error.\n"); return -ENOENT; } - stat |= STAT_ISR_REG; + vmpeg4_local_init(); + /* enable AMRISC side protocol */ + r = vmpeg4_prot_init(); + if (r < 0) { + if (mm_blk_handle) { + decoder_bmmu_box_free(mm_blk_handle); + mm_blk_handle = NULL; + } + return r; + } + amvdec_enable(); fr_hint_status = VDEC_NO_NEED_HINT; #ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER vf_provider_init(&vmpeg_vf_prov, PROVIDER_NAME, &vmpeg_vf_provider, diff --git a/drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4_multi.c b/drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4_multi.c index f21d830360b9..c86a925ee5a8 100644 --- a/drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4_multi.c +++ b/drivers/amlogic/media_modules/frame_provider/decoder/mpeg4/vmpeg4_multi.c @@ -46,7 +46,7 @@ #define DRIVER_NAME "ammvdec_mpeg4" #define MODULE_NAME "ammvdec_mpeg4" -#define MEM_NAME "codec_mpeg4" +#define MEM_NAME "codec_mmpeg4" #define DEBUG_PTS @@ -806,7 +806,8 @@ static int vmpeg_vf_states(struct vframe_states *states, void *op_arg) static int dec_status(struct vdec_s *vdec, struct vdec_info *vstatus) { struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private; - + if (NULL == hw) + return -1; vstatus->frame_width = hw->vmpeg4_amstream_dec_info.width; vstatus->frame_height = hw->vmpeg4_amstream_dec_info.height; if (0 != hw->vmpeg4_amstream_dec_info.rate) @@ -1044,7 +1045,7 @@ static void vmpeg4_local_init(struct vdec_mpeg4_hw_s *hw) INIT_WORK(&hw->work, vmpeg4_work); } -static s32 vmpeg4_init(struct vdec_mpeg4_hw_s *hw) +static s32 vmmpeg4_init(struct vdec_mpeg4_hw_s *hw) { int trickmode_fffb = 0; int size = -1, fw_size = 0x1000 * 16; @@ -1054,17 +1055,7 @@ static s32 vmpeg4_init(struct vdec_mpeg4_hw_s *hw) if (IS_ERR_OR_NULL(fw)) return -ENOMEM; - if (hw->vmpeg4_amstream_dec_info.format == - VIDEO_DEC_FORMAT_MPEG4_3) { - size = get_firmware_data(VIDEO_DEC_MPEG4_3, fw->data); - - pr_info("load VIDEO_DEC_FORMAT_MPEG4_3\n"); - } else if (hw->vmpeg4_amstream_dec_info.format == - VIDEO_DEC_FORMAT_MPEG4_4) { - size = get_firmware_data(VIDEO_DEC_MPEG4_4, fw->data); - - pr_info("load VIDEO_DEC_FORMAT_MPEG4_4\n"); - } else if (hw->vmpeg4_amstream_dec_info.format == + if (hw->vmpeg4_amstream_dec_info.format == VIDEO_DEC_FORMAT_MPEG4_5) { size = get_firmware_data(VIDEO_DEC_MPEG4_5, fw->data); @@ -1072,9 +1063,10 @@ static s32 vmpeg4_init(struct vdec_mpeg4_hw_s *hw) } else if (hw->vmpeg4_amstream_dec_info.format == VIDEO_DEC_FORMAT_H263) { size = get_firmware_data(VIDEO_DEC_H263, fw->data); - pr_info("load VIDEO_DEC_FORMAT_H263\n"); - } + } else + pr_info("not supported MPEG4 format %d\n", + hw->vmpeg4_amstream_dec_info.format); if (size < 0) { pr_err("get firmware fail."); @@ -1087,7 +1079,7 @@ static s32 vmpeg4_init(struct vdec_mpeg4_hw_s *hw) query_video_status(0, &trickmode_fffb); - pr_info("vmpeg4_init\n"); + pr_info("%s\n", __func__); amvdec_enable(); @@ -1123,7 +1115,7 @@ static void run(struct vdec_s *vdec, unsigned long mask, ret = vdec_prepare_input(vdec, &hw->chunk); if (ret < 0) { - pr_debug("amvdec_mpeg4: Input not ready\n"); + pr_debug("amvdec_mmpeg4: Input not ready\n"); hw->dec_result = DEC_RESULT_AGAIN; schedule_work(&hw->work); return; @@ -1146,7 +1138,7 @@ static void run(struct vdec_s *vdec, unsigned long mask, if (vmpeg4_hw_ctx_restore(hw) < 0) { hw->dec_result = DEC_RESULT_ERROR; - pr_err("amvdec_mpeg4: error HW context restore\n"); + pr_err("amvdec_mmpeg4: error HW context restore\n"); schedule_work(&hw->work); return; } @@ -1161,31 +1153,31 @@ static void reset(struct vdec_s *vdec) { struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *)vdec->private; - pr_info("amvdec_mpeg4: reset.\n"); + pr_info("amvdec_mmpeg4: reset.\n"); vmpeg4_local_init(hw); hw->ctx_valid = false; } -static int amvdec_mpeg4_probe(struct platform_device *pdev) +static int ammvdec_mpeg4_probe(struct platform_device *pdev) { struct vdec_s *pdata = *(struct vdec_s **)pdev->dev.platform_data; struct vdec_mpeg4_hw_s *hw = NULL; - pr_info("amvdec_mpeg4[%d] probe start.\n", pdev->id); + pr_info("%s [%d] probe start.\n", __func__, pdev->id); if (pdata == NULL) { - pr_err("ammvdec_mpeg4 memory resource undefined.\n"); + pr_err("%s memory resource undefined.\n", __func__); return -EFAULT; } - hw = (struct vdec_mpeg4_hw_s *)devm_kzalloc(&pdev->dev, - sizeof(struct vdec_mpeg4_hw_s), GFP_KERNEL); + hw = vmalloc(sizeof(struct vdec_mpeg4_hw_s)); if (hw == NULL) { pr_info("\namvdec_mpeg4 decoder driver alloc failed\n"); return -ENOMEM; } + memset(hw, 0, sizeof(struct vdec_mpeg4_hw_s)); pdata->private = hw; pdata->dec_status = dec_status; @@ -1220,6 +1212,10 @@ static int amvdec_mpeg4_probe(struct platform_device *pdev) pr_err("codec_mm alloc failed, request buf size 0x%lx\n", hw->cma_alloc_count * PAGE_SIZE); hw->cma_alloc_count = 0; + if (hw) { + vfree((void *)hw); + hw = NULL; + } return -ENOMEM; } hw->buf_start = hw->cma_alloc_addr; @@ -1228,9 +1224,16 @@ static int amvdec_mpeg4_probe(struct platform_device *pdev) if (pdata->sys_info) hw->vmpeg4_amstream_dec_info = *pdata->sys_info; - if (vmpeg4_init(hw) < 0) { - pr_err("amvdec_mpeg4 init failed.\n"); - + if (vmmpeg4_init(hw) < 0) { + pr_err("%s init failed.\n", __func__); + if (hw->cma_alloc_addr) { + codec_mm_free_for_dma(MEM_NAME, hw->cma_alloc_addr); + hw->cma_alloc_count = 0; + } + if (hw) { + vfree((void *)hw); + hw = NULL; + } return -ENODEV; } @@ -1240,7 +1243,7 @@ static int amvdec_mpeg4_probe(struct platform_device *pdev) return 0; } -static int amvdec_mpeg4_remove(struct platform_device *pdev) +static int ammvdec_mpeg4_remove(struct platform_device *pdev) { struct vdec_mpeg4_hw_s *hw = (struct vdec_mpeg4_hw_s *) @@ -1259,7 +1262,10 @@ static int amvdec_mpeg4_remove(struct platform_device *pdev) vfree(hw->fw); hw->fw = NULL; - + if (hw) { + vfree((void *)hw); + hw = NULL; + } pr_info("pts hit %d, pts missed %d, i hit %d, missed %d\n", hw->pts_hit, hw->pts_missed, hw->pts_i_hit, hw->pts_i_missed); pr_info("total frame %d, rate %d\n", hw->total_frame, @@ -1270,9 +1276,9 @@ static int amvdec_mpeg4_remove(struct platform_device *pdev) /****************************************/ -static struct platform_driver amvdec_mpeg4_driver = { - .probe = amvdec_mpeg4_probe, - .remove = amvdec_mpeg4_remove, +static struct platform_driver ammvdec_mpeg4_driver = { + .probe = ammvdec_mpeg4_probe, + .remove = ammvdec_mpeg4_remove, #ifdef CONFIG_PM .suspend = amvdec_suspend, .resume = amvdec_resume, @@ -1287,29 +1293,29 @@ static struct codec_profile_t amvdec_mpeg4_profile = { .profile = "" }; -static int __init amvdec_mmpeg4_driver_init_module(void) +static int __init ammvdec_mpeg4_driver_init_module(void) { - pr_info("amvdec_mmpeg4 module init\n"); + pr_info("%s \n", __func__); - if (platform_driver_register(&amvdec_mpeg4_driver)) { - pr_err("failed to register amvdec_mpeg4 driver\n"); + if (platform_driver_register(&ammvdec_mpeg4_driver)) { + pr_err("failed to register ammvdec_mpeg4 driver\n"); return -ENODEV; } vcodec_profile_register(&amvdec_mpeg4_profile); return 0; } -static void __exit amvdec_mmpeg4_driver_remove_module(void) +static void __exit ammvdec_mpeg4_driver_remove_module(void) { - pr_info("amvdec_mmpeg4 module remove.\n"); + pr_info("ammvdec_mpeg4 module remove.\n"); - platform_driver_unregister(&amvdec_mpeg4_driver); + platform_driver_unregister(&ammvdec_mpeg4_driver); } /****************************************/ -module_init(amvdec_mmpeg4_driver_init_module); -module_exit(amvdec_mmpeg4_driver_remove_module); +module_init(ammvdec_mpeg4_driver_init_module); +module_exit(ammvdec_mpeg4_driver_remove_module); MODULE_DESCRIPTION("AMLOGIC MPEG4 Video Decoder Driver"); MODULE_LICENSE("GPL"); diff --git a/firmware/video/video_ucode.bin b/firmware/video/video_ucode.bin index 7bebd868c859033bdafc1f6a2c7dd454eb1d462a..8b14d99f454b89f08e9b04d7ff31374063f99bde 100644 GIT binary patch delta 3468 zcmZqZGi}&oRPR#o!}q6HweOFo{xK0J)Z88}zaaiK_i_2o{7EL3Zv4tK?`-3kfA-(9 z;F{aNZ(rA(7?)k6ou(5o`>N$xuYic_s}C_Y{af+iw9m$3pNBfWy>qTqd}#Q4rd?{k zRm1O87IQ9(uTTG-n(nKhC%__QxAL{0)0X`o1vjbap6*)~DE;G7J=?Mr`EC`~S#6T{ zqY54$mKM8bf80gM8##YT=&OOlKqd~>LE za9A?^x=wR(&(WFJwkp1yQ$FnubK^3@D`64ygU#H|e7!E^AF%y(hN}4;kJ7u0$FF{2 zJ#M|U`uLQ|8y3ac@I6rZ(_P9xJ=WXVF@RwX4}*{P#;q!wc^Lzk*pt#s4J?c-Ckrx) zFlUrzPOf2=v1AA-O;zwJ%~3EmR4_EKGBUL?vQ#iKFtlKR0;nb!mw};xfnnx}_~^}v z5eAH#SYr#RWUK((SX;);ycGe0R5BOEx!qKAE{d`LXkzTPLPny^H8vm^X|rIFw(SY^ z%ynR3K$siO6zfQ2tPygr0kXNXm|_iSVeVP#nL7c=y<3=LCsN6|$i{A)Oe1sESZL$k zozycIC7JoKQZ1RGnA=Z1bAhD;B3oP{zK|r8El|vLWur~;u!BbCYO~YEz4J&g*ARa( z2}}>OA;qKx<8}@~j!>e@Gm;Drp_ReYX=U&&S{Q7=xJ{Om_`FOYhz;Oz2Q)Wk delta 10610 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 BKb-&o