55 files changed, 11471 insertions, 2282 deletions
diff --git a/drivers/amvdec_ports/decoder/vdec_hevc_if.c b/drivers/amvdec_ports/decoder/vdec_hevc_if.c index 0870da7..59ce85f 100644 --- a/drivers/amvdec_ports/decoder/vdec_hevc_if.c +++ b/drivers/amvdec_ports/decoder/vdec_hevc_if.c @@ -31,7 +31,7 @@ #include "../aml_vcodec_vfm.h" #include "aml_hevc_parser.h" -#define NAL_TYPE(value) ((value) & 0x1F) +#define HEVC_NAL_TYPE(value) ((value >> 1) & 0x3F) #define HEADER_BUFFER_SIZE (32 * 1024) /** @@ -93,10 +93,11 @@ struct vdec_hevc_vsi { int head_offset; struct vdec_hevc_dec_info dec; struct vdec_pic_info pic; + struct vdec_pic_info cur_pic; struct v4l2_rect crop; bool is_combine; int nalu_pos; - struct HEVCParamSets ps; + struct h265_param_sets ps; }; /** @@ -111,59 +112,9 @@ struct vdec_hevc_inst { struct aml_vdec_adapt vdec; struct vdec_hevc_vsi *vsi; struct vcodec_vfm_s vfm; + struct completion comp; }; -#if 0 -#define DUMP_FILE_NAME "/data/dump/dump.tmp" -static struct file *filp; -static loff_t file_pos; - -void dump_write(const char __user *buf, size_t count) -{ - mm_segment_t old_fs; - - if (!filp) - return; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - if (count != vfs_write(filp, buf, count, &file_pos)) - pr_err("Failed to write file\n"); - - set_fs(old_fs); -} - -void dump_init(void) -{ - filp = filp_open(DUMP_FILE_NAME, O_CREAT | O_RDWR, 0644); - if (IS_ERR(filp)) { - pr_err("open dump file failed\n"); - filp = NULL; - } -} - -void dump_deinit(void) -{ - if (filp) { - filp_close(filp, current->files); - filp = NULL; - file_pos = 0; - } -} - -void swap_uv(void *uv, int size) -{ - int i; - __u16 *p = uv; - - size /= 2; - - for (i = 0; i < size; i++, p++) - *p = __swab16(*p); -} -#endif - static void get_pic_info(struct vdec_hevc_inst *inst, struct vdec_pic_info *pic) { @@ -189,22 +140,10 @@ static void get_crop_info(struct vdec_hevc_inst *inst, struct v4l2_rect *cr) static void get_dpb_size(struct vdec_hevc_inst *inst, unsigned int *dpb_sz) { - *dpb_sz = 20;//inst->vsi->dec.dpb_sz; + *dpb_sz = inst->vsi->dec.dpb_sz; aml_vcodec_debug(inst, "sz=%d", *dpb_sz); } -static int find_start_code(unsigned char *data, unsigned int data_sz) -{ - if (data_sz > 3 && data[0] == 0 && data[1] == 0 && data[2] == 1) - return 3; - - if (data_sz > 4 && data[0] == 0 && data[1] == 0 && data[2] == 0 && - data[3] == 1) - return 4; - - return -1; -} - static int vdec_hevc_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) { struct vdec_hevc_inst *inst = NULL; @@ -216,7 +155,7 @@ static int vdec_hevc_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) inst->ctx = ctx; - inst->vdec.format = VFORMAT_HEVC; + inst->vdec.video_type = VFORMAT_HEVC; inst->vdec.dev = ctx->dev->vpu_plat_dev; inst->vdec.filp = ctx->dev->filp; inst->vdec.ctx = ctx; @@ -262,6 +201,8 @@ static int vdec_hevc_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) inst->vsi->pic.c_bs_sz = 0; inst->vsi->pic.c_len_sz = (1920 * 1088 / 2); + init_completion(&inst->comp); + aml_vcodec_debug(inst, "hevc Instance >> %p", inst); ctx->ada_ctx = &inst->vdec; @@ -280,31 +221,48 @@ error_free_inst: return ret; } -#if 0 -static int refer_buffer_num(int level_idc, int poc_cnt, - int mb_width, int mb_height) + +static int refer_buffer_num(struct h265_SPS_t *sps) { - return 20; + int used_buf_num = 0; + int sps_pic_buf_diff = 0; + + if ((!sps->temporal_layer[0].num_reorder_pics) && + (sps->temporal_layer[0].max_dec_pic_buffering)) { + /* the range of sps_num_reorder_pics_0 is in + [0, sps_max_dec_pic_buffering_minus1_0] */ + used_buf_num = sps->temporal_layer[0].max_dec_pic_buffering; + } else + used_buf_num = sps->temporal_layer[0].num_reorder_pics; + + sps_pic_buf_diff = sps->temporal_layer[0].max_dec_pic_buffering - + sps->temporal_layer[0].num_reorder_pics + 1; + + if (sps_pic_buf_diff >= 4) + used_buf_num += 1; + + /*need one more for multi instance, as + apply_ref_pic_set() has no chanch to run to + to clear referenced flag in some case */ + used_buf_num++; + + /* for eos add more buffer to flush.*/ + used_buf_num++; + + return used_buf_num; } -#endif -//static void fill_vdec_params(struct vdec_hevc_inst *inst, struct hevc_SPS_t *sps) -static void fill_vdec_params(struct vdec_hevc_inst *inst) +static void fill_vdec_params(struct vdec_hevc_inst *inst, struct h265_SPS_t *sps) { struct vdec_pic_info *pic = &inst->vsi->pic; struct vdec_hevc_dec_info *dec = &inst->vsi->dec; struct v4l2_rect *rect = &inst->vsi->crop; - unsigned int mb_w = 0, mb_h = 0, width, height; - //unsigned int crop_unit_x = 0, crop_unit_y = 0; - //unsigned int poc_cnt = 0; - - /* calc width & height. */ - width = 1920; - height = 1080; /* fill visible area size that be used for EGL. */ - pic->visible_width = width; - pic->visible_height = height; + pic->visible_width = sps->width - (sps->output_window.left_offset + + sps->output_window.right_offset); + pic->visible_height = sps->height - (sps->output_window.top_offset + + sps->output_window.bottom_offset); /* calc visible ares. */ rect->left = 0; @@ -313,123 +271,61 @@ static void fill_vdec_params(struct vdec_hevc_inst *inst) rect->height = pic->visible_height; /* config canvas size that be used for decoder. */ - pic->coded_width = ALIGN(mb_w, 4) << 4; - pic->coded_height = ALIGN(mb_h, 4) << 4; - - pic->coded_width = 1920; - pic->coded_height = 1088;//temp + pic->coded_width = ALIGN(sps->width, 32); + pic->coded_height = ALIGN(sps->height, 32); pic->y_len_sz = pic->coded_width * pic->coded_height; pic->c_len_sz = pic->y_len_sz >> 1; /* calc DPB size */ - dec->dpb_sz = 20;//refer_buffer_num(sps->level_idc, poc_cnt, mb_w, mb_h); + dec->dpb_sz = refer_buffer_num(sps); pr_info("[%d] The stream infos, coded:(%d x %d), visible:(%d x %d), DPB: %d\n", inst->ctx->id, pic->coded_width, pic->coded_height, pic->visible_width, pic->visible_height, dec->dpb_sz); } -static int hevc_parse_nal_header(u32 val) +static int stream_parse_by_ucode(struct vdec_hevc_inst *inst, u8 *buf, u32 size) { - if (val & 0x80) { - pr_err("the nal data is invalid.\n"); - return -1; - } + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; - return (val & 0x7f) >> 1; -} + ret = vdec_vframe_write(vdec, buf, size, 0); + if (ret < 0) { + pr_err("write frame data failed. err: %d\n", ret); + return ret; + } -static void hevc_parse(struct HEVCParamSets *ps, u8 *buf, u32 size) -{ - //int ret = -1; - int i = 0, j = 0, cnt = 0; - int pos, nal_size, nal_type; - u8 *p = buf; + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); - for (i = 4; i < size; i++) { - j = find_start_code(p, i); - if (j > 0) { - pos = p - buf + j; - nal_size = size - pos; - nal_type = hevc_parse_nal_header(buf[pos]); - - switch (nal_type) { - case HEVC_NAL_VPS: - //ret = hevc_parse_nal_vps(&ps->vps, p, nal_size); - //if (!ret) - //ps->vps_parsed = true; - pr_err("------%s,%d nal type: %u\n",__func__, __LINE__,nal_type); - break; - case HEVC_NAL_SPS: - //ret = hevc_parse_nal_sps(&ps->sps, p, nal_size); - //if (!ret) - ps->sps_parsed = true; - pr_err("------%s,%d nal type: %u\n",__func__, __LINE__,nal_type); - break; - case HEVC_NAL_PPS: - //ret = hevc_parse_nal_pps(&ps->pps, p, nal_size); - //if (!ret) - //ps->sps_parsed = true; - pr_err("------%s,%d nal type: %u\n",__func__, __LINE__,nal_type); - break; - case HEVC_NAL_SEI_PREFIX: - case HEVC_NAL_SEI_SUFFIX: - //ret = hevc_parse_nal_sei(&ps->sei, p, nal_size); - //if (!ret) - //ps->sei_parsed = true; - pr_err("------%s,%d nal type: %u\n",__func__, __LINE__,nal_type); - break; - default: - pr_info("ignoring NAL type %d in extradata\n", nal_type); - break; - } - - cnt++; - p += j; - i = pos; - } - p++; - } + return inst->vsi->dec.dpb_sz ? 0 : -1; } static int stream_parse(struct vdec_hevc_inst *inst, u8 *buf, u32 size) { - //struct hevc_stream_t s; - //struct hevc_SPS_t *sps; - //unsigned int nal_type; - int nal_idx = 0; - int real_data_pos, real_data_size; - bool is_combine = false; - - hevc_parse(&inst->vsi->ps, buf, size); - - if (!inst->vsi->ps.sps_parsed) - return -1; - - /* if the st compose from csd + slice that is the combine data. */ - inst->vsi->is_combine = is_combine; - inst->vsi->nalu_pos = nal_idx; - - /* start code plus nal type. */ - real_data_pos = nal_idx + 1; - real_data_size = size - real_data_pos; + int ret = 0; + struct h265_param_sets *ps = NULL; - //sps = kzalloc(sizeof(struct hevc_SPS_t), GFP_KERNEL); - //if (sps == NULL) - //return -ENOMEM; + ps = kzalloc(sizeof(struct h265_param_sets), GFP_KERNEL); + if (ps == NULL) + return -ENOMEM; - /* the extra data would be parsed. */ - //hevc_stream_set(&s, &buf[real_data_pos], real_data_size); - //hevc_sps_parse(&s, sps); - //hevc_sps_info(sps); + ret = h265_decode_extradata_ps(buf, size, ps); + if (ret) { + pr_err("parse extra data failed. err: %d\n", ret); + goto out; + } - //fill_vdec_params(inst, sps); - fill_vdec_params(inst); + if (ps->sps_parsed) + fill_vdec_params(inst, &ps->sps); - //kfree(sps); + ret = ps->sps_parsed ? 0 : -1; +out: + kfree(ps); - return 0; + return ret; } static int vdec_hevc_probe(unsigned long h_vdec, @@ -438,7 +334,7 @@ static int vdec_hevc_probe(unsigned long h_vdec, struct vdec_hevc_inst *inst = (struct vdec_hevc_inst *)h_vdec; struct stream_info *st; - u8 *buf = (u8 *)bs->va; + u8 *buf = (u8 *)bs->vaddr; u32 size = bs->size; int ret = 0; @@ -448,18 +344,23 @@ static int vdec_hevc_probe(unsigned long h_vdec, if (st->magic == NORe || st->magic == NORn) ret = stream_parse(inst, st->data, st->length); - else - ret = stream_parse(inst, buf, size); + else { + if (inst->ctx->param_sets_from_ucode) + ret = stream_parse_by_ucode(inst, buf, size); + else + ret = stream_parse(inst, buf, size); + } + + inst->vsi->cur_pic = inst->vsi->pic; return ret; } static void vdec_hevc_deinit(unsigned long h_vdec) { + ulong flags; struct vdec_hevc_inst *inst = (struct vdec_hevc_inst *)h_vdec; - - if (!inst) - return; + struct aml_vcodec_ctx *ctx = inst->ctx; aml_vcodec_debug_enter(inst); @@ -469,6 +370,7 @@ static void vdec_hevc_deinit(unsigned long h_vdec) //dump_deinit(); + spin_lock_irqsave(&ctx->slock, flags); if (inst->vsi && inst->vsi->header_buf) kfree(inst->vsi->header_buf); @@ -476,20 +378,20 @@ static void vdec_hevc_deinit(unsigned long h_vdec) kfree(inst->vsi); kfree(inst); + + ctx->drv_handle = 0; + spin_unlock_irqrestore(&ctx->slock, flags); } -static int vdec_hevc_get_fb(struct vdec_hevc_inst *inst, struct vdec_fb **out) +static int vdec_hevc_get_fb(struct vdec_hevc_inst *inst, struct vdec_v4l2_buffer **out) { return get_fb_from_queue(inst->ctx, out); } -static void vdec_hevc_get_vf(struct vdec_hevc_inst *inst, struct vdec_fb **out) +static void vdec_hevc_get_vf(struct vdec_hevc_inst *inst, struct vdec_v4l2_buffer **out) { struct vframe_s *vf = NULL; - struct vdec_fb *fb = NULL; - - aml_vcodec_debug(inst, "%s() [%d], vfm: %p", - __func__, __LINE__, &inst->vfm); + struct vdec_v4l2_buffer *fb = NULL; vf = peek_video_frame(&inst->vfm); if (!vf) { @@ -507,114 +409,80 @@ static void vdec_hevc_get_vf(struct vdec_hevc_inst *inst, struct vdec_fb **out) atomic_set(&vf->use_cnt, 1); - aml_vcodec_debug(inst, "%s() [%d], vf: %p, v4l_mem_handle: %lx, idx: %d\n", - __func__, __LINE__, vf, vf->v4l_mem_handle, vf->index); - - fb = (struct vdec_fb *)vf->v4l_mem_handle; + fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; fb->vf_handle = (unsigned long)vf; fb->status = FB_ST_DISPLAY; *out = fb; //pr_info("%s, %d\n", __func__, fb->base_y.bytes_used); - //dump_write(fb->base_y.va, fb->base_y.bytes_used); - //dump_write(fb->base_c.va, fb->base_c.bytes_used); + //dump_write(fb->base_y.vaddr, fb->base_y.bytes_used); + //dump_write(fb->base_c.vaddr, fb->base_c.bytes_used); /* convert yuv format. */ - //swap_uv(fb->base_c.va, fb->base_c.size); - - aml_vcodec_debug(inst, "%s() [%d], va: %p, phy: %x, size: %zu", - __func__, __LINE__, fb->base_y.va, - (unsigned int)virt_to_phys(fb->base_y.va), fb->base_y.size); - aml_vcodec_debug(inst, "%s() [%d], va: %p, phy: %x, size: %zu", - __func__, __LINE__, fb->base_c.va, - (unsigned int)virt_to_phys(fb->base_c.va), fb->base_c.size); + //swap_uv(fb->base_c.vaddr, fb->base_c.size); } static int vdec_write_nalu(struct vdec_hevc_inst *inst, u8 *buf, u32 size, u64 ts) { - int ret = 0, err = 0; + int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; - bool is_combine = true;//inst->vsi->is_combine; - int nalu_pos; - u32 nal_type; - - nalu_pos = find_start_code(buf, size); - if (nalu_pos < 0) - goto err; - - nal_type = hevc_parse_nal_header(buf[nalu_pos]); - aml_vcodec_debug(inst, "NALU type: %d, size: %u\n", nal_type, size); - - if (nal_type == HEVC_NAL_SPS && !is_combine) { - if (inst->vsi->head_offset + size > HEADER_BUFFER_SIZE) { - ret = -EILSEQ; - goto err; - } - inst->vsi->sps_size = size; - memcpy(inst->vsi->header_buf + inst->vsi->head_offset, buf, size); - inst->vsi->head_offset += inst->vsi->sps_size; - } else if (nal_type == HEVC_NAL_PPS && !is_combine) { - //buf_sz -= nal_start_idx; - if (inst->vsi->head_offset + size > HEADER_BUFFER_SIZE) { - ret = -EILSEQ; - goto err; - } - inst->vsi->pps_size = size; - memcpy(inst->vsi->header_buf + inst->vsi->head_offset, buf, size); - inst->vsi->head_offset += inst->vsi->pps_size; - } else if (nal_type == HEVC_NAL_SEI_PREFIX && !is_combine) { - if (inst->vsi->head_offset + size > HEADER_BUFFER_SIZE) { - ret = -EILSEQ; - goto err; - } - inst->vsi->sei_size = size; - memcpy(inst->vsi->header_buf + inst->vsi->head_offset, buf, size); - inst->vsi->head_offset += inst->vsi->sei_size; - } else { - char *write_buf = vmalloc(inst->vsi->head_offset + size); - memcpy(write_buf, inst->vsi->header_buf, inst->vsi->head_offset); - memcpy(write_buf + inst->vsi->head_offset, buf, size); + ret = vdec_vframe_write(vdec, buf, size, ts); - ret = vdec_vframe_write(vdec, write_buf, - inst->vsi->head_offset + size, ts); + return ret; +} - aml_vcodec_debug(inst, "buf: %p, buf size: %u, write to: %d", - write_buf, inst->vsi->head_offset + size, ret); +static bool monitor_res_change(struct vdec_hevc_inst *inst, u8 *buf, u32 size) +{ + int ret = 0, i = 0, j = 0; + u8 *p = buf; + int len = size; + u32 type; - memset(inst->vsi->header_buf, 0, HEADER_BUFFER_SIZE); - inst->vsi->head_offset = 0; - inst->vsi->sps_size = 0; - inst->vsi->pps_size = 0; - inst->vsi->sei_size = 0; + for (i = 4; i < size; i++) { + j = find_start_code(p, len); + if (j > 0) { + len = size - (p - buf); + type = HEVC_NAL_TYPE(p[j]); + if (type != HEVC_NAL_AUD && + (type > HEVC_NAL_PPS || type < HEVC_NAL_VPS)) + break; - vfree(write_buf); + if (type == HEVC_NAL_SPS) { + ret = stream_parse(inst, p, len); + if (!ret && (inst->vsi->cur_pic.coded_width != + inst->vsi->pic.coded_width || + inst->vsi->cur_pic.coded_height != + inst->vsi->pic.coded_height)) { + inst->vsi->cur_pic = inst->vsi->pic; + return true; + } + } + p += j; + } + p++; } - return 0; -err: - aml_vcodec_err(inst, "%s err(%d)", __func__, err); - - return err; + return false; } static int vdec_hevc_decode(unsigned long h_vdec, struct aml_vcodec_mem *bs, - unsigned long int timestamp, bool *res_chg) + u64 timestamp, bool *res_chg) { struct vdec_hevc_inst *inst = (struct vdec_hevc_inst *)h_vdec; struct aml_vdec_adapt *vdec = &inst->vdec; struct stream_info *st; u8 *buf; u32 size; - int ret = 0; + int ret = -1; /* bs NULL means flush decoder */ if (bs == NULL) - return 0; + return -1; - buf = (u8 *)bs->va; + buf = (u8 *)bs->vaddr; size = bs->size; st = (struct stream_info *)buf; @@ -626,8 +494,13 @@ static int vdec_hevc_decode(unsigned long h_vdec, struct aml_vcodec_mem *bs, ret = vdec_write_nalu(inst, st->data, st->length, timestamp); else if (inst->ctx->is_stream_mode) ret = vdec_vbuf_write(vdec, buf, size); - else + else { + /*checked whether the resolution changes.*/ + if ((*res_chg = monitor_res_change(inst, buf, size))) + return 0; + ret = vdec_write_nalu(inst, buf, size, timestamp); + } return ret; } @@ -672,12 +545,80 @@ static int vdec_hevc_get_param(unsigned long h_vdec, return ret; } +static void set_param_write_sync(struct vdec_hevc_inst *inst) +{ + complete(&inst->comp); +} + +static void set_param_pic_info(struct vdec_hevc_inst *inst, + struct aml_vdec_pic_infos *info) +{ + struct vdec_pic_info *pic = &inst->vsi->pic; + struct vdec_hevc_dec_info *dec = &inst->vsi->dec; + struct v4l2_rect *rect = &inst->vsi->crop; + + /* fill visible area size that be used for EGL. */ + pic->visible_width = info->visible_width; + pic->visible_height = info->visible_height; + + /* calc visible ares. */ + rect->left = 0; + rect->top = 0; + rect->width = pic->visible_width; + rect->height = pic->visible_height; + + /* config canvas size that be used for decoder. */ + pic->coded_width = ALIGN(info->coded_width, 64); + pic->coded_height = ALIGN(info->coded_height, 64); + pic->y_len_sz = pic->coded_width * pic->coded_height; + pic->c_len_sz = pic->y_len_sz >> 1; + + dec->dpb_sz = info->dpb_size; + + /*wake up*/ + complete(&inst->comp); + + pr_info("Parse from ucode, crop(%d x %d), coded(%d x %d) dpb: %d\n", + pic->visible_width, pic->visible_height, + pic->coded_width, pic->coded_height, + dec->dpb_sz); +} + +static int vdec_hevc_set_param(unsigned long h_vdec, + enum vdec_set_param_type type, void *in) +{ + int ret = 0; + struct vdec_hevc_inst *inst = (struct vdec_hevc_inst *)h_vdec; + + if (!inst) { + pr_err("the hevc inst of dec is invalid.\n"); + return -1; + } + + switch (type) { + case SET_PARAM_WRITE_FRAME_SYNC: + set_param_write_sync(inst); + break; + + case SET_PARAM_PIC_INFO: + set_param_pic_info(inst, in); + break; + + default: + aml_vcodec_err(inst, "invalid set parameter type=%d", type); + ret = -EINVAL; + } + + return ret; +} + static struct vdec_common_if vdec_hevc_if = { - vdec_hevc_init, - vdec_hevc_probe, - vdec_hevc_decode, - vdec_hevc_get_param, - vdec_hevc_deinit, + .init = vdec_hevc_init, + .probe = vdec_hevc_probe, + .decode = vdec_hevc_decode, + .get_param = vdec_hevc_get_param, + .set_param = vdec_hevc_set_param, + .deinit = vdec_hevc_deinit, }; struct vdec_common_if *get_hevc_dec_comm_if(void); |