static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx) { unsigned int dpbsize = 0; int ret; if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->last_decoded_picinfo)) { mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", ctx->id); return -EINVAL; } if (ctx->last_decoded_picinfo.pic_w == 0 || ctx->last_decoded_picinfo.pic_h == 0 || ctx->last_decoded_picinfo.buf_w == 0 || ctx->last_decoded_picinfo.buf_h == 0) { mtk_v4l2_err("Cannot get correct pic info"); return -EINVAL; } if ((ctx->last_decoded_picinfo.pic_w == ctx->picinfo.pic_w) || (ctx->last_decoded_picinfo.pic_h == ctx->picinfo.pic_h)) return 0; mtk_v4l2_debug(1, "[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)", ctx->id, ctx->last_decoded_picinfo.pic_w, ctx->last_decoded_picinfo.pic_h, ctx->picinfo.pic_w, ctx->picinfo.pic_h, ctx->last_decoded_picinfo.buf_w, ctx->last_decoded_picinfo.buf_h); ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); if (dpbsize == 0) mtk_v4l2_err("Incorrect dpb size, ret=%d", ret); ctx->dpb_size = dpbsize; return ret; }
static int vidioc_vdec_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); struct mtk_q_data *q_data; if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; q_data = &ctx->q_data[MTK_Q_DATA_DST]; switch (s->target) { case V4L2_SEL_TGT_COMPOSE_DEFAULT: s->r.left = 0; s->r.top = 0; s->r.width = ctx->picinfo.pic_w; s->r.height = ctx->picinfo.pic_h; break; case V4L2_SEL_TGT_COMPOSE_BOUNDS: s->r.left = 0; s->r.top = 0; s->r.width = ctx->picinfo.buf_w; s->r.height = ctx->picinfo.buf_h; break; case V4L2_SEL_TGT_COMPOSE: if (vdec_if_get_param(ctx, GET_PARAM_CROP_INFO, &(s->r))) { /* set to default value if header info not ready yet*/ s->r.left = 0; s->r.top = 0; s->r.width = q_data->visible_width; s->r.height = q_data->visible_height; } break; default: return -EINVAL; } if (ctx->state < MTK_STATE_HEADER) { /* set to default value if header info not ready yet*/ s->r.left = 0; s->r.top = 0; s->r.width = q_data->visible_width; s->r.height = q_data->visible_height; return 0; } return 0; }
/* * This function tries to clean all display buffers, the buffers will return * in display order. * Note the buffers returned from codec driver may still be in driver's * reference list. */ static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx) { struct vdec_fb *disp_frame_buffer = NULL; struct mtk_video_dec_buf *dstbuf; mtk_v4l2_debug(3, "[%d]", ctx->id); if (vdec_if_get_param(ctx, GET_PARAM_DISP_FRAME_BUFFER, &disp_frame_buffer)) { mtk_v4l2_err("[%d]Cannot get param : GET_PARAM_DISP_FRAME_BUFFER", ctx->id); return NULL; } if (disp_frame_buffer == NULL) { mtk_v4l2_debug(3, "No display frame buffer"); return NULL; } dstbuf = container_of(disp_frame_buffer, struct mtk_video_dec_buf, frame_buffer); mutex_lock(&ctx->lock); if (dstbuf->used) { vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, ctx->picinfo.y_bs_sz); vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1, ctx->picinfo.c_bs_sz); dstbuf->ready_to_display = true; mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to done_list %d", ctx->id, disp_frame_buffer->status, dstbuf->vb.vb2_buf.index, dstbuf->queued_in_vb2); v4l2_m2m_buf_done(&dstbuf->vb, VB2_BUF_STATE_DONE); ctx->decoded_frame_cnt++; } mutex_unlock(&ctx->lock); return &dstbuf->vb.vb2_buf; }
/* * This function tries to clean all capture buffers that are not used as * reference buffers by codec driver any more * In this case, we need re-queue buffer to vb2 buffer if user space * already returns this buffer to v4l2 or this buffer is just the output of * previous sps/pps/resolution change decode, or do nothing if user * space still owns this buffer */ static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx) { struct mtk_video_dec_buf *dstbuf; struct vdec_fb *free_frame_buffer = NULL; if (vdec_if_get_param(ctx, GET_PARAM_FREE_FRAME_BUFFER, &free_frame_buffer)) { mtk_v4l2_err("[%d] Error!! Cannot get param", ctx->id); return NULL; } if (free_frame_buffer == NULL) { mtk_v4l2_debug(3, " No free frame buffer"); return NULL; } mtk_v4l2_debug(3, "[%d] tmp_frame_addr = 0x%p", ctx->id, free_frame_buffer); dstbuf = container_of(free_frame_buffer, struct mtk_video_dec_buf, frame_buffer); mutex_lock(&ctx->lock); if (dstbuf->used) { if ((dstbuf->queued_in_vb2) && (dstbuf->queued_in_v4l2) && (free_frame_buffer->status == FB_ST_FREE)) { /* * After decode sps/pps or non-display buffer, we don't * need to return capture buffer to user space, but * just re-queue this capture buffer to vb2 queue. * This reduce overheads that dq/q unused capture * buffer. In this case, queued_in_vb2 = true. */ mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to rdy_queue %d", ctx->id, free_frame_buffer->status, dstbuf->vb.vb2_buf.index, dstbuf->queued_in_vb2); v4l2_m2m_buf_queue(ctx->m2m_ctx, &dstbuf->vb); } else if ((dstbuf->queued_in_vb2 == false) && (dstbuf->queued_in_v4l2 == true)) { /* * If buffer in v4l2 driver but not in vb2 queue yet, * and we get this buffer from free_list, it means * that codec driver do not use this buffer as * reference buffer anymore. We should q buffer to vb2 * queue, so later work thread could get this buffer * for decode. In this case, queued_in_vb2 = false * means this buffer is not from previous decode * output. */ mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to rdy_queue", ctx->id, free_frame_buffer->status, dstbuf->vb.vb2_buf.index); v4l2_m2m_buf_queue(ctx->m2m_ctx, &dstbuf->vb); dstbuf->queued_in_vb2 = true; } else { /* * Codec driver do not need to reference this capture * buffer and this buffer is not in v4l2 driver. * Then we don't need to do any thing, just add log when * we need to debug buffer flow. * When this buffer q from user space, it could * directly q to vb2 buffer */ mtk_v4l2_debug(3, "[%d]status=%x err queue id=%d %d %d", ctx->id, free_frame_buffer->status, dstbuf->vb.vb2_buf.index, dstbuf->queued_in_vb2, dstbuf->queued_in_v4l2); } dstbuf->used = false; } mutex_unlock(&ctx->lock); return &dstbuf->vb.vb2_buf; }