diff options
Diffstat (limited to 'drivers/media/platform/amphion/vdec.c')
-rw-r--r-- | drivers/media/platform/amphion/vdec.c | 218 |
1 files changed, 126 insertions, 92 deletions
diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c index feb75dc204de..87f9f8e90ab1 100644 --- a/drivers/media/platform/amphion/vdec.c +++ b/drivers/media/platform/amphion/vdec.c @@ -69,72 +69,101 @@ struct vdec_t { static const struct vpu_format vdec_formats[] = { { .pixfmt = V4L2_PIX_FMT_NV12M_8L128, - .num_planes = 2, + .mem_planes = 2, + .comp_planes = 2, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .sibling = V4L2_PIX_FMT_NV12_8L128, + }, + { + .pixfmt = V4L2_PIX_FMT_NV12_8L128, + .mem_planes = 1, + .comp_planes = 2, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .sibling = V4L2_PIX_FMT_NV12M_8L128, }, { .pixfmt = V4L2_PIX_FMT_NV12M_10BE_8L128, - .num_planes = 2, + .mem_planes = 2, + .comp_planes = 2, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .sibling = V4L2_PIX_FMT_NV12_10BE_8L128, + }, + { + .pixfmt = V4L2_PIX_FMT_NV12_10BE_8L128, + .mem_planes = 1, + .comp_planes = 2, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .sibling = V4L2_PIX_FMT_NV12M_10BE_8L128 }, { .pixfmt = V4L2_PIX_FMT_H264, - .num_planes = 1, + .mem_planes = 1, + .comp_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED }, { .pixfmt = V4L2_PIX_FMT_H264_MVC, - .num_planes = 1, + .mem_planes = 1, + .comp_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED }, { .pixfmt = V4L2_PIX_FMT_HEVC, - .num_planes = 1, + .mem_planes = 1, + .comp_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED }, { .pixfmt = V4L2_PIX_FMT_VC1_ANNEX_G, - .num_planes = 1, + .mem_planes = 1, + .comp_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED }, { .pixfmt = V4L2_PIX_FMT_VC1_ANNEX_L, - .num_planes = 1, + .mem_planes = 1, + .comp_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .flags = V4L2_FMT_FLAG_COMPRESSED }, { .pixfmt = V4L2_PIX_FMT_MPEG2, - .num_planes = 1, + .mem_planes = 1, + .comp_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED }, { .pixfmt = V4L2_PIX_FMT_MPEG4, - .num_planes = 1, + .mem_planes = 1, + .comp_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED }, { .pixfmt = V4L2_PIX_FMT_XVID, - .num_planes = 1, + .mem_planes = 1, + .comp_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED }, { .pixfmt = V4L2_PIX_FMT_VP8, - .num_planes = 1, + .mem_planes = 1, + .comp_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED }, { .pixfmt = V4L2_PIX_FMT_H263, - .num_planes = 1, + .mem_planes = 1, + .comp_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED }, {0, 0, 0, 0}, }; @@ -256,23 +285,22 @@ static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) int ret = -EINVAL; vpu_inst_lock(inst); - if (!V4L2_TYPE_IS_OUTPUT(f->type) && vdec->fixed_fmt) { - if (f->index == 0) { - f->pixelformat = inst->cap_format.pixfmt; - f->flags = inst->cap_format.flags; - ret = 0; - } + if (V4L2_TYPE_IS_CAPTURE(f->type) && vdec->fixed_fmt) { + fmt = vpu_get_format(inst, f->type); + if (f->index == 1) + fmt = vpu_helper_find_sibling(inst, f->type, fmt->pixfmt); + if (f->index > 1) + fmt = NULL; } else { fmt = vpu_helper_enum_format(inst, f->type, f->index); - memset(f->reserved, 0, sizeof(f->reserved)); - if (!fmt) - goto exit; - - f->pixelformat = fmt->pixfmt; - f->flags = fmt->flags; - ret = 0; } + if (!fmt) + goto exit; + memset(f->reserved, 0, sizeof(f->reserved)); + f->pixelformat = fmt->pixfmt; + f->flags = fmt->flags; + ret = 0; exit: vpu_inst_unlock(inst); return ret; @@ -286,23 +314,25 @@ static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f) struct vpu_format *cur_fmt; int i; + vpu_inst_lock(inst); cur_fmt = vpu_get_format(inst, f->type); pixmp->pixelformat = cur_fmt->pixfmt; - pixmp->num_planes = cur_fmt->num_planes; + pixmp->num_planes = cur_fmt->mem_planes; pixmp->width = cur_fmt->width; pixmp->height = cur_fmt->height; pixmp->field = cur_fmt->field; pixmp->flags = cur_fmt->flags; for (i = 0; i < pixmp->num_planes; i++) { pixmp->plane_fmt[i].bytesperline = cur_fmt->bytesperline[i]; - pixmp->plane_fmt[i].sizeimage = cur_fmt->sizeimage[i]; + pixmp->plane_fmt[i].sizeimage = vpu_get_fmt_plane_size(cur_fmt, i); } f->fmt.pix_mp.colorspace = vdec->codec_info.color_primaries; f->fmt.pix_mp.xfer_func = vdec->codec_info.transfer_chars; f->fmt.pix_mp.ycbcr_enc = vdec->codec_info.matrix_coeffs; f->fmt.pix_mp.quantization = vdec->codec_info.full_range; + vpu_inst_unlock(inst); return 0; } @@ -311,10 +341,19 @@ static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f) { struct vpu_inst *inst = to_inst(file); struct vdec_t *vdec = inst->priv; - - vpu_try_fmt_common(inst, f); + struct vpu_format fmt; vpu_inst_lock(inst); + if (V4L2_TYPE_IS_CAPTURE(f->type) && vdec->fixed_fmt) { + struct vpu_format *cap_fmt = vpu_get_format(inst, f->type); + + if (!vpu_helper_match_format(inst, cap_fmt->type, cap_fmt->pixfmt, + f->fmt.pix_mp.pixelformat)) + f->fmt.pix_mp.pixelformat = cap_fmt->pixfmt; + } + + vpu_try_fmt_common(inst, f, &fmt); + if (vdec->fixed_fmt) { f->fmt.pix_mp.colorspace = vdec->codec_info.color_primaries; f->fmt.pix_mp.xfer_func = vdec->codec_info.transfer_chars; @@ -334,7 +373,7 @@ static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f) static int vdec_s_fmt_common(struct vpu_inst *inst, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; - const struct vpu_format *fmt; + struct vpu_format fmt; struct vpu_format *cur_fmt; struct vb2_queue *q; struct vdec_t *vdec = inst->priv; @@ -349,36 +388,30 @@ static int vdec_s_fmt_common(struct vpu_inst *inst, struct v4l2_format *f) if (vb2_is_busy(q)) return -EBUSY; - fmt = vpu_try_fmt_common(inst, f); - if (!fmt) + if (vpu_try_fmt_common(inst, f, &fmt)) return -EINVAL; cur_fmt = vpu_get_format(inst, f->type); if (V4L2_TYPE_IS_OUTPUT(f->type) && inst->state != VPU_CODEC_STATE_DEINIT) { - if (cur_fmt->pixfmt != fmt->pixfmt) { + if (cur_fmt->pixfmt != fmt.pixfmt) { vdec->reset_codec = true; vdec->fixed_fmt = false; } } - cur_fmt->pixfmt = fmt->pixfmt; if (V4L2_TYPE_IS_OUTPUT(f->type) || !vdec->fixed_fmt) { - cur_fmt->num_planes = fmt->num_planes; - cur_fmt->flags = fmt->flags; - cur_fmt->width = pixmp->width; - cur_fmt->height = pixmp->height; - for (i = 0; i < fmt->num_planes; i++) { - cur_fmt->sizeimage[i] = pixmp->plane_fmt[i].sizeimage; - cur_fmt->bytesperline[i] = pixmp->plane_fmt[i].bytesperline; - } - if (pixmp->field != V4L2_FIELD_ANY) - cur_fmt->field = pixmp->field; + memcpy(cur_fmt, &fmt, sizeof(*cur_fmt)); } else { - pixmp->num_planes = cur_fmt->num_planes; + if (vpu_helper_match_format(inst, f->type, cur_fmt->pixfmt, pixmp->pixelformat)) { + cur_fmt->pixfmt = fmt.pixfmt; + cur_fmt->mem_planes = fmt.mem_planes; + } + pixmp->pixelformat = cur_fmt->pixfmt; + pixmp->num_planes = cur_fmt->mem_planes; pixmp->width = cur_fmt->width; pixmp->height = cur_fmt->height; for (i = 0; i < pixmp->num_planes; i++) { pixmp->plane_fmt[i].bytesperline = cur_fmt->bytesperline[i]; - pixmp->plane_fmt[i].sizeimage = cur_fmt->sizeimage[i]; + pixmp->plane_fmt[i].sizeimage = vpu_get_fmt_plane_size(cur_fmt, i); } pixmp->field = cur_fmt->field; } @@ -678,9 +711,11 @@ static struct vpu_vb2_buffer *vdec_find_buffer(struct vpu_inst *inst, u32 luma) static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame) { struct vdec_t *vdec = inst->priv; + struct vpu_format *cur_fmt; struct vpu_vb2_buffer *vpu_buf; struct vb2_v4l2_buffer *vbuf; u32 sequence; + int i; if (!frame) return; @@ -699,6 +734,7 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame) return; } + cur_fmt = vpu_get_format(inst, inst->cap_format.type); vbuf = &vpu_buf->m2m_buf.vb; if (vbuf->vb2_buf.index != frame->id) dev_err(inst->dev, "[%d] buffer id(%d, %d) dismatch\n", @@ -707,9 +743,9 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame) if (vpu_get_buffer_state(vbuf) != VPU_BUF_STATE_DECODED) dev_err(inst->dev, "[%d] buffer(%d) ready without decoded\n", inst->id, frame->id); vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY); - vb2_set_plane_payload(&vbuf->vb2_buf, 0, inst->cap_format.sizeimage[0]); - vb2_set_plane_payload(&vbuf->vb2_buf, 1, inst->cap_format.sizeimage[1]); - vbuf->field = inst->cap_format.field; + for (i = 0; i < vbuf->vb2_buf.num_planes; i++) + vb2_set_plane_payload(&vbuf->vb2_buf, i, vpu_get_fmt_plane_size(cur_fmt, i)); + vbuf->field = cur_fmt->field; vbuf->sequence = sequence; dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp); @@ -747,15 +783,20 @@ static void vdec_stop_done(struct vpu_inst *inst) static bool vdec_check_source_change(struct vpu_inst *inst) { struct vdec_t *vdec = inst->priv; - const struct vpu_format *fmt; - int i; + const struct vpu_format *sibling; if (!inst->fh.m2m_ctx) return false; + if (vdec->reset_codec) + return false; + + sibling = vpu_helper_find_sibling(inst, inst->cap_format.type, inst->cap_format.pixfmt); + if (sibling && vdec->codec_info.pixfmt == sibling->pixfmt) + vdec->codec_info.pixfmt = inst->cap_format.pixfmt; + if (!vb2_is_streaming(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx))) return true; - fmt = vpu_helper_find_format(inst, inst->cap_format.type, vdec->codec_info.pixfmt); if (inst->cap_format.pixfmt != vdec->codec_info.pixfmt) return true; if (inst->cap_format.width != vdec->codec_info.decoded_width) @@ -772,14 +813,6 @@ static bool vdec_check_source_change(struct vpu_inst *inst) return true; if (inst->crop.height != vdec->codec_info.height) return true; - if (fmt && inst->cap_format.num_planes != fmt->num_planes) - return true; - for (i = 0; i < inst->cap_format.num_planes; i++) { - if (inst->cap_format.bytesperline[i] != vdec->codec_info.bytesperline[i]) - return true; - if (inst->cap_format.sizeimage[i] != vdec->codec_info.sizeimage[i]) - return true; - } return false; } @@ -787,27 +820,21 @@ static bool vdec_check_source_change(struct vpu_inst *inst) static void vdec_init_fmt(struct vpu_inst *inst) { struct vdec_t *vdec = inst->priv; - const struct vpu_format *fmt; - int i; + struct v4l2_format f; - fmt = vpu_helper_find_format(inst, inst->cap_format.type, vdec->codec_info.pixfmt); - inst->out_format.width = vdec->codec_info.width; - inst->out_format.height = vdec->codec_info.height; - inst->cap_format.width = vdec->codec_info.decoded_width; - inst->cap_format.height = vdec->codec_info.decoded_height; - inst->cap_format.pixfmt = vdec->codec_info.pixfmt; - if (fmt) { - inst->cap_format.num_planes = fmt->num_planes; - inst->cap_format.flags = fmt->flags; - } - for (i = 0; i < inst->cap_format.num_planes; i++) { - inst->cap_format.bytesperline[i] = vdec->codec_info.bytesperline[i]; - inst->cap_format.sizeimage[i] = vdec->codec_info.sizeimage[i]; - } + memset(&f, 0, sizeof(f)); + f.type = inst->cap_format.type; + f.fmt.pix_mp.pixelformat = vdec->codec_info.pixfmt; + f.fmt.pix_mp.width = vdec->codec_info.decoded_width; + f.fmt.pix_mp.height = vdec->codec_info.decoded_height; if (vdec->codec_info.progressive) - inst->cap_format.field = V4L2_FIELD_NONE; + f.fmt.pix_mp.field = V4L2_FIELD_NONE; else - inst->cap_format.field = V4L2_FIELD_SEQ_TB; + f.fmt.pix_mp.field = V4L2_FIELD_SEQ_TB; + vpu_try_fmt_common(inst, &f, &inst->cap_format); + + inst->out_format.width = vdec->codec_info.width; + inst->out_format.height = vdec->codec_info.height; } static void vdec_init_crop(struct vpu_inst *inst) @@ -966,7 +993,10 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb info.tag = vdec->seq_tag; info.luma_addr = vpu_get_vb_phy_addr(&vbuf->vb2_buf, 0); info.luma_size = inst->cap_format.sizeimage[0]; - info.chroma_addr = vpu_get_vb_phy_addr(&vbuf->vb2_buf, 1); + if (vbuf->vb2_buf.num_planes > 1) + info.chroma_addr = vpu_get_vb_phy_addr(&vbuf->vb2_buf, 1); + else + info.chroma_addr = info.luma_addr + info.luma_size; info.chromau_size = inst->cap_format.sizeimage[1]; info.bytesperline = inst->cap_format.bytesperline[0]; ret = vpu_session_alloc_fs(inst, &info); @@ -975,7 +1005,7 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb vpu_buf->tag = info.tag; vpu_buf->luma = info.luma_addr; - vpu_buf->chroma_u = info.chromau_size; + vpu_buf->chroma_u = info.chroma_addr; vpu_buf->chroma_v = 0; vpu_set_buffer_state(vbuf, VPU_BUF_STATE_INUSE); vdec->slots[info.id] = vpu_buf; @@ -1088,7 +1118,8 @@ static void vdec_event_seq_hdr(struct vpu_inst *inst, struct vpu_dec_codec_info vdec->seq_tag = vdec->codec_info.tag; if (vdec->is_source_changed) { vdec_update_state(inst, VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE, 0); - vpu_notify_source_change(inst); + vdec->source_change++; + vdec_handle_resolution_change(inst); vdec->is_source_changed = false; } } @@ -1335,6 +1366,8 @@ static void vdec_abort(struct vpu_inst *inst) vdec->decoded_frame_count, vdec->display_frame_count, vdec->sequence); + if (!vdec->seq_hdr_found) + vdec->reset_codec = true; vdec->params.end_flag = 0; vdec->drain = 0; vdec->params.frame_count = 0; @@ -1342,6 +1375,7 @@ static void vdec_abort(struct vpu_inst *inst) vdec->display_frame_count = 0; vdec->sequence = 0; vdec->aborting = false; + inst->extra_size = 0; } static void vdec_stop(struct vpu_inst *inst, bool free) @@ -1464,8 +1498,7 @@ static int vdec_start_session(struct vpu_inst *inst, u32 type) } if (V4L2_TYPE_IS_OUTPUT(type)) { - if (inst->state == VPU_CODEC_STATE_SEEK) - vdec_update_state(inst, vdec->state, 1); + vdec_update_state(inst, vdec->state, 1); vdec->eos_received = 0; vpu_process_output_buffer(inst); } else { @@ -1629,6 +1662,7 @@ static int vdec_open(struct file *file) return ret; vdec->fixed_fmt = false; + vdec->state = VPU_CODEC_STATE_ACTIVE; inst->min_buffer_cap = VDEC_MIN_BUFFER_CAP; inst->min_buffer_out = VDEC_MIN_BUFFER_OUT; vdec_init(file); |