| /* |
| * drivers/amlogic/media/frame_provider/decoder/h264/vh264.c |
| * |
| * Copyright (C) 2016 Amlogic, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| */ |
| |
| #define DEBUG |
| #include <linux/kernel.h> |
| #include <linux/types.h> |
| #include <linux/errno.h> |
| #include <linux/interrupt.h> |
| #include <linux/timer.h> |
| #include <linux/kfifo.h> |
| #include <linux/platform_device.h> |
| #include <linux/amlogic/media/utils/amstream.h> |
| #include <linux/amlogic/media/frame_sync/ptsserv.h> |
| #include <linux/amlogic/media/vfm/vframe.h> |
| #include <linux/amlogic/media/vfm/vframe_provider.h> |
| #include <linux/amlogic/media/vfm/vframe_receiver.h> |
| #include <linux/amlogic/media/utils/vformat.h> |
| #include <linux/amlogic/media/frame_sync/tsync.h> |
| #include <linux/workqueue.h> |
| #include <linux/dma-mapping.h> |
| #include <linux/atomic.h> |
| #include <linux/module.h> |
| #include <linux/slab.h> |
| #include "../../../stream_input/amports/amports_priv.h" |
| #include <linux/amlogic/media/canvas/canvas.h> |
| #include "../utils/vdec.h" |
| #include <linux/amlogic/media/utils/vdec_reg.h> |
| #include "../utils/amvdec.h" |
| #include "vh264.h" |
| #include "../../../stream_input/amports/streambuf.h" |
| #include <linux/delay.h> |
| #include <linux/amlogic/media/video_sink/video.h> |
| //#include <linux/amlogic/tee.h> |
| #include <uapi/linux/tee.h> |
| #include <linux/amlogic/media/ge2d/ge2d.h> |
| #include "../utils/decoder_mmu_box.h" |
| #include "../utils/decoder_bmmu_box.h" |
| #include <linux/amlogic/media/codec_mm/codec_mm.h> |
| #include <linux/amlogic/media/codec_mm/configs.h> |
| #include "../utils/firmware.h" |
| #include "../../../common/chips/decoder_cpu_ver_info.h" |
| #include <linux/uaccess.h> |
| |
| #define DRIVER_NAME "amvdec_h264" |
| #define MODULE_NAME "amvdec_h264" |
| #define MEM_NAME "codec_264" |
| #define HANDLE_H264_IRQ |
| |
| #if 0 |
| /* currently, only iptv supports this function*/ |
| #define SUPPORT_BAD_MACRO_BLOCK_REDUNDANCY |
| #endif |
| |
| /* #define DEBUG_PTS */ |
| #if 0 /* MESON_CPU_TYPE <= MESON_CPU_TYPE_MESON6TV */ |
| #define DROP_B_FRAME_FOR_1080P_50_60FPS |
| #endif |
| #define RATE_MEASURE_NUM 8 |
| #define RATE_CORRECTION_THRESHOLD 5 |
| #define RATE_24_FPS 4004 /* 23.97 */ |
| #define RATE_25_FPS 3840 /* 25 */ |
| #define DUR2PTS(x) ((x)*90/96) |
| #define PTS2DUR(x) ((x)*96/90) |
| #define DUR2PTS_REM(x) (x*90 - DUR2PTS(x)*96) |
| #define FIX_FRAME_RATE_CHECK_IDRFRAME_NUM 2 |
| #define VDEC_CLOCK_ADJUST_FRAME 30 |
| |
| static inline bool close_to(int a, int b, int m) |
| { |
| return (abs(a - b) < m) ? true : false; |
| } |
| |
| static DEFINE_MUTEX(vh264_mutex); |
| #define DEF_BUF_START_ADDR 0x1000000 |
| #define V_BUF_ADDR_OFFSET_NEW (0x1ee000) |
| #define V_BUF_ADDR_OFFSET (0x13e000) |
| |
| #define PIC_SINGLE_FRAME 0 |
| #define PIC_TOP_BOT_TOP 1 |
| #define PIC_BOT_TOP_BOT 2 |
| #define PIC_DOUBLE_FRAME 3 |
| #define PIC_TRIPLE_FRAME 4 |
| #define PIC_TOP_BOT 5 |
| #define PIC_BOT_TOP 6 |
| #define PIC_INVALID 7 |
| |
| #define EXTEND_SAR 0xff |
| |
| #define VF_POOL_SIZE 64 |
| #define VF_BUF_NUM 24 |
| #define WORKSPACE_BUF_NUM 2 |
| #define PUT_INTERVAL (HZ/100) |
| #define NO_DISP_WD_COUNT (3 * HZ / PUT_INTERVAL) |
| |
| #define SWITCHING_STATE_OFF 0 |
| #define SWITCHING_STATE_ON_CMD3 1 |
| #define SWITCHING_STATE_ON_CMD1 2 |
| #define SWITCHING_STATE_ON_CMD1_PENDING 3 |
| |
| |
| #define DEC_CONTROL_FLAG_FORCE_2997_1080P_INTERLACE 0x0001 |
| #define DEC_CONTROL_FLAG_FORCE_2500_576P_INTERLACE 0x0002 |
| #define DEC_CONTROL_FLAG_DISABLE_FAST_POC 0x0004 |
| |
| #define INCPTR(p) ptr_atomic_wrap_inc(&p) |
| |
| #define SLICE_TYPE_I 2 |
| #define SLICE_TYPE_P 5 |
| #define SLICE_TYPE_B 6 |
| |
| struct buffer_spec_s { |
| unsigned int y_addr; |
| unsigned int u_addr; |
| unsigned int v_addr; |
| |
| int y_canvas_index; |
| int u_canvas_index; |
| int v_canvas_index; |
| |
| unsigned int y_canvas_width; |
| unsigned int u_canvas_width; |
| unsigned int v_canvas_width; |
| |
| unsigned int y_canvas_height; |
| unsigned int u_canvas_height; |
| unsigned int v_canvas_height; |
| |
| unsigned long phy_addr; |
| int alloc_count; |
| }; |
| |
| #define spec2canvas(x) \ |
| (((x)->v_canvas_index << 16) | \ |
| ((x)->u_canvas_index << 8) | \ |
| ((x)->y_canvas_index << 0)) |
| |
| static struct vframe_s *vh264_vf_peek(void *); |
| static struct vframe_s *vh264_vf_get(void *); |
| static void vh264_vf_put(struct vframe_s *, void *); |
| static int vh264_vf_states(struct vframe_states *states, void *); |
| static int vh264_event_cb(int type, void *data, void *private_data); |
| |
| static void vh264_prot_init(void); |
| static int vh264_local_init(void); |
| static void vh264_put_timer_func(struct timer_list *timer); |
| static void stream_switching_done(void); |
| |
| static const char vh264_dec_id[] = "vh264-dev"; |
| |
| #define PROVIDER_NAME "decoder.h264" |
| |
| static const struct vframe_operations_s vh264_vf_provider_ops = { |
| .peek = vh264_vf_peek, |
| .get = vh264_vf_get, |
| .put = vh264_vf_put, |
| .event_cb = vh264_event_cb, |
| .vf_states = vh264_vf_states, |
| }; |
| |
| static struct vframe_provider_s vh264_vf_prov; |
| /*TODO irq*/ |
| #if 1 |
| static u32 frame_width, frame_height, frame_dur, frame_prog, frame_packing_type, |
| last_duration; |
| static u32 saved_resolution; |
| static u32 last_mb_width, last_mb_height; |
| #else |
| static u32 frame_buffer_size; |
| static u32 frame_width, frame_height, frame_dur, frame_prog, last_duration; |
| static u32 last_mb_width, last_mb_height; |
| static u32 frame_packing_type; |
| #endif |
| static DECLARE_KFIFO(newframe_q, struct vframe_s *, VF_POOL_SIZE); |
| static DECLARE_KFIFO(display_q, struct vframe_s *, VF_POOL_SIZE); |
| static DECLARE_KFIFO(recycle_q, struct vframe_s *, VF_POOL_SIZE); |
| static DECLARE_KFIFO(delay_display_q, struct vframe_s *, VF_POOL_SIZE); |
| |
| static struct vframe_s vfpool[VF_POOL_SIZE]; |
| static s32 vfbuf_use[VF_BUF_NUM]; |
| static struct buffer_spec_s buffer_spec[VF_BUF_NUM]; |
| static struct buffer_spec_s fense_buffer_spec[2]; |
| /* disp buf + keep buf+ fense buf + workspace */ |
| |
| #define MAX_BLK_BUFFERS (VF_BUF_NUM + 2 + WORKSPACE_BUF_NUM) |
| #define VF_BUFFER_IDX(n) (WORKSPACE_BUF_NUM + n) |
| #define FENSE_BUFFER_IDX(n) (WORKSPACE_BUF_NUM + VF_BUF_NUM + n) |
| |
| #define USER_DATA_RUND_SIZE (USER_DATA_SIZE + 4096) |
| static struct vframe_s fense_vf[2]; |
| |
| static struct timer_list recycle_timer; |
| static u32 stat; |
| static s32 buf_offset; |
| static u32 pts_outside; |
| static u32 sync_outside; |
| static u32 dec_control; |
| static u32 vh264_ratio; |
| static u32 vh264_rotation; |
| static u32 use_idr_framerate; |
| static u32 high_bandwidth; |
| |
| static u32 seq_info; |
| static u32 timing_info_present_flag; |
| static u32 fixed_frame_rate_flag; |
| static u32 fixed_frame_rate_check_count; |
| static u32 aspect_ratio_info; |
| static u32 num_units_in_tick; |
| static u32 time_scale; |
| static u32 h264_ar; |
| static u32 decoder_debug_flag; |
| static u32 dpb_size_adj = 6; |
| static u32 fr_hint_status; |
| |
| #ifdef DROP_B_FRAME_FOR_1080P_50_60FPS |
| static u32 last_interlaced; |
| #endif |
| static bool is_4k; |
| static unsigned char h264_first_pts_ready; |
| static bool h264_first_valid_pts_ready; |
| static u32 h264pts1, h264pts2; |
| static u32 h264_pts_count, duration_from_pts_done, duration_on_correcting; |
| static u32 vh264_error_count; |
| static u32 vh264_no_disp_count; |
| static u32 fatal_error_flag; |
| static u32 fatal_error_reset; |
| static u32 max_refer_buf = 1; |
| static u32 decoder_force_reset; |
| static unsigned int no_idr_error_count; |
| static unsigned int no_idr_error_max = 60; |
| static unsigned int canvas_mode; |
| |
| #ifdef SUPPORT_BAD_MACRO_BLOCK_REDUNDANCY |
| /* 0~128*/ |
| static u32 bad_block_scale; |
| #endif |
| static u32 enable_userdata_debug; |
| |
| static unsigned int enable_switch_fense = 1; |
| #define EN_SWITCH_FENCE() (enable_switch_fense && !is_4k) |
| static struct vframe_qos_s s_vframe_qos; |
| static int frame_count; |
| |
| #if 0 |
| static u32 vh264_no_disp_wd_count; |
| #endif |
| static u32 vh264_running; |
| static s32 vh264_stream_switching_state; |
| static s32 vh264_eos; |
| static struct vframe_s *p_last_vf; |
| static s32 iponly_early_mode; |
| static void *mm_blk_handle; |
| static int tvp_flag; |
| static bool is_reset; |
| |
| /*TODO irq*/ |
| #if 1 |
| static u32 last_pts, last_pts_remainder; |
| #else |
| static u32 last_pts; |
| #endif |
| static bool check_pts_discontinue; |
| static u32 wait_buffer_counter; |
| static u32 video_signal_from_vui; |
| |
| static uint error_recovery_mode; |
| static uint error_recovery_mode_in = 3; |
| static uint error_recovery_mode_use = 3; |
| |
| static uint mb_total = 0, mb_width = 0, mb_height; |
| static uint saved_idc_level; |
| #define UCODE_IP_ONLY 2 |
| #define UCODE_IP_ONLY_PARAM 1 |
| static uint ucode_type; |
| |
| #ifdef DEBUG_PTS |
| static unsigned long pts_missed, pts_hit; |
| #endif |
| static uint debugfirmware; |
| |
| static atomic_t vh264_active = ATOMIC_INIT(0); |
| static int vh264_reset; |
| static struct work_struct error_wd_work; |
| static struct work_struct stream_switching_work; |
| static struct work_struct set_parameter_work; |
| static struct work_struct notify_work; |
| static struct work_struct set_clk_work; |
| static struct work_struct userdata_push_work; |
| |
| struct h264_qos_data_node_t { |
| struct list_head list; |
| |
| uint32_t b_offset; |
| int poc; |
| /* picture qos infomation*/ |
| int max_qp; |
| int avg_qp; |
| int min_qp; |
| int max_skip; |
| int avg_skip; |
| int min_skip; |
| int max_mv; |
| int min_mv; |
| int avg_mv; |
| }; |
| |
| /*qos data records list waiting for match with picture that be display*/ |
| static struct list_head picture_qos_list; |
| /*free qos data records list*/ |
| static struct list_head free_qos_nodes_list; |
| #define MAX_FREE_QOS_NODES 64 |
| static struct h264_qos_data_node_t free_nodes[MAX_FREE_QOS_NODES]; |
| static struct work_struct qos_work; |
| static struct dec_sysinfo vh264_amstream_dec_info; |
| static dma_addr_t mc_dma_handle; |
| static void *mc_cpu_addr; |
| static u32 first_offset; |
| static u32 first_pts; |
| static u32 first_frame_size; |
| static u64 first_pts64; |
| static bool first_pts_cached; |
| static void *sei_data_buffer; |
| static dma_addr_t sei_data_buffer_phys; |
| static int clk_adj_frame_count; |
| |
| #define MC_OFFSET_HEADER 0x0000 |
| #define MC_OFFSET_DATA 0x1000 |
| #define MC_OFFSET_MMCO 0x2000 |
| #define MC_OFFSET_LIST 0x3000 |
| #define MC_OFFSET_SLICE 0x4000 |
| |
| #define MC_TOTAL_SIZE (20*SZ_1K) |
| #define MC_SWAP_SIZE (4*SZ_1K) |
| |
| #define MODE_ERROR 0 |
| #define MODE_FULL 1 |
| |
| static DEFINE_SPINLOCK(lock); |
| static DEFINE_SPINLOCK(prepare_lock); |
| static DEFINE_SPINLOCK(recycle_lock); |
| |
| static bool block_display_q; |
| static int vh264_stop(int mode); |
| static s32 vh264_init(void); |
| |
| |
| #define DFS_HIGH_THEASHOLD 3 |
| |
| static bool pts_discontinue; |
| |
| static struct ge2d_context_s *ge2d_videoh264_context; |
| |
| static struct vdec_info *gvs; |
| |
| static struct vdec_s *vdec_h264; |
| |
| static int ge2d_videoh264task_init(void) |
| { |
| if (ge2d_videoh264_context == NULL) |
| ge2d_videoh264_context = create_ge2d_work_queue(); |
| |
| if (ge2d_videoh264_context == NULL) { |
| pr_info("create_ge2d_work_queue video task failed\n"); |
| return -1; |
| } |
| return 0; |
| } |
| |
| static int ge2d_videoh264task_release(void) |
| { |
| if (ge2d_videoh264_context) { |
| destroy_ge2d_work_queue(ge2d_videoh264_context); |
| ge2d_videoh264_context = NULL; |
| } |
| return 0; |
| } |
| |
| static int ge2d_canvas_dup(struct canvas_s *srcy, struct canvas_s *srcu, |
| struct canvas_s *des, int format, u32 srcindex, |
| u32 desindex) |
| { |
| |
| struct config_para_ex_s ge2d_config; |
| /* pr_info("[%s]h264 ADDR srcy[0x%lx] srcu[0x%lx] des[0x%lx]\n", |
| * __func__, srcy->addr, srcu->addr, des->addr); |
| */ |
| memset(&ge2d_config, 0, sizeof(struct config_para_ex_s)); |
| |
| ge2d_config.alu_const_color = 0; |
| ge2d_config.bitmask_en = 0; |
| ge2d_config.src1_gb_alpha = 0; |
| |
| ge2d_config.src_planes[0].addr = srcy->addr; |
| ge2d_config.src_planes[0].w = srcy->width; |
| ge2d_config.src_planes[0].h = srcy->height; |
| |
| ge2d_config.src_planes[1].addr = srcu->addr; |
| ge2d_config.src_planes[1].w = srcu->width; |
| ge2d_config.src_planes[1].h = srcu->height; |
| |
| ge2d_config.dst_planes[0].addr = des->addr; |
| ge2d_config.dst_planes[0].w = des->width; |
| ge2d_config.dst_planes[0].h = des->height; |
| |
| ge2d_config.src_para.canvas_index = srcindex; |
| ge2d_config.src_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.src_para.format = format; |
| ge2d_config.src_para.fill_color_en = 0; |
| ge2d_config.src_para.fill_mode = 0; |
| ge2d_config.src_para.color = 0; |
| ge2d_config.src_para.top = 0; |
| ge2d_config.src_para.left = 0; |
| ge2d_config.src_para.width = srcy->width; |
| ge2d_config.src_para.height = srcy->height; |
| |
| ge2d_config.dst_para.canvas_index = desindex; |
| ge2d_config.dst_para.mem_type = CANVAS_TYPE_INVALID; |
| ge2d_config.dst_para.format = format; |
| ge2d_config.dst_para.fill_color_en = 0; |
| ge2d_config.dst_para.fill_mode = 0; |
| ge2d_config.dst_para.color = 0; |
| ge2d_config.dst_para.top = 0; |
| ge2d_config.dst_para.left = 0; |
| ge2d_config.dst_para.width = srcy->width; |
| ge2d_config.dst_para.height = srcy->height; |
| |
| if (ge2d_context_config_ex(ge2d_videoh264_context, &ge2d_config) < 0) { |
| pr_info("ge2d_context_config_ex failed\n"); |
| return -1; |
| } |
| |
| stretchblt_noalpha(ge2d_videoh264_context, 0, 0, srcy->width, |
| srcy->height, 0, 0, srcy->width, srcy->height); |
| |
| return 0; |
| } |
| |
| static inline int fifo_level(void) |
| { |
| return VF_POOL_SIZE - kfifo_len(&newframe_q); |
| } |
| |
| |
| void spec_set_canvas(struct buffer_spec_s *spec, |
| unsigned int width, unsigned int height) |
| { |
| int endian; |
| |
| endian = (canvas_mode == CANVAS_BLKMODE_LINEAR)?7:0; |
| config_cav_lut_ex(spec->y_canvas_index, |
| spec->y_addr, |
| width, height, |
| CANVAS_ADDR_NOWRAP, canvas_mode, endian, VDEC_1); |
| |
| config_cav_lut_ex(spec->u_canvas_index, |
| spec->u_addr, |
| width, height / 2, |
| CANVAS_ADDR_NOWRAP, canvas_mode, endian, VDEC_1); |
| |
| } |
| |
| static void vh264_notify_work(struct work_struct *work) |
| { |
| pr_info("frame duration changed %d\n", frame_dur); |
| vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_FR_HINT, |
| (void *)((unsigned long)frame_dur)); |
| |
| return; |
| } |
| |
| static void prepare_display_q(void) |
| { |
| unsigned long flags; |
| int count; |
| |
| spin_lock_irqsave(&prepare_lock, flags); |
| |
| if (block_display_q) { |
| spin_unlock_irqrestore(&prepare_lock, flags); |
| return; |
| } |
| |
| spin_unlock_irqrestore(&prepare_lock, flags); |
| |
| count = (int)VF_POOL_SIZE - |
| kfifo_len(&delay_display_q) - |
| kfifo_len(&display_q) - |
| kfifo_len(&recycle_q) - |
| kfifo_len(&newframe_q); |
| |
| if ((vh264_stream_switching_state != SWITCHING_STATE_OFF) |
| || !EN_SWITCH_FENCE()) |
| count = 0; |
| else |
| count = (count < 2) ? 0 : 2; |
| |
| while (kfifo_len(&delay_display_q) > count) { |
| struct vframe_s *vf; |
| |
| if (kfifo_get(&delay_display_q, &vf)) { |
| kfifo_put(&display_q, |
| (const struct vframe_s *)vf); |
| ATRACE_COUNTER(MODULE_NAME, vf->pts); |
| vf_notify_receiver(PROVIDER_NAME, |
| VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); |
| } |
| } |
| } |
| |
| static struct vframe_s *vh264_vf_peek(void *op_arg) |
| { |
| struct vframe_s *vf; |
| |
| if (kfifo_peek(&display_q, &vf)) |
| return vf; |
| |
| return NULL; |
| } |
| |
| static struct vframe_s *vh264_vf_get(void *op_arg) |
| { |
| struct vframe_s *vf; |
| |
| if (kfifo_get(&display_q, &vf)) |
| return vf; |
| |
| return NULL; |
| } |
| static bool vf_valid_check(struct vframe_s *vf) { |
| int i; |
| for (i = 0; i < VF_POOL_SIZE; i++) { |
| if (vf == &vfpool[i]) |
| return true; |
| } |
| pr_info(" invalid vf been put, vf = %p\n", vf); |
| for (i = 0; i < VF_POOL_SIZE; i++) { |
| pr_info("www valid vf[%d]= %p \n", i, &vfpool[i]); |
| } |
| return false; |
| } |
| |
| static void vh264_vf_put(struct vframe_s *vf, void *op_arg) |
| { |
| unsigned long flags; |
| |
| spin_lock_irqsave(&recycle_lock, flags); |
| |
| if ((vf != &fense_vf[0]) && (vf != &fense_vf[1])) { |
| if (vf && (vf_valid_check(vf) == true)) |
| kfifo_put(&recycle_q, (const struct vframe_s *)vf); |
| } |
| spin_unlock_irqrestore(&recycle_lock, flags); |
| } |
| |
| static int vh264_event_cb(int type, void *data, void *private_data) |
| { |
| if (type & VFRAME_EVENT_RECEIVER_RESET) { |
| unsigned long flags; |
| |
| amvdec_stop(); |
| #ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER |
| vf_light_unreg_provider(&vh264_vf_prov); |
| #endif |
| spin_lock_irqsave(&lock, flags); |
| vh264_local_init(); |
| vh264_prot_init(); |
| spin_unlock_irqrestore(&lock, flags); |
| #ifndef CONFIG_AMLOGIC_POST_PROCESS_MANAGER |
| vf_reg_provider(&vh264_vf_prov); |
| #endif |
| amvdec_start(); |
| } |
| return 0; |
| } |
| |
| static int vh264_vf_states(struct vframe_states *states, void *op_arg) |
| { |
| unsigned long flags; |
| |
| spin_lock_irqsave(&lock, flags); |
| |
| states->vf_pool_size = VF_POOL_SIZE; |
| states->buf_free_num = kfifo_len(&newframe_q); |
| states->buf_avail_num = kfifo_len(&display_q) + |
| kfifo_len(&delay_display_q); |
| states->buf_recycle_num = kfifo_len(&recycle_q); |
| |
| spin_unlock_irqrestore(&lock, flags); |
| |
| return 0; |
| } |
| |
| #if 0 |
| static tvin_trans_fmt_t convert_3d_format(u32 type) |
| { |
| const tvin_trans_fmt_t conv_tab[] = { |
| 0, /* checkerboard */ |
| 0, /* column alternation */ |
| TVIN_TFMT_3D_LA, /* row alternation */ |
| TVIN_TFMT_3D_LRH_OLER, /* side by side */ |
| TVIN_TFMT_3D_FA /* top bottom */ |
| }; |
| |
| return (type <= 4) ? conv_tab[type] : 0; |
| } |
| #endif |
| |
| |
| |
| #define DUMP_CC_AS_ASCII |
| |
| #ifdef DUMP_CC_AS_ASCII |
| static int vbi_to_ascii(int c) |
| { |
| if (c < 0) |
| return '?'; |
| |
| c &= 0x7F; |
| |
| if (c < 0x20 || c >= 0x7F) |
| return '.'; |
| |
| return c; |
| } |
| |
| static void dump_cc_ascii(const uint8_t *buf, unsigned int vpts, int poc) |
| { |
| int cc_flag; |
| int cc_count; |
| int i; |
| int szAscii[32]; |
| int index = 0; |
| |
| cc_flag = buf[1] & 0x40; |
| if (!cc_flag) { |
| pr_info("### cc_flag is invalid\n"); |
| return; |
| } |
| cc_count = buf[1] & 0x1f; |
| |
| for (i = 0; i < cc_count; ++i) { |
| unsigned int b0; |
| unsigned int cc_valid; |
| unsigned int cc_type; |
| unsigned char cc_data1; |
| unsigned char cc_data2; |
| |
| b0 = buf[3 + i * 3]; |
| cc_valid = b0 & 4; |
| cc_type = b0 & 3; |
| cc_data1 = buf[4 + i * 3]; |
| cc_data2 = buf[5 + i * 3]; |
| |
| |
| if (cc_type == 0) { |
| /* NTSC pair, Line 21 */ |
| szAscii[index++] = vbi_to_ascii(cc_data1); |
| szAscii[index++] = vbi_to_ascii(cc_data2); |
| if ((!cc_valid) || (i >= 3)) |
| break; |
| } |
| } |
| |
| if (index > 0 && index <= 8) { |
| char pr_buf[128]; |
| int len; |
| |
| sprintf(pr_buf, "push vpts:0x%x, poc:%d :", vpts, poc); |
| len = strlen(pr_buf); |
| for (i=0;i<index;i++) |
| sprintf(pr_buf + len + i*2, "%c ", szAscii[i]); |
| pr_info("%s\n", pr_buf); |
| } |
| |
| } |
| #endif |
| |
| /* |
| #define DUMP_USER_DATA_HEX |
| */ |
| #ifdef DUMP_USER_DATA_HEX |
| static void print_data(unsigned char *pdata, int len) |
| { |
| int nLeft; |
| char buf[128]; |
| |
| nLeft = len; |
| while (nLeft >= 16) { |
| int i; |
| |
| for (i=0;i<16;i++) |
| sprintf(buf+i*3, "%02x ", pdata[i]); |
| |
| pr_info("%s\n", buf); |
| nLeft -= 16; |
| pdata += 16; |
| } |
| |
| while (nLeft >= 8) { |
| int i; |
| for (i=0;i<nLeft;i++) |
| sprintf(buf+i*3, "%02x ", pdata[i]); |
| |
| pr_info("%s\n", buf); |
| nLeft -= 8; |
| pdata += 8; |
| } |
| } |
| #endif |
| |
| |
| |
| static void aml_swap_data(uint8_t *user_data, int ud_size) |
| { |
| int swap_blocks, i, j, k, m; |
| unsigned char c_temp; |
| |
| /* swap byte order */ |
| swap_blocks = ud_size / 8; |
| for (i = 0; i < swap_blocks; i++) { |
| j = i * 8; |
| k = j + 7; |
| for (m = 0; m < 4; m++) { |
| c_temp = user_data[j]; |
| user_data[j++] = user_data[k]; |
| user_data[k--] = c_temp; |
| } |
| } |
| } |
| |
| |
| static void udr_dump_data(unsigned int user_data_wp, |
| unsigned int user_data_length, |
| unsigned int pts, |
| int poc) |
| { |
| unsigned char *pdata; |
| int user_data_len; |
| int wp_start; |
| int nLeft; |
| unsigned char szBuf[256]; |
| int nOffset; |
| |
| dma_sync_single_for_cpu(amports_get_dma_device(), |
| sei_data_buffer_phys, USER_DATA_SIZE, |
| DMA_FROM_DEVICE); |
| |
| if (user_data_length & 0x07) |
| user_data_len = (user_data_length + 8) & 0xFFFFFFF8; |
| else |
| user_data_len = user_data_length; |
| |
| if (user_data_wp >= user_data_len) { |
| wp_start = user_data_wp - user_data_len; |
| |
| pdata = (unsigned char *)sei_data_buffer; |
| pdata += wp_start; |
| nLeft = user_data_len; |
| |
| memset(szBuf, 0, 256); |
| memcpy(szBuf, pdata, user_data_len); |
| } else { |
| wp_start = user_data_wp + |
| USER_DATA_SIZE - user_data_len; |
| |
| pdata = (unsigned char *)sei_data_buffer; |
| pdata += wp_start; |
| nLeft = USER_DATA_SIZE - wp_start; |
| |
| memset(szBuf, 0, 256); |
| memcpy(szBuf, pdata, nLeft); |
| nOffset = nLeft; |
| |
| pdata = (unsigned char *)sei_data_buffer; |
| nLeft = user_data_wp; |
| memcpy(szBuf+nOffset, pdata, nLeft); |
| } |
| |
| aml_swap_data(szBuf, user_data_len); |
| |
| #ifdef DUMP_USER_DATA_HEX |
| print_data(szBuf, user_data_len); |
| #endif |
| |
| #ifdef DUMP_CC_AS_ASCII |
| dump_cc_ascii(szBuf+7, pts, poc); |
| #endif |
| } |
| |
| |
| struct vh264_userdata_recored_t { |
| struct userdata_meta_info_t meta_info; |
| u32 rec_start; |
| u32 rec_len; |
| }; |
| |
| #define USERDATA_FIFO_NUM 256 |
| |
| struct vh264_userdata_info_t { |
| struct vh264_userdata_recored_t records[USERDATA_FIFO_NUM]; |
| u8 *data_buf; |
| u8 *data_buf_end; |
| u32 buf_len; |
| u32 read_index; |
| u32 write_index; |
| u32 last_wp; |
| }; |
| |
| static struct vh264_userdata_info_t *p_userdata_mgr; |
| |
| static DEFINE_MUTEX(userdata_mutex); |
| |
| |
| void vh264_crate_userdata_manager(u8 *userdata_buf, int buf_len) |
| { |
| p_userdata_mgr = (struct vh264_userdata_info_t *) |
| vmalloc(sizeof(struct vh264_userdata_info_t)); |
| if (p_userdata_mgr) { |
| memset(p_userdata_mgr, 0, |
| sizeof(struct vh264_userdata_info_t)); |
| p_userdata_mgr->data_buf = userdata_buf; |
| p_userdata_mgr->buf_len = buf_len; |
| p_userdata_mgr->data_buf_end = userdata_buf + buf_len; |
| } |
| } |
| |
| void vh264_destroy_userdata_manager(void) |
| { |
| if (p_userdata_mgr) { |
| vfree(p_userdata_mgr); |
| p_userdata_mgr = NULL; |
| } |
| } |
| |
| /* |
| #define DUMP_USER_DATA |
| */ |
| #ifdef DUMP_USER_DATA |
| |
| #define MAX_USER_DATA_SIZE 3145728 |
| static void *user_data_buf; |
| static unsigned char *pbuf_start; |
| static int total_len; |
| static int bskip; |
| static int n_userdata_id; |
| |
| |
| static void print_mem_data(unsigned char *pdata, |
| int len, |
| unsigned int flag, |
| unsigned int duration, |
| unsigned int vpts, |
| unsigned int vpts_valid, |
| int rec_id) |
| { |
| int nLeft; |
| |
| nLeft = len; |
| #if 0 |
| pr_info("%d len = %d, flag = %d, duration = %d, vpts = 0x%x, vpts_valid = %d\n", |
| rec_id, len, flag, |
| duration, vpts, vpts_valid); |
| #endif |
| pr_info("%d len = %d, flag = %d, vpts = 0x%x\n", |
| rec_id, len, flag, vpts); |
| |
| |
| while (nLeft >= 16) { |
| pr_info("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", |
| pdata[0], pdata[1], pdata[2], pdata[3], |
| pdata[4], pdata[5], pdata[6], pdata[7], |
| pdata[8], pdata[9], pdata[10], pdata[11], |
| pdata[12], pdata[13], pdata[14], pdata[15]); |
| nLeft -= 16; |
| pdata += 16; |
| } |
| |
| |
| while (nLeft > 0) { |
| pr_info("%02x %02x %02x %02x %02x %02x %02x %02x\n", |
| pdata[0], pdata[1], pdata[2], pdata[3], |
| pdata[4], pdata[5], pdata[6], pdata[7]); |
| nLeft -= 8; |
| pdata += 8; |
| } |
| } |
| |
| |
| static void dump_data(u8 *pdata, |
| unsigned int user_data_length, |
| unsigned int flag, |
| unsigned int duration, |
| unsigned int vpts, |
| unsigned int vpts_valid, |
| int rec_id) |
| { |
| unsigned char szBuf[256]; |
| |
| |
| memset(szBuf, 0, 256); |
| memcpy(szBuf, pdata, user_data_length); |
| /* |
| aml_swap_data(szBuf, user_data_length); |
| */ |
| |
| print_mem_data(szBuf, user_data_length, |
| flag, duration, vpts, |
| vpts_valid, rec_id); |
| |
| #ifdef DEBUG_CC_DUMP_ASCII |
| dump_cc_ascii(szBuf+7); |
| #endif |
| } |
| |
| static void push_to_buf(u8 *pdata, int len, struct userdata_meta_info_t *pmeta) |
| { |
| u32 *pLen; |
| int info_cnt; |
| u8 *pbuf_end; |
| |
| if (!user_data_buf) |
| return; |
| |
| if (bskip) { |
| pr_info("over size, skip\n"); |
| return; |
| } |
| info_cnt = 0; |
| pLen = (u32 *)pbuf_start; |
| |
| *pLen = len; |
| pbuf_start += sizeof(u32); |
| info_cnt++; |
| pLen++; |
| |
| *pLen = pmeta->duration; |
| pbuf_start += sizeof(u32); |
| info_cnt++; |
| pLen++; |
| |
| *pLen = pmeta->flags; |
| pbuf_start += sizeof(u32); |
| info_cnt++; |
| pLen++; |
| |
| *pLen = pmeta->vpts; |
| pbuf_start += sizeof(u32); |
| info_cnt++; |
| pLen++; |
| |
| *pLen = pmeta->vpts_valid; |
| pbuf_start += sizeof(u32); |
| info_cnt++; |
| pLen++; |
| |
| |
| *pLen = n_userdata_id; |
| pbuf_start += sizeof(u32); |
| info_cnt++; |
| pLen++; |
| |
| |
| |
| pbuf_end = (u8 *)sei_data_buffer + USER_DATA_SIZE; |
| if (pdata + len > pbuf_end) { |
| int first_section_len; |
| |
| first_section_len = pbuf_end - pdata; |
| memcpy(pbuf_start, pdata, first_section_len); |
| pdata = (u8 *)sei_data_buffer; |
| pbuf_start += first_section_len; |
| memcpy(pbuf_start, pdata, len - first_section_len); |
| pbuf_start += len - first_section_len; |
| } else { |
| memcpy(pbuf_start, pdata, len); |
| pbuf_start += len; |
| } |
| |
| total_len += len + info_cnt * sizeof(u32); |
| if (total_len >= MAX_USER_DATA_SIZE-4096) |
| bskip = 1; |
| } |
| |
| |
| static void dump_userdata_info( |
| void *puser_data, |
| int len, |
| struct userdata_meta_info_t *pmeta) |
| { |
| u8 *pstart; |
| |
| pstart = (u8 *)puser_data; |
| |
| |
| push_to_buf(pstart, len, pmeta); |
| } |
| |
| static void show_user_data_buf(void) |
| { |
| u8 *pbuf; |
| int len; |
| unsigned int flag; |
| unsigned int duration; |
| unsigned int vpts; |
| unsigned int vpts_valid; |
| int rec_id; |
| |
| pr_info("show user data buf\n"); |
| pbuf = user_data_buf; |
| |
| while (pbuf < pbuf_start) { |
| u32 *pLen; |
| |
| pLen = (u32 *)pbuf; |
| |
| len = *pLen; |
| pLen++; |
| pbuf += sizeof(u32); |
| |
| duration = *pLen; |
| pLen++; |
| pbuf += sizeof(u32); |
| |
| flag = *pLen; |
| pLen++; |
| pbuf += sizeof(u32); |
| |
| vpts = *pLen; |
| pLen++; |
| pbuf += sizeof(u32); |
| |
| vpts_valid = *pLen; |
| pLen++; |
| pbuf += sizeof(u32); |
| |
| rec_id = *pLen; |
| pLen++; |
| pbuf += sizeof(u32); |
| |
| dump_data(pbuf, len, flag, duration, vpts, vpts_valid, rec_id); |
| pbuf += len; |
| msleep(30); |
| } |
| } |
| |
| static int vh264_init_userdata_dump(void) |
| { |
| user_data_buf = kmalloc(MAX_USER_DATA_SIZE, GFP_KERNEL); |
| if (user_data_buf) |
| return 1; |
| else |
| return 0; |
| } |
| |
| static void vh264_dump_userdata(void) |
| { |
| if (user_data_buf) { |
| show_user_data_buf(); |
| kfree(user_data_buf); |
| user_data_buf = NULL; |
| } |
| } |
| |
| static void vh264_reset_user_data_buf(void) |
| { |
| total_len = 0; |
| pbuf_start = user_data_buf; |
| bskip = 0; |
| n_userdata_id = 0; |
| } |
| #endif |
| |
| static void vh264_add_userdata(struct userdata_meta_info_t meta_info, int wp) |
| { |
| struct vh264_userdata_recored_t *p_userdata_rec; |
| int data_length; |
| |
| mutex_lock(&userdata_mutex); |
| |
| if (p_userdata_mgr) { |
| if (wp > p_userdata_mgr->last_wp) |
| data_length = wp - p_userdata_mgr->last_wp; |
| else |
| data_length = wp + p_userdata_mgr->buf_len - |
| p_userdata_mgr->last_wp; |
| |
| if (data_length & 0x7) |
| data_length = (((data_length + 8) >> 3) << 3); |
| #if 0 |
| pr_info("wakeup_push: ri:%d, wi:%d, data_len:%d, last_wp:%d, wp:%d, id = %d\n", |
| p_userdata_mgr->read_index, |
| p_userdata_mgr->write_index, |
| data_length, |
| p_userdata_mgr->last_wp, |
| wp, |
| n_userdata_id); |
| #endif |
| p_userdata_rec = p_userdata_mgr->records + |
| p_userdata_mgr->write_index; |
| p_userdata_rec->meta_info = meta_info; |
| p_userdata_rec->rec_start = p_userdata_mgr->last_wp; |
| p_userdata_rec->rec_len = data_length; |
| p_userdata_mgr->last_wp = wp; |
| |
| #ifdef DUMP_USER_DATA |
| dump_userdata_info(p_userdata_mgr->data_buf + |
| p_userdata_rec->rec_start, |
| data_length, |
| &meta_info); |
| n_userdata_id++; |
| #endif |
| |
| p_userdata_mgr->write_index++; |
| if (p_userdata_mgr->write_index >= USERDATA_FIFO_NUM) |
| p_userdata_mgr->write_index = 0; |
| } |
| mutex_unlock(&userdata_mutex); |
| |
| vdec_wakeup_userdata_poll(vdec_h264); |
| } |
| |
| static int vh264_user_data_read(struct vdec_s *vdec, |
| struct userdata_param_t *puserdata_para) |
| { |
| int rec_ri, rec_wi; |
| int rec_len; |
| u8 *rec_data_start; |
| u8 *pdest_buf; |
| struct vh264_userdata_recored_t *p_userdata_rec; |
| u32 data_size; |
| u32 res; |
| int copy_ok = 1; |
| |
| |
| pdest_buf = puserdata_para->pbuf_addr; |
| |
| |
| mutex_lock(&userdata_mutex); |
| |
| if (!p_userdata_mgr) { |
| mutex_unlock(&userdata_mutex); |
| return 0; |
| } |
| /* |
| pr_info("ri = %d, wi = %d\n", |
| p_userdata_mgr->read_index, |
| p_userdata_mgr->write_index); |
| */ |
| rec_ri = p_userdata_mgr->read_index; |
| rec_wi = p_userdata_mgr->write_index; |
| |
| if (rec_ri == rec_wi) { |
| mutex_unlock(&userdata_mutex); |
| return 0; |
| } |
| |
| p_userdata_rec = p_userdata_mgr->records + rec_ri; |
| |
| rec_len = p_userdata_rec->rec_len; |
| rec_data_start = p_userdata_rec->rec_start + p_userdata_mgr->data_buf; |
| /* |
| pr_info("rec_len:%d, rec_start:%d, buf_len:%d\n", |
| p_userdata_rec->rec_len, |
| p_userdata_rec->rec_start, |
| puserdata_para->buf_len); |
| */ |
| if (rec_len <= puserdata_para->buf_len) { |
| /* dvb user data buffer is enought to copy the whole recored. */ |
| data_size = rec_len; |
| if (rec_data_start + data_size |
| > p_userdata_mgr->data_buf_end) { |
| int first_section_len; |
| |
| first_section_len = p_userdata_mgr->buf_len - |
| p_userdata_rec->rec_start; |
| res = (u32)copy_to_user((void *)pdest_buf, |
| (void *)rec_data_start, |
| first_section_len); |
| if (res) { |
| pr_info("p1 read not end res=%d, request=%d\n", |
| res, first_section_len); |
| copy_ok = 0; |
| |
| p_userdata_rec->rec_len -= |
| first_section_len - res; |
| p_userdata_rec->rec_start += |
| first_section_len - res; |
| puserdata_para->data_size = |
| first_section_len - res; |
| } else { |
| res = (u32)copy_to_user( |
| (void *)(pdest_buf+first_section_len), |
| (void *)p_userdata_mgr->data_buf, |
| data_size - first_section_len); |
| if (res) { |
| pr_info("p2 read not end res=%d, request=%d\n", |
| res, data_size); |
| copy_ok = 0; |
| } |
| p_userdata_rec->rec_len -= |
| data_size - res; |
| p_userdata_rec->rec_start = |
| data_size - first_section_len - res; |
| puserdata_para->data_size = |
| data_size - res; |
| } |
| } else { |
| res = (u32)copy_to_user((void *)pdest_buf, |
| (void *)rec_data_start, |
| data_size); |
| if (res) { |
| pr_info("p3 read not end res=%d, request=%d\n", |
| res, data_size); |
| copy_ok = 0; |
| } |
| p_userdata_rec->rec_len -= data_size - res; |
| p_userdata_rec->rec_start += data_size - res; |
| puserdata_para->data_size = data_size - res; |
| } |
| |
| if (copy_ok) { |
| p_userdata_mgr->read_index++; |
| if (p_userdata_mgr->read_index >= USERDATA_FIFO_NUM) |
| p_userdata_mgr->read_index = 0; |
| } |
| } else { |
| /* dvb user data buffer is not enought |
| to copy the whole recored. */ |
| data_size = puserdata_para->buf_len; |
| if (rec_data_start + data_size |
| > p_userdata_mgr->data_buf_end) { |
| int first_section_len; |
| |
| first_section_len = p_userdata_mgr->buf_len |
| - p_userdata_rec->rec_start; |
| res = (u32)copy_to_user((void *)pdest_buf, |
| (void *)rec_data_start, |
| first_section_len); |
| if (res) { |
| pr_info("p4 read not end res=%d, request=%d\n", |
| res, first_section_len); |
| copy_ok = 0; |
| p_userdata_rec->rec_len -= |
| first_section_len - res; |
| p_userdata_rec->rec_start += |
| first_section_len - res; |
| puserdata_para->data_size = |
| first_section_len - res; |
| } else { |
| /* first secton copy is ok*/ |
| res = (u32)copy_to_user( |
| (void *)(pdest_buf+first_section_len), |
| (void *)p_userdata_mgr->data_buf, |
| data_size - first_section_len); |
| if (res) { |
| pr_info("p5 read not end res=%d, request=%d\n", |
| res, |
| data_size - first_section_len); |
| copy_ok = 0; |
| } |
| |
| p_userdata_rec->rec_len -= data_size - res; |
| p_userdata_rec->rec_start = |
| data_size - first_section_len - res; |
| puserdata_para->data_size = data_size - res; |
| } |
| } else { |
| res = (u32)copy_to_user((void *)pdest_buf, |
| (void *)rec_data_start, |
| data_size); |
| if (res) { |
| pr_info("p6 read not end res=%d, request=%d\n", |
| res, data_size); |
| copy_ok = 0; |
| } |
| |
| p_userdata_rec->rec_len -= data_size - res; |
| p_userdata_rec->rec_start += data_size - res; |
| puserdata_para->data_size = data_size - res; |
| } |
| |
| if (copy_ok) { |
| p_userdata_mgr->read_index++; |
| if (p_userdata_mgr->read_index |
| >= USERDATA_FIFO_NUM) |
| p_userdata_mgr->read_index = 0; |
| } |
| |
| } |
| puserdata_para->meta_info = p_userdata_rec->meta_info; |
| |
| if (p_userdata_mgr->read_index <= p_userdata_mgr->write_index) |
| puserdata_para->meta_info.records_in_que = |
| p_userdata_mgr->write_index - |
| p_userdata_mgr->read_index; |
| else |
| puserdata_para->meta_info.records_in_que = |
| p_userdata_mgr->write_index + |
| USERDATA_FIFO_NUM - |
| p_userdata_mgr->read_index; |
| |
| puserdata_para->version = (0<<24|0<<16|0<<8|1); |
| |
| mutex_unlock(&userdata_mutex); |
| |
| return 1; |
| } |
| |
| static void vh264_wakeup_userdata_poll(struct vdec_s *vdec) |
| { |
| amstream_wakeup_userdata_poll(vdec); |
| } |
| |
| static void vh264_reset_userdata_fifo(struct vdec_s *vdec, int bInit) |
| { |
| mutex_lock(&userdata_mutex); |
| |
| if (p_userdata_mgr) { |
| pr_info("h264_reset_userdata_fifo: bInit: %d, ri: %d, wi: %d\n", |
| bInit, p_userdata_mgr->read_index, |
| p_userdata_mgr->write_index); |
| p_userdata_mgr->read_index = 0; |
| p_userdata_mgr->write_index = 0; |
| |
| if (bInit) |
| p_userdata_mgr->last_wp = 0; |
| } |
| |
| mutex_unlock(&userdata_mutex); |
| } |
| |
| static void h264_reset_qos_mgr(void) |
| { |
| int i; |
| |
| pr_info("h264_reset_qos_mgr\n"); |
| |
| INIT_LIST_HEAD(&free_qos_nodes_list); |
| INIT_LIST_HEAD(&picture_qos_list); |
| |
| for (i = 0; i < MAX_FREE_QOS_NODES; i++) { |
| free_nodes[i].b_offset = 0xFFFFFFFF; |
| |
| list_add_tail(&free_nodes[i].list, |
| &free_qos_nodes_list); |
| } |
| } |
| |
| |
| static void load_qos_data(int pic_number, uint32_t b_offset) |
| { |
| uint32_t blk88_y_count; |
| uint32_t blk88_c_count; |
| uint32_t blk22_mv_count; |
| uint32_t rdata32; |
| int32_t mv_hi; |
| int32_t mv_lo; |
| uint32_t rdata32_l; |
| uint32_t mvx_L0_hi; |
| uint32_t mvy_L0_hi; |
| uint32_t mvx_L1_hi; |
| uint32_t mvy_L1_hi; |
| int64_t value; |
| uint64_t temp_value; |
| /* |
| #define DEBUG_QOS |
| */ |
| #define SUPPORT_NODE |
| |
| #ifdef SUPPORT_NODE |
| struct h264_qos_data_node_t *node; |
| struct h264_qos_data_node_t *tmp; |
| int bFoundNode = 0; |
| |
| node = NULL; |
| if (!list_empty(&picture_qos_list)) { |
| list_for_each_entry_safe(node, tmp, &picture_qos_list, list) { |
| if (node->b_offset == b_offset) { |
| bFoundNode = 1; |
| break; |
| } |
| } |
| } |
| /* |
| pr_info("bFoundNode = %d, node:0x%p\n", bFoundNode, node); |
| */ |
| if (!bFoundNode) { |
| if (!list_empty(&free_qos_nodes_list)) { |
| node = list_entry( |
| free_qos_nodes_list.next, |
| struct h264_qos_data_node_t, |
| list); |
| /* |
| pr_info("get a node:0x%p\n", node); |
| */ |
| } else { |
| pr_info("there is no qos data node avaible\n"); |
| |
| return; |
| } |
| } |
| |
| node->b_offset = b_offset; |
| node->poc = pic_number; |
| |
| node->max_mv = 0; |
| node->avg_mv = 0; |
| node->min_mv = 0; |
| |
| node->max_skip = 0; |
| node->avg_skip = 0; |
| node->min_skip = 0; |
| |
| node->max_qp = 0; |
| node->avg_qp = 0; |
| node->min_qp = 0; |
| #endif |
| |
| |
| |
| |
| |
| |
| /* set rd_idx to 0 */ |
| WRITE_VREG(VDEC_PIC_QUALITY_CTRL, 0); |
| blk88_y_count = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| if (blk88_y_count == 0) { |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] NO Data yet.\n", |
| pic_number); |
| #endif |
| /* reset all counts */ |
| WRITE_VREG(VDEC_PIC_QUALITY_CTRL, (1<<8)); |
| |
| #ifdef SUPPORT_NODE |
| list_move(&node->list, &picture_qos_list); |
| #endif |
| return; |
| } |
| /* qp_y_sum */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] Y QP AVG : %d (%d/%d)\n", |
| pic_number, rdata32/blk88_y_count, |
| rdata32, blk88_y_count); |
| #endif |
| #ifdef SUPPORT_NODE |
| node->avg_qp = rdata32/blk88_y_count; |
| #endif |
| |
| /* intra_y_count */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] Y intra rate : %d%c (%d)\n", |
| pic_number, rdata32*100/blk88_y_count, |
| '%', rdata32); |
| #endif |
| /* skipped_y_count */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] Y skipped rate : %d%c (%d)\n", |
| pic_number, rdata32*100/blk88_y_count, |
| '%', rdata32); |
| #endif |
| #ifdef SUPPORT_NODE |
| node->avg_skip = rdata32*100/blk88_y_count; |
| #endif |
| /* coeff_non_zero_y_count */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] Y ZERO_Coeff rate : %d%c (%d)\n", |
| pic_number, (100 - rdata32*100/(blk88_y_count*1)), |
| '%', rdata32); |
| #endif |
| /* blk66_c_count */ |
| blk88_c_count = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| if (blk88_c_count == 0) { |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] NO Data yet.\n", |
| pic_number); |
| #endif |
| /* reset all counts */ |
| WRITE_VREG(VDEC_PIC_QUALITY_CTRL, (1<<8)); |
| |
| #ifdef SUPPORT_NODE |
| list_move(&node->list, &picture_qos_list); |
| #endif |
| return; |
| } |
| /* qp_c_sum */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] C QP AVG : %d (%d/%d)\n", |
| pic_number, rdata32/blk88_c_count, |
| rdata32, blk88_c_count); |
| #endif |
| /* intra_c_count */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] C intra rate : %d%c (%d)\n", |
| pic_number, rdata32*100/blk88_c_count, |
| '%', rdata32); |
| #endif |
| /* skipped_cu_c_count */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] C skipped rate : %d%c (%d)\n", |
| pic_number, rdata32*100/blk88_c_count, |
| '%', rdata32); |
| #endif |
| /* coeff_non_zero_c_count */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] C ZERO_Coeff rate : %d%c (%d)\n", |
| pic_number, (100 - rdata32*100/(blk88_c_count*1)), |
| '%', rdata32); |
| #endif |
| |
| /* 1'h0, qp_c_max[6:0], 1'h0, qp_c_min[6:0], |
| 1'h0, qp_y_max[6:0], 1'h0, qp_y_min[6:0] */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] Y QP min : %d\n", |
| pic_number, (rdata32>>0)&0xff); |
| #endif |
| #ifdef SUPPORT_NODE |
| node->min_qp = (rdata32>>0)&0xff; |
| #endif |
| |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] Y QP max : %d\n", |
| pic_number, (rdata32>>8)&0xff); |
| #endif |
| #ifdef SUPPORT_NODE |
| node->max_qp = (rdata32>>8)&0xff; |
| #endif |
| |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] C QP min : %d\n", |
| pic_number, (rdata32>>16)&0xff); |
| pr_info(" [Picture %d Quality] C QP max : %d\n", |
| pic_number, (rdata32>>24)&0xff); |
| #endif |
| |
| /* blk22_mv_count */ |
| blk22_mv_count = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| if (blk22_mv_count == 0) { |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] NO MV Data yet.\n", |
| pic_number); |
| #endif |
| /* reset all counts */ |
| WRITE_VREG(VDEC_PIC_QUALITY_CTRL, (1<<8)); |
| #ifdef SUPPORT_NODE |
| list_move(&node->list, &picture_qos_list); |
| #endif |
| return; |
| } |
| /* mvy_L1_count[39:32], mvx_L1_count[39:32], |
| mvy_L0_count[39:32], mvx_L0_count[39:32] */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| /* should all be 0x00 or 0xff */ |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] MV AVG High Bits: 0x%X\n", |
| pic_number, rdata32); |
| #endif |
| mvx_L0_hi = ((rdata32>>0)&0xff); |
| mvy_L0_hi = ((rdata32>>8)&0xff); |
| mvx_L1_hi = ((rdata32>>16)&0xff); |
| mvy_L1_hi = ((rdata32>>24)&0xff); |
| |
| /* mvx_L0_count[31:0] */ |
| rdata32_l = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| temp_value = mvx_L0_hi; |
| temp_value = (temp_value << 32) | rdata32_l; |
| |
| if (mvx_L0_hi & 0x80) |
| value = 0xFFFFFFF000000000 | temp_value; |
| else |
| value = temp_value; |
| value = div_s64(value, blk22_mv_count); |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] MVX_L0 AVG : %d (%lld/%d)\n", |
| pic_number, (int)(value), |
| value, blk22_mv_count); |
| #endif |
| #ifdef SUPPORT_NODE |
| node->avg_mv = value; |
| #endif |
| |
| /* mvy_L0_count[31:0] */ |
| rdata32_l = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| temp_value = mvy_L0_hi; |
| temp_value = (temp_value << 32) | rdata32_l; |
| |
| if (mvy_L0_hi & 0x80) |
| value = 0xFFFFFFF000000000 | temp_value; |
| else |
| value = temp_value; |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] MVY_L0 AVG : %d (%lld/%d)\n", |
| pic_number, rdata32_l/blk22_mv_count, |
| value, blk22_mv_count); |
| #endif |
| |
| /* mvx_L1_count[31:0] */ |
| rdata32_l = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| temp_value = mvx_L1_hi; |
| temp_value = (temp_value << 32) | rdata32_l; |
| if (mvx_L1_hi & 0x80) |
| value = 0xFFFFFFF000000000 | temp_value; |
| else |
| value = temp_value; |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] MVX_L1 AVG : %d (%lld/%d)\n", |
| pic_number, rdata32_l/blk22_mv_count, |
| value, blk22_mv_count); |
| #endif |
| |
| /* mvy_L1_count[31:0] */ |
| rdata32_l = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| temp_value = mvy_L1_hi; |
| temp_value = (temp_value << 32) | rdata32_l; |
| if (mvy_L1_hi & 0x80) |
| value = 0xFFFFFFF000000000 | temp_value; |
| else |
| value = temp_value; |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] MVY_L1 AVG : %d (%lld/%d)\n", |
| pic_number, rdata32_l/blk22_mv_count, |
| value, blk22_mv_count); |
| #endif |
| |
| /* {mvx_L0_max, mvx_L0_min} // format : {sign, abs[14:0]} */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| mv_hi = (rdata32>>16)&0xffff; |
| if (mv_hi & 0x8000) |
| mv_hi = 0x8000 - mv_hi; |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] MVX_L0 MAX : %d\n", |
| pic_number, mv_hi); |
| #endif |
| #ifdef SUPPORT_NODE |
| node->max_mv = mv_hi; |
| #endif |
| |
| mv_lo = (rdata32>>0)&0xffff; |
| if (mv_lo & 0x8000) |
| mv_lo = 0x8000 - mv_lo; |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] MVX_L0 MIN : %d\n", |
| pic_number, mv_lo); |
| #endif |
| #ifdef SUPPORT_NODE |
| node->min_mv = mv_lo; |
| #endif |
| |
| #ifdef DEBUG_QOS |
| /* {mvy_L0_max, mvy_L0_min} */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| mv_hi = (rdata32>>16)&0xffff; |
| if (mv_hi & 0x8000) |
| mv_hi = 0x8000 - mv_hi; |
| pr_info(" [Picture %d Quality] MVY_L0 MAX : %d\n", |
| pic_number, mv_hi); |
| |
| |
| mv_lo = (rdata32>>0)&0xffff; |
| if (mv_lo & 0x8000) |
| mv_lo = 0x8000 - mv_lo; |
| |
| pr_info(" [Picture %d Quality] MVY_L0 MIN : %d\n", |
| pic_number, mv_lo); |
| |
| |
| /* {mvx_L1_max, mvx_L1_min} */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| mv_hi = (rdata32>>16)&0xffff; |
| if (mv_hi & 0x8000) |
| mv_hi = 0x8000 - mv_hi; |
| |
| pr_info(" [Picture %d Quality] MVX_L1 MAX : %d\n", |
| pic_number, mv_hi); |
| |
| |
| mv_lo = (rdata32>>0)&0xffff; |
| if (mv_lo & 0x8000) |
| mv_lo = 0x8000 - mv_lo; |
| |
| pr_info(" [Picture %d Quality] MVX_L1 MIN : %d\n", |
| pic_number, mv_lo); |
| |
| |
| /* {mvy_L1_max, mvy_L1_min} */ |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_DATA); |
| mv_hi = (rdata32>>16)&0xffff; |
| if (mv_hi & 0x8000) |
| mv_hi = 0x8000 - mv_hi; |
| |
| pr_info(" [Picture %d Quality] MVY_L1 MAX : %d\n", |
| pic_number, mv_hi); |
| |
| mv_lo = (rdata32>>0)&0xffff; |
| if (mv_lo & 0x8000) |
| mv_lo = 0x8000 - mv_lo; |
| |
| pr_info(" [Picture %d Quality] MVY_L1 MIN : %d\n", |
| pic_number, mv_lo); |
| #endif |
| |
| rdata32 = READ_VREG(VDEC_PIC_QUALITY_CTRL); |
| #ifdef DEBUG_QOS |
| pr_info(" [Picture %d Quality] After Read : VDEC_PIC_QUALITY_CTRL : 0x%x\n", |
| pic_number, rdata32); |
| #endif |
| /* reset all counts */ |
| WRITE_VREG(VDEC_PIC_QUALITY_CTRL, (1<<8)); |
| #ifdef SUPPORT_NODE |
| list_move(&node->list, &picture_qos_list); |
| #endif |
| } |
| |
| void search_qos_node(struct vframe_qos_s *picture_qos, uint32_t b_offset) |
| { |
| struct h264_qos_data_node_t *node; |
| struct h264_qos_data_node_t *tmp; |
| |
| if (!list_empty(&picture_qos_list)) { |
| list_for_each_entry_safe(node, tmp, &picture_qos_list, list) { |
| if (node->b_offset == b_offset) { |
| |
| picture_qos->avg_mv = node->avg_mv; |
| picture_qos->min_mv = node->min_mv; |
| picture_qos->max_mv = node->max_mv; |
| |
| picture_qos->avg_skip = node->avg_skip; |
| picture_qos->min_skip = node->min_skip; |
| picture_qos->max_skip = node->max_skip; |
| |
| picture_qos->avg_qp = node->avg_qp; |
| picture_qos->min_qp = node->min_qp; |
| picture_qos->max_qp = node->max_qp; |
| |
| #if 0 |
| pr_info("POC:%d, mv: max:%d, avg:%d, min:%d\n" |
| "qp: max:%d, avg:%d, min:%d\n" |
| "skip: max:%d, avg:%d, min:%d\n", |
| node->poc, |
| picture_qos->max_mv, |
| picture_qos->avg_mv, |
| picture_qos->min_mv, |
| picture_qos->max_qp, |
| picture_qos->avg_qp, |
| picture_qos->min_qp, |
| picture_qos->max_skip, |
| picture_qos->avg_skip, |
| picture_qos->min_skip); |
| #endif |
| node->b_offset = 0xFFFFFFFF; |
| list_move(&node->list, &free_qos_nodes_list); |
| |
| break; |
| } |
| } |
| } |
| } |
| |
| static void qos_do_work(struct work_struct *work) |
| { |
| uint32_t poc; |
| uint32_t bOffset; |
| |
| |
| poc = READ_VREG(AV_SCRATCH_M); |
| bOffset = READ_VREG(AV_SCRATCH_L); |
| /* |
| pr_info("poc:%d, bOffset:0x%x\n", poc, bOffset); |
| */ |
| load_qos_data(poc, bOffset); |
| |
| |
| WRITE_VREG(AV_SCRATCH_0, 0); |
| } |
| |
| static void userdata_push_do_work(struct work_struct *work) |
| { |
| unsigned int sei_itu35_flags; |
| unsigned int sei_itu35_wp; |
| unsigned int sei_itu35_data_length; |
| |
| struct userdata_meta_info_t meta_info; |
| u32 offset, pts; |
| u64 pts_us64 = 0; |
| u32 slice_type; |
| u32 reg; |
| u32 poc_number; |
| u32 picture_struct; |
| |
| memset(&meta_info, 0, sizeof(meta_info)); |
| |
| meta_info.duration = frame_dur; |
| |
| reg = READ_VREG(AV_SCRATCH_M); |
| poc_number = reg & 0x7FFFFFF; |
| if ((poc_number >> 16) == 0x7FF) |
| poc_number = (reg & 0x7FFFFFF) - 0x8000000; |
| |
| slice_type = (reg >> 29) & 0x7; |
| switch (slice_type) { |
| case SLICE_TYPE_I: |
| meta_info.flags |= 1<<7; |
| break; |
| case SLICE_TYPE_P: |
| meta_info.flags |= 3<<7; |
| break; |
| case SLICE_TYPE_B: |
| meta_info.flags |= 2<<7; |
| break; |
| } |
| meta_info.poc_number = poc_number; |
| picture_struct = (reg >> 27) & 0x3; |
| |
| meta_info.flags |= (VFORMAT_H264 << 3) | (picture_struct << 12); |
| |
| |
| offset = READ_VREG(AV_SCRATCH_L); |
| |
| if (pts_pickout_offset_us64 |
| (PTS_TYPE_VIDEO, offset, &pts, 0, &pts_us64) != 0) { |
| pr_info("pts pick outfailed, offset:0x%x\n", offset); |
| pts = -1; |
| meta_info.vpts_valid = 0; |
| } else |
| meta_info.vpts_valid = 1; |
| meta_info.vpts = pts; |
| /* |
| pr_info("offset:0x%x, vpts:0x%x, slice:%d, poc:%d\n", |
| offset, pts, slice_type, |
| poc_number); |
| */ |
| sei_itu35_flags = READ_VREG(AV_SCRATCH_J); |
| sei_itu35_wp = (sei_itu35_flags >> 16) & 0xffff; |
| sei_itu35_data_length = sei_itu35_flags & 0x7fff; |
| |
| if (enable_userdata_debug) |
| udr_dump_data(sei_itu35_wp, |
| sei_itu35_data_length, |
| pts, poc_number); |
| |
| |
| vh264_add_userdata(meta_info, sei_itu35_wp); |
| |
| WRITE_VREG(AV_SCRATCH_J, 0); |
| } |
| |
| |
| static void set_frame_info(struct vframe_s *vf) |
| { |
| vf->width = frame_width; |
| vf->height = frame_height; |
| vf->duration = frame_dur; |
| vf->ratio_control = |
| (min(h264_ar, (u32) DISP_RATIO_ASPECT_RATIO_MAX)) << |
| DISP_RATIO_ASPECT_RATIO_BIT; |
| vf->orientation = vh264_rotation; |
| vf->flag = 0; |
| |
| #ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER_3D_PROCESS |
| vf->trans_fmt = 0; |
| if ((vf->trans_fmt == TVIN_TFMT_3D_LRF) || |
| (vf->trans_fmt == TVIN_TFMT_3D_LA)) { |
| vf->left_eye.start_x = 0; |
| vf->left_eye.start_y = 0; |
| vf->left_eye.width = frame_width / 2; |
| vf->left_eye.height = frame_height; |
| |
| vf->right_eye.start_x = 0; |
| vf->right_eye.start_y = 0; |
| vf->right_eye.width = frame_width / 2; |
| vf->right_eye.height = frame_height; |
| } else if ((vf->trans_fmt == TVIN_TFMT_3D_LRH_OLER) || |
| (vf->trans_fmt == TVIN_TFMT_3D_TB)) { |
| vf->left_eye.start_x = 0; |
| vf->left_eye.start_y = 0; |
| vf->left_eye.width = frame_width / 2; |
| vf->left_eye.height = frame_height; |
| |
| vf->right_eye.start_x = 0; |
| vf->right_eye.start_y = 0; |
| vf->right_eye.width = frame_width / 2; |
| vf->right_eye.height = frame_height; |
| } |
| #endif |
| |
| } |
| |
| #ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER |
| static void vh264_ppmgr_reset(void) |
| { |
| vf_notify_receiver(PROVIDER_NAME, VFRAME_EVENT_PROVIDER_RESET, NULL); |
| |
| vh264_local_init(); |
| |
| pr_info("vh264dec: vf_ppmgr_reset\n"); |
| } |
| #endif |
| |
| static int get_max_dpb_size(int level_idc, int mb_width, int mb_height) |
| { |
| int size, r; |
| |
| switch (level_idc) { |
| case 10: |
| r = 1485; |
| break; |
| case 11: |
| r = 3375; |
| break; |
| case 12: |
| case 13: |
| case 20: |
| r = 8910; |
| break; |
| case 21: |
| r = 17820; |
| break; |
| case 22: |
| case 30: |
| r = 30375; |
| break; |
| case 31: |
| r = 67500; |
| break; |
| case 32: |
| r = 76800; |
| break; |
| case 40: |
| case 41: |
| case 42: |
| r = 122880; |
| break; |
| case 50: |
| r = 414000; |
| break; |
| case 51: |
| case 52: |
| r = 691200; |
| break; |
| default: |
| return 0; |
| } |
| size = (mb_width * mb_height + |
| (mb_width * mb_height / 2)) * 256 * 10; |
| r = (r * 1024 + size-1) / size; |
| r = min(r, 16); |
| /*pr_info("max_dpb %d size:%d\n", r, size);*/ |
| return r; |
| } |
| static void vh264_set_params(struct work_struct *work) |
| { |
| int aspect_ratio_info_present_flag, aspect_ratio_idc; |
| int max_dpb_size, actual_dpb_size, max_reference_size; |
| int i, mb_mv_byte, ret; |
| unsigned long addr; |
| unsigned int post_canvas, buf_size, endian; |
| unsigned int frame_mbs_only_flag; |
| unsigned int chroma_format_idc, chroma444, video_signal; |
| unsigned int crop_infor, crop_bottom, crop_right, level_idc; |
| if (!atomic_read(&vh264_active)) |
| return; |
| mutex_lock(&vh264_mutex); |
| if (vh264_stream_switching_state == SWITCHING_STATE_ON_CMD1) |
| vh264_stream_switching_state = SWITCHING_STATE_ON_CMD1_PENDING; |
| post_canvas = get_post_canvas(); |
| clk_adj_frame_count = 0; |
| /* set to max decoder clock rate at the beginning */ |
| |
| if (vdec_is_support_4k()) |
| vdec_source_changed(VFORMAT_H264, 3840, 2160, 60); |
| else |
| vdec_source_changed(VFORMAT_H264, 1920, 1080, 29); |
| |
| timing_info_present_flag = 0; |
| mb_width = READ_VREG(AV_SCRATCH_1); |
| seq_info = READ_VREG(AV_SCRATCH_2); |
| aspect_ratio_info = READ_VREG(AV_SCRATCH_3); |
| num_units_in_tick = READ_VREG(AV_SCRATCH_4); |
| time_scale = READ_VREG(AV_SCRATCH_5); |
| level_idc = READ_VREG(AV_SCRATCH_A); |
| if (level_idc > 0) |
| saved_idc_level = level_idc; |
| else if (saved_idc_level > 0) |
| level_idc = saved_idc_level; |
| video_signal = READ_VREG(AV_SCRATCH_H); |
| video_signal_from_vui = |
| ((video_signal & 0xffff) << 8) | |
| ((video_signal & 0xff0000) >> 16) | |
| ((video_signal & 0x3f000000)); |
| /* |
| * pr_info("video_signal_type_present_flag 0x%x\n", |
| * (video_signal_from_vui >> 29) & 1); |
| * pr_info("video_format 0x%x\n", |
| * (video_signal_from_vui >> 26) & 7); |
| * pr_info("video_full_range_flag 0x%x\n", |
| * (video_signal_from_vui >> 25) & 1); |
| * pr_info("color_description_present_flag 0x%x\n", |
| * (video_signal_from_vui >> 24) & 1); |
| * pr_info("color_primaries 0x%x\n", |
| * (video_signal_from_vui >> 16) & 0xff); |
| * pr_info("transfer_characteristic 0x%x\n", |
| * (video_signal_from_vui >> 8) & 0xff); |
| * pr_info("matrix_coefficient 0x%x\n", |
| * video_signal_from_vui & 0xff); |
| */ |
| |
| mb_total = (mb_width >> 8) & 0xffff; |
| max_reference_size = (mb_width >> 24) & 0x7f; |
| mb_mv_byte = (mb_width & 0x80000000) ? 24 : 96; |
| if (ucode_type == UCODE_IP_ONLY_PARAM) |
| mb_mv_byte = 96; |
| mb_width = mb_width & 0xff; |
| if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXTVBB) { |
| if (!mb_width && mb_total) |
| mb_width = 256; |
| } |
| if (mb_width) |
| mb_height = mb_total / mb_width; |
| last_duration = 0; |
| /* AV_SCRATCH_2 |
| * bit 15: frame_mbs_only_flag |
| * bit 13-14: chroma_format_idc |
| */ |
| frame_mbs_only_flag = (seq_info >> 15) & 0x01; |
| chroma_format_idc = (seq_info >> 13) & 0x03; |
| chroma444 = (chroma_format_idc == 3) ? 1 : 0; |
| |
| /* @AV_SCRATCH_6.31-16 = (left << 8 | right ) << 1 |
| * @AV_SCRATCH_6.15-0 = (top << 8 | bottom ) << |
| * (2 - frame_mbs_only_flag) |
| */ |
| crop_infor = READ_VREG(AV_SCRATCH_6); |
| crop_bottom = (crop_infor & 0xff) >> (2 - frame_mbs_only_flag); |
| crop_right = ((crop_infor >> 16) & 0xff) >> (2 - frame_mbs_only_flag); |
| |
| /* if width or height from outside is not equal to mb, then use mb */ |
| /* add: for seeking stream with other resolution */ |
| if ((last_mb_width && (last_mb_width != mb_width)) |
| || (mb_width != ((frame_width + 15) >> 4))) |
| frame_width = 0; |
| if ((last_mb_height && (last_mb_height != mb_height)) |
| || (mb_height != ((frame_height + 15) >> 4))) |
| frame_height = 0; |
| last_mb_width = mb_width; |
| last_mb_height = mb_height; |
| |
| if ((frame_width == 0) || (frame_height == 0) || crop_infor) { |
| frame_width = mb_width << 4; |
| frame_height = mb_height << 4; |
| if (frame_mbs_only_flag) { |
| frame_height = |
| frame_height - (2 >> chroma444) * |
| min(crop_bottom, |
| (unsigned int)((8 << chroma444) - 1)); |
| frame_width = |
| frame_width - (2 >> chroma444) * min(crop_right, |
| (unsigned |
| int)((8 << chroma444) - 1)); |
| } else { |
| frame_height = |
| frame_height - (4 >> chroma444) * |
| min(crop_bottom, |
| (unsigned int)((8 << chroma444) |
| - 1)); |
| frame_width = |
| frame_width - (4 >> chroma444) * min(crop_right, |
| (unsigned |
| int)((8 << |
| chroma444) |
| - 1)); |
| } |
| #if 0 |
| pr_info |
| ("frame_mbs_only_flag %d, crop_bottom %d, frame_height %d, ", |
| frame_mbs_only_flag, crop_bottom, frame_height); |
| pr_info |
| ("mb_height %d,crop_right %d, frame_width %d, mb_width %d\n", |
| mb_height, crop_right, frame_width, mb_width); |
| #endif |
| if (frame_height == 1088) |
| frame_height = 1080; |
| } |
| |
| mb_width = (mb_width + 3) & 0xfffffffc; |
| mb_height = (mb_height + 3) & 0xfffffffc; |
| mb_total = mb_width * mb_height; |
| |
| /*max_reference_size <= max_dpb_size <= actual_dpb_size*/ |
| is_4k = (mb_total > 8160) ? true:false; |
| |
| |
| max_dpb_size = get_max_dpb_size(level_idc, mb_width, mb_height); |
| if (max_dpb_size < max_reference_size) |
| max_dpb_size = max_reference_size; |
| if (max_dpb_size > 15 |
| && get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_GXTVBB |
| && (codec_mm_get_total_size() < 80 * SZ_1M)) { |
| actual_dpb_size |
| = max_reference_size + dpb_size_adj; |
| if (actual_dpb_size > VF_BUF_NUM) |
| actual_dpb_size = VF_BUF_NUM; |
| } else { |
| actual_dpb_size = max_dpb_size + dpb_size_adj; |
| actual_dpb_size = min(actual_dpb_size, VF_BUF_NUM); |
| } |
| max_reference_size++; |
| pr_info("actual_dpb_size %d max_dpb_size %d max_ref %d\n", |
| actual_dpb_size, max_dpb_size, |
| max_reference_size); |
| buf_size = mb_total * mb_mv_byte * max_reference_size; |
| |
| ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, 1, |
| buf_size, DRIVER_NAME, &addr); |
| |
| if (ret < 0) { |
| fatal_error_flag = |
| DECODER_FATAL_ERROR_NO_MEM; |
| vh264_running = 0; |
| mutex_unlock(&vh264_mutex); |
| return; |
| } |
| |
| WRITE_VREG(AV_SCRATCH_1, addr); |
| WRITE_VREG(AV_SCRATCH_3, post_canvas); |
| WRITE_VREG(AV_SCRATCH_4, addr + buf_size); |
| |
| if (!(READ_VREG(AV_SCRATCH_F) & 0x1)) { |
| for (i = 0; i < actual_dpb_size; i++) { |
| #ifdef DOUBLE_WRITE |
| int page_count = |
| PAGE_ALIGN((mb_total << 8) + (mb_total |
| << 7) + (mb_total << 6) + |
| (mb_total << 5)) / PAGE_SIZE; |
| #else |
| int page_count = |
| PAGE_ALIGN((mb_total << 8) + |
| (mb_total << 7)) / PAGE_SIZE; |
| #endif |
| |
| ret = decoder_bmmu_box_alloc_buf_phy(mm_blk_handle, |
| VF_BUFFER_IDX(i), |
| page_count << PAGE_SHIFT, |
| DRIVER_NAME, &buffer_spec[i].phy_addr); |
| |
| if (ret < 0) { |
| buffer_spec[i].alloc_count = 0; |
| fatal_error_flag = |
| DECODER_FATAL_ERROR_NO_MEM; |
| vh264_running = 0; |
| mutex_unlock(&vh264_mutex); |
| return; |
| } |
| |
| addr = buffer_spec[i].phy_addr; |
| buffer_spec[i].alloc_count = page_count; |
| |
| if (i <= 21) { |
| buffer_spec[i].y_addr = addr; |
| addr += mb_total << 8; |
| buffer_spec[i].u_addr = addr; |
| buffer_spec[i].v_addr = addr; |
| addr += mb_total << 7; |
| vfbuf_use[i] = 0; |
| |
| buffer_spec[i].y_canvas_index = 128 + i * 2; |
| buffer_spec[i].u_canvas_index = 128 + i * 2 + 1; |
| buffer_spec[i].v_canvas_index = 128 + i * 2 + 1; |
| |
| buffer_spec[i].y_canvas_width = mb_width << 4; |
| buffer_spec[i].y_canvas_height = mb_height << 4; |
| buffer_spec[i].u_canvas_width = mb_width << 4; |
| buffer_spec[i].u_canvas_height = mb_height << 4; |
| buffer_spec[i].v_canvas_width = mb_width << 4; |
| buffer_spec[i].v_canvas_height = mb_height << 4; |
| |
| endian = (canvas_mode == CANVAS_BLKMODE_LINEAR)?7:0; |
| config_cav_lut_ex(128 + i * 2, |
| buffer_spec[i].y_addr, |
| mb_width << 4, mb_height << 4, |
| CANVAS_ADDR_NOWRAP, |
| canvas_mode, endian, VDEC_1); |
| config_cav_lut_ex(128 + i * 2 + 1, |
| buffer_spec[i].u_addr, |
| mb_width << 4, mb_height << 3, |
| CANVAS_ADDR_NOWRAP, |
| canvas_mode, endian, VDEC_1); |
| WRITE_VREG(ANC0_CANVAS_ADDR + i, |
| spec2canvas(&buffer_spec[i])); |
| } else { |
| buffer_spec[i].y_canvas_index = |
| 2 * (i - 21) + 4; |
| buffer_spec[i].y_addr = addr; |
| addr += mb_total << 8; |
| buffer_spec[i].u_canvas_index = |
| 2 * (i - 21) + 5; |
| buffer_spec[i].v_canvas_index = |
| 2 * (i - 21) + 5; |
| buffer_spec[i].u_addr = addr; |
| addr += mb_total << 7; |
| vfbuf_use[i] = 0; |
| |
| buffer_spec[i].y_canvas_width = mb_width << 4; |
| buffer_spec[i].y_canvas_height = mb_height << 4; |
| buffer_spec[i].u_canvas_width = mb_width << 4; |
| buffer_spec[i].u_canvas_height = mb_height << 4; |
| buffer_spec[i].v_canvas_width = mb_width << 4; |
| buffer_spec[i].v_canvas_height = mb_height << 4; |
| |
| spec_set_canvas(&buffer_spec[i] |
| , mb_width << 4, mb_height << 4); |
| WRITE_VREG(ANC0_CANVAS_ADDR + i |
| , spec2canvas(&buffer_spec[i])); |
| } |
| } |
| } else { |
| fatal_error_flag = |
| DECODER_FATAL_ERROR_NO_MEM; |
| vh264_running = 0; |
| mutex_unlock(&vh264_mutex); |
| pr_err("never be here!!\n"); |
| return; |
| } |
| |
| timing_info_present_flag = seq_info & 0x2; |
| fixed_frame_rate_flag = 0; |
| aspect_ratio_info_present_flag = seq_info & 0x1; |
| aspect_ratio_idc = (seq_info >> 16) & 0xff; |
| |
| if (timing_info_present_flag) { |
| fixed_frame_rate_flag = seq_info & 0x40; |
| |
| if (((num_units_in_tick * 120) >= time_scale |
| && ((!sync_outside) || (!frame_dur))) && |
| num_units_in_tick |
| && time_scale) { |
| if (use_idr_framerate || !frame_dur |
| || !duration_from_pts_done || vh264_running) { |
| u32 frame_dur_es = |
| div_u64(96000ULL * 2 * |
| num_units_in_tick, |
| time_scale); |
| |
| /* hack to avoid use ES frame duration |
| * when it's half of the rate from |
| * system info |
| */ |
| /* sometimes the encoder is given a wrong |
| * frame rate but the system side information |
| *is more reliable |
| */ |
| if ((frame_dur * 2) != frame_dur_es) { |
| frame_dur = frame_dur_es; |
| if (fr_hint_status == VDEC_NEED_HINT) { |
| schedule_work(¬ify_work); |
| fr_hint_status = VDEC_HINTED; |
| } |
| } |
| } |
| } |
| } else |
| pr_info("H.264: timing_info not present\n"); |
| |
| if (aspect_ratio_info_present_flag) { |
| if (aspect_ratio_idc == EXTEND_SAR) { |
| h264_ar = |
| div_u64(256ULL * (aspect_ratio_info >> 16) * |
| frame_height, |
| (aspect_ratio_info & 0xffff) * |
| frame_width); |
| } else { |
| /* pr_info("v264dec: aspect_ratio_idc = %d\n", |
| * aspect_ratio_idc); |
| */ |
| |
| switch (aspect_ratio_idc) { |
| case 1: |
| h264_ar = 0x100 * frame_height / frame_width; |
| break; |
| case 2: |
| h264_ar = 0x100 * frame_height * 11 / |
| (frame_width * 12); |
| break; |
| case 3: |
| h264_ar = 0x100 * frame_height * 11 / |
| (frame_width * 10); |
| break; |
| case 4: |
| h264_ar = 0x100 * frame_height * 11 / |
| (frame_width * 16); |
| break; |
| case 5: |
| h264_ar = 0x100 * frame_height * 33 / |
| (frame_width * 40); |
| break; |
| case 6: |
| h264_ar = 0x100 * frame_height * 11 / |
| (frame_width * 24); |
| break; |
| case 7: |
| h264_ar = 0x100 * frame_height * 11 / |
| (frame_width * 20); |
| break; |
| case 8: |
| h264_ar = 0x100 * frame_height * 11 / |
| (frame_width * 32); |
| break; |
| case 9: |
| h264_ar = 0x100 * frame_height * 33 / |
| (frame_width * 80); |
| break; |
| case 10: |
| h264_ar = 0x100 * frame_height * 11 / |
| (frame_width * 18); |
| break; |
| case 11: |
| h264_ar = 0x100 * frame_height * 11 / |
| (frame_width * 15); |
| break; |
| case 12: |
| h264_ar = 0x100 * frame_height * 33 / |
| (frame_width * 64); |
| break; |
| case 13: |
| h264_ar = 0x100 * frame_height * 99 / |
| (frame_width * 160); |
| break; |
| case 14: |
| h264_ar = 0x100 * frame_height * 3 / |
| (frame_width * 4); |
| break; |
| case 15: |
| h264_ar = 0x100 * frame_height * 2 / |
| (frame_width * 3); |
| break; |
| case 16: |
| h264_ar = 0x100 * frame_height * 1 / |
| (frame_width * 2); |
| break; |
| default: |
| if (vh264_ratio >> 16) { |
| h264_ar = (frame_height * |
| (vh264_ratio & 0xffff) * |
| 0x100 + |
| ((vh264_ratio >> 16) * |
| frame_width / 2)) / |
| ((vh264_ratio >> 16) * |
| frame_width); |
| } else { |
| h264_ar = frame_height * 0x100 / |
| frame_width; |
| } |
| break; |
| } |
| } |
| } else { |
| pr_info("v264dec: aspect_ratio not available from source\n"); |
| if (vh264_ratio >> 16) { |
| /* high 16 bit is width, low 16 bit is height */ |
| h264_ar = |
| ((vh264_ratio & 0xffff) * frame_height * 0x100 + |
| (vh264_ratio >> 16) * frame_width / 2) / |
| ((vh264_ratio >> 16) * frame_width); |
| } else |
| h264_ar = frame_height * 0x100 / frame_width; |
| } |
| |
| WRITE_VREG(AV_SCRATCH_0, |
| (max_reference_size << 24) | (actual_dpb_size << 16) | |
| (max_dpb_size << 8)); |
| if (vh264_stream_switching_state != SWITCHING_STATE_OFF) { |
| vh264_stream_switching_state = SWITCHING_STATE_OFF; |
| pr_info("Leaving switching mode.\n"); |
| } |
| mutex_unlock(&vh264_mutex); |
| } |
| |
| static unsigned int pts_inc_by_duration( |
| unsigned int *new_pts, unsigned int *new_pts_rem) |
| { |
| unsigned int r, rem; |
| |
| r = last_pts + DUR2PTS(frame_dur); |
| rem = last_pts_remainder + DUR2PTS_REM(frame_dur); |
| |
| if (rem >= 96) { |
| r++; |
| rem -= 96; |
| } |
| |
| if (new_pts) |
| *new_pts = r; |
| if (new_pts_rem) |
| *new_pts_rem = rem; |
| |
| return r; |
| } |
| static inline bool vh264_isr_parser(struct vframe_s *vf, |
| unsigned int pts_valid, unsigned int buffer_index, |
| unsigned int pts) |
| { |
| unsigned int pts_duration = 0; |
| |
| if (h264_first_pts_ready == 0) { |
| if (pts_valid == 0) { |
| vfbuf_use[buffer_index]++; |
| vf->index = buffer_index; |
| kfifo_put(&recycle_q, |
| (const struct vframe_s *)vf); |
| return false; |
| } |
| |
| h264pts1 = pts; |
| h264_pts_count = 0; |
| h264_first_pts_ready = 1; |
| } else { |
| if (pts < h264pts1) { |
| if (h264_pts_count > 24) { |
| pr_info("invalid h264pts1, reset\n"); |
| h264pts1 = pts; |
| h264_pts_count = 0; |
| } |
| } |
| if (pts_valid && (pts > h264pts1) && (h264_pts_count > 24) |
| && (duration_from_pts_done == 0)) { |
| unsigned int |
| old_duration = frame_dur; |
| h264pts2 = pts; |
| |
| pts_duration = (h264pts2 - h264pts1) * 16 / |
| (h264_pts_count * 15); |
| |
| if ((pts_duration != frame_dur) |
| && (!pts_outside)) { |
| if (use_idr_framerate) { |
| bool pts_c_24 = close_to(pts_duration, |
| RATE_24_FPS, |
| RATE_CORRECTION_THRESHOLD); |
| bool frm_c_25 = close_to(frame_dur, |
| RATE_25_FPS, |
| RATE_CORRECTION_THRESHOLD); |
| bool pts_c_25 = close_to(pts_duration, |
| RATE_25_FPS, |
| RATE_CORRECTION_THRESHOLD); |
| bool frm_c_24 = close_to(frame_dur, |
| RATE_24_FPS, |
| RATE_CORRECTION_THRESHOLD); |
| if ((pts_c_24 && frm_c_25) |
| || (pts_c_25 && frm_c_24)) { |
| pr_info |
| ("H.264:Correct frame dur "); |
| pr_info |
| (" from %d to duration based ", |
| frame_dur); |
| pr_info |
| ("on PTS %d ---\n", |
| pts_duration); |
| frame_dur = pts_duration; |
| duration_from_pts_done = 1; |
| } else if (((frame_dur < 96000 / 240) |
| && (pts_duration > 96000 / 240)) |
| || (!duration_on_correcting && |
| !frm_c_25 && !frm_c_24)) { |
| /* fft: if the frame rate is |
| * not regular, use the |
| * calculate rate insteadof. |
| */ |
| pr_info |
| ("H.264:Correct frame dur "); |
| pr_info |
| (" from %d to duration based ", |
| frame_dur); |
| pr_info |
| ("on PTS %d ---\n", |
| pts_duration); |
| frame_dur = pts_duration; |
| duration_on_correcting = 1; |
| } |
| } else { |
| if (close_to(pts_duration, |
| frame_dur, 2000)) { |
| frame_dur = pts_duration; |
| pr_info |
| ("used calculate frame rate,"); |
| pr_info("on duration =%d\n", |
| frame_dur); |
| } else { |
| pr_info |
| ("don't use calculate frame "); |
| pr_info |
| ("rate pts_duration =%d\n", |
| pts_duration); |
| } |
| } |
| } |
| |
| if (duration_from_pts_done == 0) { |
| if (close_to |
| (pts_duration, |
| old_duration, |
| RATE_CORRECTION_THRESHOLD)) { |
| pr_info |
| ("finished correct frame dur"); |
| pr_info |
| (" new=%d,old_duration=%d,cnt=%d\n", |
| pts_duration, |
| old_duration, |
| h264_pts_count); |
| duration_from_pts_done = 1; |
| } else { /*not the same,redo it. */ |
| if (!close_to(pts_duration, |
| old_duration, 1000) && |
| !close_to(pts_duration, |
| frame_dur, 1000) && |
| close_to(pts_duration, |
| last_duration, 200)) { |
| /* yangle: frame_dur must |
| * wrong,recover it. |
| */ |
| frame_dur = pts_duration; |
| } |
| |
| pr_info |
| ("restart correct frame duration "); |
| pr_info |
| ("new=%d,old_duration=%d,cnt=%d\n", |
| pts_duration, |
| old_duration, |
| h264_pts_count); |
| h264pts1 = h264pts2; |
| h264_pts_count = 0; |
| duration_from_pts_done = 0; |
| } |
| } |
| last_duration = pts_duration; |
| } |
| } |
| return true; |
| } |
| |
| static inline void h264_update_gvs(void) |
| { |
| u32 ratio_control; |
| u32 ar; |
| |
| if (gvs->frame_height != frame_height) { |
| gvs->frame_width = frame_width; |
| gvs->frame_height = frame_height; |
| } |
| if (gvs->frame_dur != frame_dur) { |
| gvs->frame_dur = frame_dur; |
| if (frame_dur != 0) |
| gvs->frame_rate = 96000 / frame_dur; |
| else |
| gvs->frame_rate = -1; |
| } |
| gvs->error_count = READ_VREG(AV_SCRATCH_D); |
| gvs->status = stat; |
| if (fatal_error_reset) |
| gvs->status |= fatal_error_flag; |
| ar = min_t(u32, |
| h264_ar, |
| DISP_RATIO_ASPECT_RATIO_MAX); |
| ratio_control = |
| ar << DISP_RATIO_ASPECT_RATIO_BIT; |
| gvs->ratio_control = ratio_control; |
| } |
| |
| #ifdef HANDLE_H264_IRQ |
| static irqreturn_t vh264_isr(int irq, void *dev_id) |
| #else |
| static void vh264_isr(void) |
| #endif |
| { |
| unsigned int buffer_index; |
| struct vframe_s *vf; |
| unsigned int cpu_cmd; |
| unsigned int pts, pts_lookup_save, pts_valid_save, pts_valid = 0; |
| unsigned int pts_us64_valid = 0; |
| unsigned int framesize; |
| u64 pts_us64; |
| bool force_interlaced_frame = false; |
| unsigned int sei_itu35_flags; |
| |
| static const unsigned int idr_num = |
| FIX_FRAME_RATE_CHECK_IDRFRAME_NUM; |
| static const unsigned int flg_1080_itl = |
| DEC_CONTROL_FLAG_FORCE_2997_1080P_INTERLACE; |
| static const unsigned int flg_576_itl = |
| DEC_CONTROL_FLAG_FORCE_2500_576P_INTERLACE; |
| |
| WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); |
| |
| if (0 == (stat & STAT_VDEC_RUN)) { |
| pr_info("decoder is not running\n"); |
| #ifdef HANDLE_H264_IRQ |
| return IRQ_HANDLED; |
| #else |
| return; |
| #endif |
| } |
| |
| cpu_cmd = READ_VREG(AV_SCRATCH_0); |
| |
| #ifdef DROP_B_FRAME_FOR_1080P_50_60FPS |
| if ((frame_dur < 2004) && |
| (frame_width >= 1400) && |
| (frame_height >= 1000) && (last_interlaced == 0)) |
| SET_VREG_MASK(AV_SCRATCH_F, 0x8); |
| #endif |
| if ((decoder_force_reset == 1) |
| || ((error_recovery_mode != 1) |
| && (no_idr_error_count >= no_idr_error_max) |
| && (ucode_type != UCODE_IP_ONLY_PARAM))) { |
| vh264_running = 0; |
| pr_info("force reset decoder %d!!!\n", no_idr_error_count); |
| schedule_work(&error_wd_work); |
| decoder_force_reset = 0; |
| no_idr_error_count = 0; |
| } else if ((cpu_cmd & 0xff) == 1) { |
| if (unlikely |
| (vh264_running |
| && (kfifo_len(&newframe_q) != VF_POOL_SIZE))) { |
| /* a cmd 1 sent during decoding w/o getting a cmd 3. */ |
| /* should not happen but the original code has such |
| * case, do the same process |
| */ |
| if ((READ_VREG(AV_SCRATCH_1) & 0xff) |
| == 1) {/*invalid mb_width*/ |
| vh264_running = 0; |
| fatal_error_flag = DECODER_FATAL_ERROR_UNKNOWN; |
| /* this is fatal error, need restart */ |
| pr_info("cmd 1 fatal error happened\n"); |
| schedule_work(&error_wd_work); |
| } else { |
| vh264_stream_switching_state = SWITCHING_STATE_ON_CMD1; |
| pr_info("Enter switching mode cmd1.\n"); |
| schedule_work(&stream_switching_work); |
| } |
| return IRQ_HANDLED; |
| } |
| pr_info("Enter set parameter cmd1.\n"); |
| schedule_work(&set_parameter_work); |
| return IRQ_HANDLED; |
| } else if ((cpu_cmd & 0xff) == 2) { |
| int frame_mb_only, pic_struct_present, pic_struct, prog_frame, |
| poc_sel, idr_flag, eos, error; |
| int i, status, num_frame, b_offset; |
| int current_error_count, slice_type; |
| |
| vh264_running = 1; |
| vh264_no_disp_count = 0; |
| num_frame = (cpu_cmd >> 8) & 0xff; |
| frame_mb_only = seq_info & 0x8000; |
| pic_struct_present = seq_info & 0x10; |
| |
| current_error_count = READ_VREG(AV_SCRATCH_D); |
| if (vh264_error_count != current_error_count) { |
| /* pr_info("decoder error happened, count %d\n", |
| * current_error_count); |
| */ |
| vh264_error_count = current_error_count; |
| } |
| |
| for (i = 0; (i < num_frame) && (!vh264_eos); i++) { |
| status = READ_VREG(AV_SCRATCH_1 + i); |
| buffer_index = status & 0x1f; |
| error = status & 0x200; |
| slice_type = (READ_VREG(AV_SCRATCH_H) >> (i * 4)) & 0xf; |
| |
| if ((error_recovery_mode_use & 2) && error) |
| check_pts_discontinue = true; |
| if (ucode_type == UCODE_IP_ONLY_PARAM |
| && iponly_early_mode) |
| continue; |
| if ((p_last_vf != NULL) |
| && (p_last_vf->index == buffer_index)) |
| continue; |
| |
| if (buffer_index >= VF_BUF_NUM) |
| continue; |
| |
| pic_struct = (status >> 5) & 0x7; |
| prog_frame = status & 0x100; |
| poc_sel = status & 0x200; |
| idr_flag = status & 0x400; |
| frame_packing_type = (status >> 12) & 0x7; |
| eos = (status >> 15) & 1; |
| |
| if (eos) |
| vh264_eos = 1; |
| |
| b_offset = (status >> 16) & 0xffff; |
| |
| if (error) |
| no_idr_error_count++; |
| if (idr_flag || |
| (!error && (slice_type != SLICE_TYPE_I))) |
| no_idr_error_count = 0; |
| |
| if (decoder_debug_flag) { |
| pr_info |
| ("slice_type %x idr %x error %x count %d", |
| slice_type, idr_flag, error, |
| no_idr_error_count); |
| pr_info(" prog %x pic_struct %x offset %x\n", |
| prog_frame, pic_struct, b_offset); |
| } |
| #ifdef DROP_B_FRAME_FOR_1080P_50_60FPS |
| last_interlaced = prog_frame ? 0 : 1; |
| #endif |
| if (kfifo_get(&newframe_q, &vf) == 0) { |
| pr_info |
| ("fatal error, no available buffer slot."); |
| return IRQ_HANDLED; |
| } |
| |
| if (clk_adj_frame_count < (VDEC_CLOCK_ADJUST_FRAME + 1)) |
| clk_adj_frame_count++; |
| |
| set_frame_info(vf); |
| |
| switch (i) { |
| case 0: |
| b_offset |= |
| (READ_VREG(AV_SCRATCH_A) & 0xffff) |
| << 16; |
| break; |
| case 1: |
| b_offset |= |
| READ_VREG(AV_SCRATCH_A) & 0xffff0000; |
| break; |
| case 2: |
| b_offset |= |
| (READ_VREG(AV_SCRATCH_B) & 0xffff) |
| << 16; |
| break; |
| case 3: |
| b_offset |= |
| READ_VREG(AV_SCRATCH_B) & 0xffff0000; |
| break; |
| case 4: |
| b_offset |= |
| (READ_VREG(AV_SCRATCH_C) & 0xffff) |
| << 16; |
| break; |
| case 5: |
| b_offset |= |
| READ_VREG(AV_SCRATCH_C) & 0xffff0000; |
| break; |
| default: |
| break; |
| } |
| |
| if (error) |
| gvs->drop_frame_count++; |
| |
| /* add 64bit pts us ; */ |
| if (unlikely |
| ((b_offset == first_offset) |
| && (first_pts_cached))) { |
| pts = first_pts; |
| pts_us64 = first_pts64; |
| framesize = first_frame_size; |
| first_pts_cached = false; |
| pts_valid = 1; |
| pts_us64_valid = 1; |
| #ifdef DEBUG_PTS |
| pts_hit++; |
| #endif |
| } else if (pts_lookup_offset_us64 |
| (PTS_TYPE_VIDEO, b_offset, &pts, |
| &framesize, 0, &pts_us64) == 0) { |
| pts_valid = 1; |
| pts_us64_valid = 1; |
| #ifdef DEBUG_PTS |
| pts_hit++; |
| #endif |
| } else { |
| pts_valid = 0; |
| pts_us64_valid = 0; |
| framesize = 0; |
| #ifdef DEBUG_PTS |
| pts_missed++; |
| #endif |
| } |
| |
| if (idr_flag) |
| s_vframe_qos.type = 4; |
| else if (slice_type == SLICE_TYPE_I) |
| s_vframe_qos.type = 1; |
| else if (slice_type == SLICE_TYPE_P) |
| s_vframe_qos.type = 2; |
| else if (slice_type == SLICE_TYPE_B || slice_type == 8) |
| s_vframe_qos.type = 3; |
| |
| s_vframe_qos.size = framesize; |
| |
| if (pts_valid) |
| s_vframe_qos.pts = pts; |
| else |
| s_vframe_qos.pts = last_pts + DUR2PTS(frame_dur); |
| #ifndef ENABLE_SEI_ITU_T35 |
| if (get_cpu_major_id() < AM_MESON_CPU_MAJOR_ID_G12A) { |
| u32 reg_data; |
| if (i) { |
| reg_data = READ_VREG(AV_SCRATCH_N); |
| s_vframe_qos.max_mv |
| = (reg_data >> 16) & 0xffff; |
| s_vframe_qos.avg_mv |
| = (reg_data >> 8) & 0xff; |
| s_vframe_qos.min_mv |
| = reg_data & 0xff; |
| reg_data = READ_VREG(AV_SCRATCH_L); |
| s_vframe_qos.max_qp |
| = (reg_data >> 16) & 0xff; |
| s_vframe_qos.avg_qp |
| = (reg_data >> 8) & 0xff; |
| s_vframe_qos.min_qp |
| = reg_data & 0xff; |
| reg_data = READ_VREG(AV_SCRATCH_M); |
| s_vframe_qos.max_skip |
| = (reg_data >> 16) & 0xff; |
| s_vframe_qos.avg_skip |
| = (reg_data >> 8) & 0xff; |
| s_vframe_qos.min_skip |
| = reg_data & 0xff; |
| } else { |
| reg_data = READ_VREG(AV_SCRATCH_J); |
| s_vframe_qos.max_mv |
| = (reg_data >> 16) & 0xffff; |
| s_vframe_qos.avg_mv |
| = (reg_data >> 8) & 0xff; |
| s_vframe_qos.min_mv |
| = reg_data & 0xff; |
| reg_data = READ_VREG(AV_SCRATCH_I); |
| s_vframe_qos.max_qp |
| = (reg_data >> 16) & 0xff; |
| s_vframe_qos.avg_qp |
| = (reg_data >> 8) & 0xff; |
| s_vframe_qos.min_qp |
| = reg_data & 0xff; |
| reg_data = READ_VREG(AV_SCRATCH_K); |
| s_vframe_qos.max_skip |
| = (reg_data >> 16) & 0xff; |
| s_vframe_qos.avg_skip |
| = (reg_data >> 8) & 0xff; |
| s_vframe_qos.min_skip |
| = reg_data & 0xff; |
| } |
| if (decoder_debug_flag&0x2) { |
| pr_info("max_mv %d avg_mv %d min_mv %d slice_type %d offset %x i = %d\n", |
| s_vframe_qos.max_mv, |
| s_vframe_qos.avg_mv, |
| s_vframe_qos.min_mv, |
| slice_type, |
| b_offset, |
| i); |
| pr_info("max_qp %d avg_qp %d min_qp %d\n", |
| s_vframe_qos.max_qp, |
| s_vframe_qos.avg_qp, |
| s_vframe_qos.min_qp); |
| pr_info("max_skip %d avg_skip %d min_skip %d\n", |
| s_vframe_qos.max_skip, |
| s_vframe_qos.avg_skip, |
| s_vframe_qos.min_skip); |
| } |
| } else |
| search_qos_node(&s_vframe_qos, b_offset); |
| #endif |
| frame_count++; |
| |
| s_vframe_qos.num = frame_count; |
| //vdec_fill_frame_info(&s_vframe_qos, 1); |
| |
| /* on second IDR frame,check the diff between pts |
| * compute from duration and pts from lookup , |
| * if large than frame_dur,we think it is uncorrect. |
| */ |
| pts_lookup_save = pts; |
| pts_valid_save = pts_valid; |
| if (fixed_frame_rate_flag |
| && (fixed_frame_rate_check_count <= |
| idr_num)) { |
| if (idr_flag && pts_valid) { |
| fixed_frame_rate_check_count++; |
| /* pr_info("diff:%d\n", |
| * last_pts - pts_lookup_save); |
| */ |
| if ((fixed_frame_rate_check_count == |
| idr_num) && |
| (abs(pts - (last_pts + |
| DUR2PTS(frame_dur))) > |
| DUR2PTS(frame_dur))) { |
| fixed_frame_rate_flag = 0; |
| pr_info("pts sync mode play\n"); |
| } |
| |
| if (fixed_frame_rate_flag |
| && (fixed_frame_rate_check_count |
| > idr_num)) { |
| pr_info |
| ("fix_frame_rate mode play\n"); |
| } |
| } |
| } |
| |
| if (READ_VREG(AV_SCRATCH_F) & 2) { |
| /* for I only mode, ignore the PTS information |
| * and only uses frame duration for each I |
| * frame decoded |
| */ |
| if (p_last_vf) |
| pts_valid = 0; |
| /* also skip frame duration calculation |
| * based on PTS |
| */ |
| duration_from_pts_done = 1; |
| /* and add a default duration for 1/30 second |
| * if there is no valid frame |
| * duration available |
| */ |
| if (frame_dur == 0) |
| frame_dur = 96000 / 30; |
| } |
| |
| if (sync_outside == 0) { |
| if (!vh264_isr_parser(vf, |
| pts_valid, buffer_index, pts)) |
| continue; |
| |
| h264_pts_count++; |
| } else { |
| if (!idr_flag) |
| pts_valid = 0; |
| } |
| |
| if (pts_valid && !pts_discontinue) { |
| pts_discontinue = |
| (abs(last_pts - pts) >= |
| tsync_vpts_discontinuity_margin()); |
| } |
| /* if use_idr_framerate or fixed frame rate, only |
| * use PTS for IDR frames except for pts discontinue |
| */ |
| if (timing_info_present_flag && |
| frame_dur && |
| (use_idr_framerate || |
| (fixed_frame_rate_flag != 0)) |
| && pts_valid && h264_first_valid_pts_ready |
| && (!pts_discontinue)) { |
| pts_valid = |
| (slice_type == SLICE_TYPE_I) ? 1 : 0; |
| } |
| |
| if (!h264_first_valid_pts_ready && pts_valid) { |
| h264_first_valid_pts_ready = true; |
| last_pts = pts - DUR2PTS(frame_dur); |
| last_pts_remainder = 0; |
| } |
| /* calculate PTS of next frame and smooth |
| * PTS for fixed rate source |
| */ |
| if (pts_valid) { |
| if ((fixed_frame_rate_flag) && |
| (!pts_discontinue) && |
| (abs(pts_inc_by_duration(NULL, NULL) |
| - pts) |
| < DUR2PTS(frame_dur))) { |
| pts = pts_inc_by_duration(&pts, |
| &last_pts_remainder); |
| } else |
| last_pts_remainder = 0; |
| |
| } else { |
| if (fixed_frame_rate_flag && !pts_discontinue && |
| (fixed_frame_rate_check_count > idr_num) && |
| pts_valid_save && (sync_outside == 0) && |
| (abs(pts_inc_by_duration(NULL, NULL) - pts) |
| > DUR2PTS(frame_dur))) { |
| duration_from_pts_done = 0; |
| pr_info("recalc frame_dur\n"); |
| } else |
| pts = pts_inc_by_duration(&pts, |
| &last_pts_remainder); |
| pts_valid = 1; |
| } |
| |
| if ((dec_control & |
| flg_1080_itl) |
| && (frame_width == 1920) |
| && (frame_height >= 1080) |
| && (vf->duration == 3203)) |
| force_interlaced_frame = true; |
| else if ((dec_control & |
| flg_576_itl) |
| && (frame_width == 720) |
| && (frame_height == 576) |
| && (vf->duration == 3840)) |
| force_interlaced_frame = true; |
| |
| /* for frames with PTS, check if there is PTS |
| * discontinue based on previous frames |
| * (including error frames), |
| * force no VPTS discontinue reporting if we saw |
| *errors earlier but only once. |
| */ |
| |
| /*count info*/ |
| h264_update_gvs(); |
| vdec_count_info(gvs, error, b_offset); |
| vdec_fill_vdec_frame(vdec_h264, &s_vframe_qos, gvs, vf, 0); |
| |
| if ((pts_valid) && (check_pts_discontinue) |
| && (!error)) { |
| if (pts_discontinue) { |
| vf->flag = 0; |
| check_pts_discontinue = false; |
| } else if ((pts - last_pts) < 90000) { |
| vf->flag = VFRAME_FLAG_NO_DISCONTINUE; |
| check_pts_discontinue = false; |
| } |
| } |
| |
| last_pts = pts; |
| |
| if (fixed_frame_rate_flag |
| && (fixed_frame_rate_check_count <= |
| idr_num) |
| && (sync_outside == 0) |
| && pts_valid_save) |
| pts = pts_lookup_save; |
| |
| if (pic_struct_present) { |
| if ((pic_struct == PIC_TOP_BOT) |
| || (pic_struct == PIC_BOT_TOP)) |
| prog_frame = 0; |
| } |
| |
| if ((!force_interlaced_frame) |
| && (prog_frame |
| || (pic_struct_present |
| && pic_struct |
| <= PIC_TRIPLE_FRAME))) { |
| if (pic_struct_present) { |
| if (pic_struct == PIC_TOP_BOT_TOP |
| || pic_struct |
| == PIC_BOT_TOP_BOT) { |
| vf->duration += |
| vf->duration >> 1; |
| } else if (pic_struct == |
| PIC_DOUBLE_FRAME) |
| vf->duration += vf->duration; |
| else if (pic_struct == |
| PIC_TRIPLE_FRAME) { |
| vf->duration += |
| vf->duration << 1; |
| } |
| } |
| |
| last_pts = |
| last_pts + DUR2PTS(vf->duration - |
| frame_dur); |
| |
| vf->index = buffer_index; |
| vf->type = |
| VIDTYPE_PROGRESSIVE | |
| VIDTYPE_VIU_FIELD | |
| VIDTYPE_VIU_NV21; |
| vf->duration_pulldown = 0; |
| vf->signal_type = video_signal_from_vui; |
| vf->index = buffer_index; |
| vf->pts = (pts_valid) ? pts : 0; |
| if (pts_us64_valid == 1) |
| vf->pts_us64 = pts_us64; |
| else |
| vf->pts_us64 = div64_u64(((u64)vf->pts)*100, 9); |
| vf->canvas0Addr = vf->canvas1Addr = |
| spec2canvas(&buffer_spec[buffer_index]); |
| vf->type_original = vf->type; |
| vfbuf_use[buffer_index]++; |
| vf->mem_handle = |
| decoder_bmmu_box_get_mem_handle( |
| mm_blk_handle, |
| VF_BUFFER_IDX(buffer_index)); |
| decoder_do_frame_check(NULL, vf); |
| if ((error_recovery_mode_use & 2) && error) { |
| kfifo_put(&recycle_q, |
| (const struct vframe_s *)vf); |
| } else { |
| p_last_vf = vf; |
| pts_discontinue = false; |
| kfifo_put(&delay_display_q, |
| (const struct vframe_s *)vf); |
| } |
| } else { |
| if (pic_struct_present |
| && pic_struct == PIC_TOP_BOT) |
| vf->type = VIDTYPE_INTERLACE_TOP; |
| else if (pic_struct_present |
| && pic_struct == PIC_BOT_TOP) |
| vf->type = VIDTYPE_INTERLACE_BOTTOM; |
| else { |
| vf->type = |
| poc_sel ? |
| VIDTYPE_INTERLACE_BOTTOM : |
| VIDTYPE_INTERLACE_TOP; |
| } |
| vf->type |= VIDTYPE_VIU_NV21; |
| vf->type |= VIDTYPE_INTERLACE_FIRST; |
| |
| high_bandwidth |= |
|