summaryrefslogtreecommitdiff
path: root/drivers/media/platform/amphion/vdec.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/amphion/vdec.c')
-rw-r--r--drivers/media/platform/amphion/vdec.c218
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);