author | Nanxin Qin <nanxin.qin@amlogic.com> | 2020-05-14 14:47:19 (GMT) |
---|---|---|
committer | Nanxin Qin <nanxin.qin@amlogic.com> | 2020-06-29 09:52:25 (GMT) |
commit | 87e53d07cebb868c4973843d0a374ec94d990e4f (patch) | |
tree | edd2c95b0ba7fed22aa68f0dcd7cfab36eaf3363 | |
parent | ff87bfb40c0c50fcc37a1c9932c3a09fac609ce1 (diff) | |
download | media_modules-87e53d07cebb868c4973843d0a374ec94d990e4f.zip media_modules-87e53d07cebb868c4973843d0a374ec94d990e4f.tar.gz media_modules-87e53d07cebb868c4973843d0a374ec94d990e4f.tar.bz2 |
v4l: porting v4l codec from branch amlogic-4.9-dev. [1/1]
PD#SWPL-24949
Problem:
v4l2 need support for kernel 5.4
Solution:
porting v4l codec from branch amlogic-4.9-dev.
commit base: 5f8edcbf
Verify:
u212
Change-Id: Ia8bf3087e85cd92ae1fb7ee1ecc647b369313a19
Signed-off-by: Nanxin Qin <nanxin.qin@amlogic.com>
35 files changed, 2202 insertions, 1695 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 1af0482..b3ad95f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -2,4 +2,4 @@ obj-y += common/ obj-y += frame_provider/ obj-y += frame_sink/ obj-y += stream_input/ -#obj-y += amvdec_ports/ +obj-$(CONFIG_AMLOGIC_MEDIA_V4L_DEC) += amvdec_ports/ diff --git a/drivers/amvdec_ports/aml_vcodec_adapt.c b/drivers/amvdec_ports/aml_vcodec_adapt.c index 7bb8eea..a166c9c 100644 --- a/drivers/amvdec_ports/aml_vcodec_adapt.c +++ b/drivers/amvdec_ports/aml_vcodec_adapt.c @@ -52,8 +52,6 @@ #define PTS_OUTSIDE (1) #define SYNC_OUTSIDE (2) -#define USE_V4L_PORTS (0x80) -#define SCATTER_MEM (0x100) //#define DATA_DEBUG @@ -114,9 +112,8 @@ extern bool aml_set_vfm_enable, aml_set_vdec_type_enable; static void set_default_params(struct aml_vdec_adapt *vdec) { - ulong sync_mode = (PTS_OUTSIDE | SYNC_OUTSIDE | USE_V4L_PORTS); + ulong sync_mode = (PTS_OUTSIDE | SYNC_OUTSIDE); - sync_mode |= vdec->ctx->scatter_mem_enable ? SCATTER_MEM : 0; vdec->dec_prop.param = (void *)sync_mode; vdec->dec_prop.format = vdec->format; vdec->dec_prop.width = 1920; @@ -465,7 +462,7 @@ static void set_vdec_properity(struct vdec_s *vdec, { vdec->sys_info = &ada_ctx->dec_prop; vdec->port = &ada_ctx->port; - vdec->format = ada_ctx->video_type; + vdec->format = ada_ctx->format; vdec->sys_info_store = ada_ctx->dec_prop; vdec->vf_receiver_name = ada_ctx->recv_name; @@ -475,33 +472,25 @@ static void set_vdec_properity(struct vdec_s *vdec, /* set video format, sys info and vfm map.*/ vdec->port->vformat = vdec->format; vdec->port->type |= PORT_TYPE_VIDEO; - vdec->port_flag |= PORT_FLAG_VFORMAT; + vdec->port_flag |= (vdec->port->flag | PORT_FLAG_VFORMAT); if (vdec->slave) { vdec->slave->format = ada_ctx->dec_prop.format; vdec->slave->port_flag |= PORT_FLAG_VFORMAT; } - if (vdec->port->type & PORT_FLAG_DRM) { - vdec->type = VDEC_TYPE_STREAM_PARSER; - vdec->port->type |= PORT_TYPE_ES; - vdec->frame_base_video_path = FRAME_BASE_PATH_V4L_VIDEO; - } else { - vdec->type = VDEC_TYPE_FRAME_BLOCK; - vdec->port->type |= PORT_TYPE_FRAME; - vdec->frame_base_video_path = FRAME_BASE_PATH_V4L_OSD; - } + vdec->type = VDEC_TYPE_FRAME_BLOCK; + vdec->port->type |= PORT_TYPE_FRAME; + vdec->frame_base_video_path = FRAME_BASE_PATH_V4L_OSD; if (aml_set_vdec_type_enable) { if (aml_set_vdec_type == VDEC_TYPE_STREAM_PARSER) { vdec->type = VDEC_TYPE_STREAM_PARSER; vdec->port->type &= ~PORT_TYPE_FRAME; vdec->port->type |= PORT_TYPE_ES; - ada_ctx->ctx->is_stream_mode = true; } else if (aml_set_vdec_type == VDEC_TYPE_FRAME_BLOCK) { vdec->type = VDEC_TYPE_FRAME_BLOCK; vdec->port->type &= ~PORT_TYPE_ES; vdec->port->type |= PORT_TYPE_FRAME; - ada_ctx->ctx->is_stream_mode = false; } } @@ -700,6 +689,30 @@ int vdec_vframe_write(struct aml_vdec_adapt *ada_ctx, return ret; } +int vdec_vframe_write_with_dma(struct aml_vdec_adapt *ada_ctx, + ulong addr, u32 count, u64 timestamp, u32 handle) +{ + int ret = -1; + struct vdec_s *vdec = ada_ctx->vdec; + + /* set timestamp */ + vdec_set_timestamp(vdec, timestamp); + + ret = vdec_write_vframe_with_dma(vdec, addr, count, handle); + + if (slow_input) { + v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO, + "slow_input: frame codec write size %d\n", ret); + msleep(30); + } + + v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_INPUT, + "write frames, vbuf: %lx, size: %u, ret: %d\n", + addr, count, ret); + + return ret; +} + void aml_decoder_flush(struct aml_vdec_adapt *ada_ctx) { struct vdec_s *vdec = ada_ctx->vdec; @@ -714,12 +727,21 @@ int aml_codec_reset(struct aml_vdec_adapt *ada_ctx, int *mode) int ret = 0; if (vdec) { - vdec_set_eos(vdec, false); - + if (!ada_ctx->ctx->q_data[AML_Q_DATA_SRC].resolution_changed) + vdec_set_eos(vdec, false); if (*mode == V4L_RESET_MODE_NORMAL && - vdec->input.have_frame_num == 0) + vdec->input.have_frame_num == 0) { + v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO, + "no input reset mode: %d\n", *mode); *mode = V4L_RESET_MODE_LIGHT; - + } + if (ada_ctx->ctx->param_sets_from_ucode && + *mode == V4L_RESET_MODE_NORMAL && + ada_ctx->ctx->q_data[AML_Q_DATA_SRC].resolution_changed == true) { + v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO, + "resolution_changed reset mode: %d\n", *mode); + *mode = V4L_RESET_MODE_LIGHT; + } v4l_dbg(ada_ctx->ctx, V4L_DEBUG_CODEC_PRINFO, "reset mode: %d\n", *mode); @@ -764,3 +786,8 @@ void v4l2_config_vdec_parm(struct aml_vdec_adapt *ada_ctx, u8 *data, u32 len) memcpy(vdec->config, data, vdec->config_len); } +u32 aml_recycle_buffer(struct aml_vdec_adapt *adaptor) +{ + return vdec_input_get_freed_handle(adaptor->vdec); +} + diff --git a/drivers/amvdec_ports/aml_vcodec_adapt.h b/drivers/amvdec_ports/aml_vcodec_adapt.h index 1f8afdd..c96d0fb 100644 --- a/drivers/amvdec_ports/aml_vcodec_adapt.h +++ b/drivers/amvdec_ports/aml_vcodec_adapt.h @@ -27,6 +27,7 @@ struct aml_vdec_adapt { enum vformat_e format; + enum VIDEO_DEC_TYPE dec_type; void *vsi; int32_t failure; uint32_t inst_addr; @@ -39,7 +40,6 @@ struct aml_vdec_adapt { struct stream_port_s port; struct dec_sysinfo dec_prop; struct v4l2_config_parm config; - int video_type; char *recv_name; int vfm_path; }; @@ -54,6 +54,9 @@ int vdec_vbuf_write(struct aml_vdec_adapt *ada_ctx, int vdec_vframe_write(struct aml_vdec_adapt *ada_ctx, const char *buf, unsigned int count, u64 timestamp); +int vdec_vframe_write_with_dma(struct aml_vdec_adapt *ada_ctx, + ulong addr, u32 count, u64 timestamp, u32 handle); + bool vdec_input_full(struct aml_vdec_adapt *ada_ctx); void aml_decoder_flush(struct aml_vdec_adapt *ada_ctx); @@ -66,5 +69,7 @@ bool is_input_ready(struct aml_vdec_adapt *ada_ctx); int vdec_frame_number(struct aml_vdec_adapt *ada_ctx); +u32 aml_recycle_buffer(struct aml_vdec_adapt *adaptor); + #endif /* VDEC_ADAPT_H */ diff --git a/drivers/amvdec_ports/aml_vcodec_dec.c b/drivers/amvdec_ports/aml_vcodec_dec.c index 880f3a5..2ffab91 100644 --- a/drivers/amvdec_ports/aml_vcodec_dec.c +++ b/drivers/amvdec_ports/aml_vcodec_dec.c @@ -29,6 +29,8 @@ #include <linux/delay.h> #include <linux/atomic.h> #include <linux/crc32.h> +#include <linux/sched.h> +#include <uapi/linux/sched/types.h> #include "aml_vcodec_adapt.h" #include <linux/spinlock.h> @@ -48,7 +50,7 @@ #define DFT_CFG_HEIGHT AML_VDEC_MIN_H #define V4L2_CID_USER_AMLOGIC_BASE (V4L2_CID_USER_BASE + 0x1100) -#define AML_V4L2_SET_DECMODE (V4L2_CID_USER_AMLOGIC_BASE + 0) +#define AML_V4L2_SET_DRMMODE (V4L2_CID_USER_AMLOGIC_BASE + 0) #define WORK_ITEMS_MAX (32) @@ -121,38 +123,58 @@ static struct aml_video_fmt aml_video_formats[] = { static const struct aml_codec_framesizes aml_vdec_framesizes[] = { { .fourcc = V4L2_PIX_FMT_H264, - .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 8, - AML_VDEC_MIN_H, AML_VDEC_MAX_H, 8 }, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, }, { .fourcc = V4L2_PIX_FMT_HEVC, - .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 8, - AML_VDEC_MIN_H, AML_VDEC_MAX_H, 8 }, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, }, { .fourcc = V4L2_PIX_FMT_VP9, - .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 8, - AML_VDEC_MIN_H, AML_VDEC_MAX_H, 8 }, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, }, { .fourcc = V4L2_PIX_FMT_MPEG1, - .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 8, - AML_VDEC_MIN_H, AML_VDEC_MAX_H, 8 }, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, }, { .fourcc = V4L2_PIX_FMT_MPEG2, - .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 8, - AML_VDEC_MIN_H, AML_VDEC_MAX_H, 8 }, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, }, { .fourcc = V4L2_PIX_FMT_MPEG4, - .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 8, - AML_VDEC_MIN_H, AML_VDEC_MAX_H, 8 }, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, }, { .fourcc = V4L2_PIX_FMT_MJPEG, - .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 8, - AML_VDEC_MIN_H, AML_VDEC_MAX_H, 8 }, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { + .fourcc = V4L2_PIX_FMT_NV21, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { + .fourcc = V4L2_PIX_FMT_NV21M, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { + .fourcc = V4L2_PIX_FMT_NV12, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .stepwise = { AML_VDEC_MIN_W, AML_VDEC_MAX_W, 2, + AML_VDEC_MIN_H, AML_VDEC_MAX_H, 2}, }, }; @@ -206,7 +228,9 @@ void aml_vdec_dispatch_event(struct aml_vcodec_ctx *ctx, u32 changes) { struct v4l2_event event = {0}; - if (ctx->receive_cmd_stop) { + if (ctx->receive_cmd_stop && + changes != V4L2_EVENT_SRC_CH_RESOLUTION && + changes != V4L2_EVENT_SEND_EOS) { ctx->state = AML_STATE_ABORT; ATRACE_COUNTER("v4l2_state", ctx->state); changes = V4L2_EVENT_REQUEST_EXIT; @@ -222,6 +246,9 @@ void aml_vdec_dispatch_event(struct aml_vcodec_ctx *ctx, u32 changes) event.type = V4L2_EVENT_SOURCE_CHANGE; event.u.src_change.changes = changes; break; + case V4L2_EVENT_SEND_EOS: + event.type = V4L2_EVENT_EOS; + break; default: v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "unsupport dispatch event %x\n", changes); @@ -365,28 +392,34 @@ int get_fb_from_queue(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer **out_ return -1; } - dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + //fixme + /*dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); if (!dst_buf) { aml_vcodec_ctx_unlock(ctx, flags); return -1; + }*/ + + dst_vb2_v4l2 = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + if (!dst_vb2_v4l2) { + aml_vcodec_ctx_unlock(ctx, flags); + return -1; } + dst_buf = (struct vb2_buffer *)dst_vb2_v4l2; + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, "vbuf idx: %d, state: %d, ready: %d\n", dst_buf->index, dst_buf->state, v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)); - dst_vb2_v4l2 = container_of(dst_buf, struct vb2_v4l2_buffer, vb2_buf); + //fixme + //dst_vb2_v4l2 = container_of(dst_buf, struct vb2_v4l2_buffer, vb2_buf); dst_buf_info = container_of(dst_vb2_v4l2, struct aml_video_dec_buf, vb); - if (ctx->scatter_mem_enable) { - pfb = &dst_buf_info->frame_buffer; - pfb->mem_type = VDEC_SCATTER_MEMORY_TYPE; - pfb->status = FB_ST_NORMAL; - } else if (dst_buf->num_planes == 1) { + if (dst_buf->num_planes == 1) { pfb = &dst_buf_info->frame_buffer; pfb->m.mem[0].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - pfb->m.mem[0].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[0].dma_addr); + pfb->m.mem[0].addr = pfb->m.mem[0].dma_addr; pfb->m.mem[0].size = ctx->picinfo.y_len_sz + ctx->picinfo.c_len_sz; pfb->m.mem[0].offset = ctx->picinfo.y_len_sz; pfb->num_planes = dst_buf->num_planes; @@ -398,12 +431,12 @@ int get_fb_from_queue(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer **out_ } else if (dst_buf->num_planes == 2) { pfb = &dst_buf_info->frame_buffer; pfb->m.mem[0].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - pfb->m.mem[0].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[0].dma_addr); + pfb->m.mem[0].addr = pfb->m.mem[0].dma_addr; pfb->m.mem[0].size = ctx->picinfo.y_len_sz; pfb->m.mem[0].offset = 0; pfb->m.mem[1].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 1); - pfb->m.mem[1].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[1].dma_addr); + pfb->m.mem[1].addr = pfb->m.mem[1].dma_addr; pfb->m.mem[1].size = ctx->picinfo.c_len_sz; pfb->m.mem[1].offset = ctx->picinfo.c_len_sz >> 1; pfb->num_planes = dst_buf->num_planes; @@ -416,17 +449,17 @@ int get_fb_from_queue(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer **out_ } else { pfb = &dst_buf_info->frame_buffer; pfb->m.mem[0].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - pfb->m.mem[0].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[0].dma_addr); + pfb->m.mem[0].addr = pfb->m.mem[0].dma_addr; pfb->m.mem[0].size = ctx->picinfo.y_len_sz; pfb->m.mem[0].offset = 0; pfb->m.mem[1].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 1); - pfb->m.mem[1].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[2].dma_addr); + pfb->m.mem[1].addr = pfb->m.mem[1].dma_addr; pfb->m.mem[1].size = ctx->picinfo.c_len_sz >> 1; pfb->m.mem[1].offset = 0; pfb->m.mem[2].dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 2); - pfb->m.mem[2].addr = dma_to_phys(v4l_get_dev_from_codec_mm(), pfb->m.mem[3].dma_addr); + pfb->m.mem[2].addr = pfb->m.mem[2].dma_addr; pfb->m.mem[2].size = ctx->picinfo.c_len_sz >> 1; pfb->m.mem[2].offset = 0; pfb->num_planes = dst_buf->num_planes; @@ -530,7 +563,6 @@ void trans_vframe_to_user(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer *f } if (vf->flag & VFRAME_FLAG_EMPTY_FRAME_V4L) { - dstbuf->lastframe = true; dstbuf->vb.flags = V4L2_BUF_FLAG_LAST; if (dstbuf->frame_buffer.num_planes == 1) { vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, 0); @@ -551,6 +583,25 @@ void trans_vframe_to_user(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer *f dstbuf->vb.vb2_buf.index, dstbuf->vb.vb2_buf.state); + if (vf->flag & VFRAME_FLAG_EMPTY_FRAME_V4L) { + if (ctx->q_data[AML_Q_DATA_SRC].resolution_changed) { + /* make the run to stanby until new buffs to enque. */ + ctx->v4l_codec_dpb_ready = false; + ctx->reset_flag = V4L_RESET_MODE_LIGHT; + + /* + * After all buffers containing decoded frames from + * before the resolution change point ready to be + * dequeued on the CAPTURE queue, the driver sends a + * V4L2_EVENT_SOURCE_CHANGE event for source change + * type V4L2_EVENT_SRC_CH_RESOLUTION, also the upper + * layer will get new information from cts->picinfo. + */ + aml_vdec_dispatch_event(ctx, V4L2_EVENT_SRC_CH_RESOLUTION); + } else + aml_vdec_dispatch_event(ctx, V4L2_EVENT_SEND_EOS); + } + if (dstbuf->vb.vb2_buf.state == VB2_BUF_STATE_ACTIVE) { /* binding vframe handle. */ vf->flag |= VFRAME_FLAG_VIDEO_LINEAR; @@ -572,24 +623,6 @@ void trans_vframe_to_user(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer *f } mutex_unlock(&ctx->state_lock); - if (dstbuf->lastframe && - ctx->q_data[AML_Q_DATA_SRC].resolution_changed) { - - /* make the run to stanby until new buffs to enque. */ - ctx->v4l_codec_dpb_ready = false; - ctx->reset_flag = V4L_RESET_MODE_LIGHT; - - /* - * After all buffers containing decoded frames from - * before the resolution change point ready to be - * dequeued on the CAPTURE queue, the driver sends a - * V4L2_EVENT_SOURCE_CHANGE event for source change - * type V4L2_EVENT_SRC_CH_RESOLUTION, also the upper - * layer will get new information from cts->picinfo. - */ - aml_vdec_dispatch_event(ctx, V4L2_EVENT_SRC_CH_RESOLUTION); - } - ctx->decoded_frame_cnt++; } @@ -648,8 +681,6 @@ static int is_vdec_ready(struct aml_vcodec_ctx *ctx) if (ctx->state == AML_STATE_PROBE) { ctx->state = AML_STATE_READY; ATRACE_COUNTER("v4l2_state", ctx->state); - ctx->v4l_codec_ready = true; - wake_up_interruptible(&ctx->wq); v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, "vcodec state (AML_STATE_READY)\n"); } @@ -706,6 +737,30 @@ static void aml_wait_dpb_ready(struct aml_vcodec_ctx *ctx) } } +static void aml_recycle_dma_buffers(struct aml_vcodec_ctx *ctx) +{ + struct vb2_v4l2_buffer *vb; + struct aml_video_dec_buf *buf; + struct vb2_queue *q; + u32 handle; + + q = v4l2_m2m_get_vq(ctx->m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT); + + while ((handle = aml_recycle_buffer(ctx->ada_ctx))) { + int index = handle & 0xf; + + vb = to_vb2_v4l2_buffer(q->bufs[index]); + buf = container_of(vb, struct aml_video_dec_buf, vb); + v4l2_m2m_buf_done(vb, buf->error ? VB2_BUF_STATE_ERROR : + VB2_BUF_STATE_DONE); + + v4l_dbg(ctx, V4L_DEBUG_CODEC_INPUT, + "recycle buff idx: %d, vbuf: %lx\n", index, + (ulong)vb2_dma_contig_plane_dma_addr(q->bufs[index], 0)); + } +} + static void aml_vdec_worker(struct work_struct *work) { struct aml_vcodec_ctx *ctx = @@ -730,18 +785,29 @@ static void aml_vdec_worker(struct work_struct *work) goto out; } - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + //fixme + /*src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); if (src_buf == NULL) { v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "src_buf empty.\n"); goto out; + }*/ + + src_vb2_v4l2 = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + if (src_vb2_v4l2 == NULL) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, + "src_buf empty.\n"); + goto out; } + src_buf = (struct vb2_buffer *)src_vb2_v4l2; + /*this case for google, but some frames are droped on ffmpeg, so disabled temp.*/ if (0 && !is_enough_work_items(ctx)) goto out; - src_vb2_v4l2 = container_of(src_buf, struct vb2_v4l2_buffer, vb2_buf); + //fixme + //src_vb2_v4l2 = container_of(src_buf, struct vb2_v4l2_buffer, vb2_buf); src_buf_info = container_of(src_vb2_v4l2, struct aml_video_dec_buf, vb); if (src_buf_info->lastframe) { @@ -767,7 +833,7 @@ static void aml_vdec_worker(struct work_struct *work) } mutex_unlock(&ctx->state_lock); - src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); /* sets eos data for vdec input. */ @@ -776,11 +842,13 @@ static void aml_vdec_worker(struct work_struct *work) goto out; } - buf.vaddr = vb2_plane_vaddr(src_buf, 0); - buf.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + buf.index = src_buf->index; + buf.vaddr = vb2_plane_vaddr(src_buf, 0); + buf.addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + buf.size = src_buf->planes[0].bytesused; + buf.model = src_buf->memory; - buf.size = src_buf->planes[0].bytesused; - if (!buf.vaddr) { + if (!buf.vaddr && !buf.addr) { v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "id=%d src_addr is NULL.\n", src_buf->index); @@ -803,12 +871,21 @@ static void aml_vdec_worker(struct work_struct *work) * we only return src buffer with VB2_BUF_STATE_DONE * when decode success without resolution change. */ - src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_DONE); + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + + if (ctx->is_drm_mode && buf.model == VB2_MEMORY_DMABUF) + aml_recycle_dma_buffers(ctx); + else + v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_DONE); } else if (ret && ret != -EAGAIN) { src_buf_info->error = (ret == -EIO ? true : false); - src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_ERROR); + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + + if (ctx->is_drm_mode && buf.model == VB2_MEMORY_DMABUF) + aml_recycle_dma_buffers(ctx); + else + v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_ERROR); + v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "error processing src data. %d.\n", ret); } else if (res_chg) { @@ -833,7 +910,9 @@ static void aml_vdec_worker(struct work_struct *work) mutex_unlock(&ctx->state_lock); ctx->q_data[AML_Q_DATA_SRC].resolution_changed = true; - v4l2_m2m_job_pause(dev->m2m_dev_dec, ctx->m2m_ctx); + while (ctx->m2m_ctx->job_flags & TRANS_RUNNING) { + v4l2_m2m_job_pause(dev->m2m_dev_dec, ctx->m2m_ctx); + } aml_vdec_flush_decoder(ctx); @@ -886,18 +965,22 @@ void wait_vcodec_ending(struct aml_vcodec_ctx *ctx) { struct aml_vcodec_dev *dev = ctx->dev; - /* pause inject output data to vdec. */ - v4l2_m2m_job_pause(dev->m2m_dev_dec, ctx->m2m_ctx); + /* disable queue output item to worker. */ + ctx->output_thread_ready = false; - /* flush worker. */ + /* flush output buffer worker. */ flush_workqueue(dev->decode_workqueue); - ctx->v4l_codec_ready = false; - ctx->v4l_codec_dpb_ready = false; - - /* stop decoder. */ + /* clean output cache and decoder status . */ if (ctx->state > AML_STATE_INIT) aml_vdec_reset(ctx); + + /* pause the job and clean trans status. */ + while (ctx->m2m_ctx->job_flags & TRANS_RUNNING) { + v4l2_m2m_job_pause(ctx->dev->m2m_dev_dec, ctx->m2m_ctx); + } + + ctx->v4l_codec_dpb_ready = false; } void try_to_capture(struct aml_vcodec_ctx *ctx) @@ -954,6 +1037,7 @@ void aml_thread_notify(struct aml_vcodec_ctx *ctx, { struct aml_vdec_thread *thread = NULL; + mutex_lock(&ctx->lock); list_for_each_entry(thread, &ctx->vdec_thread_list, node) { if (thread->task == NULL) continue; @@ -961,6 +1045,7 @@ void aml_thread_notify(struct aml_vcodec_ctx *ctx, if (thread->type == type) up(&thread->sem); } + mutex_unlock(&ctx->lock); } EXPORT_SYMBOL_GPL(aml_thread_notify); @@ -1006,7 +1091,10 @@ void aml_thread_stop(struct aml_vcodec_ctx *ctx) while (!list_empty(&ctx->vdec_thread_list)) { thread = list_entry(ctx->vdec_thread_list.next, struct aml_vdec_thread, node); + mutex_lock(&ctx->lock); list_del(&thread->node); + mutex_unlock(&ctx->lock); + thread->stop = true; up(&thread->sem); kthread_stop(thread->task); @@ -1121,7 +1209,6 @@ static int vidioc_decoder_streamon(struct file *file, void *priv, (ctx->reset_flag == V4L_RESET_MODE_LIGHT)) { ctx->state = AML_STATE_RESET; ATRACE_COUNTER("v4l2_state", ctx->state); - ctx->v4l_codec_ready = false; ctx->v4l_codec_dpb_ready = false; v4l_dbg(ctx, V4L_DEBUG_CODEC_STATE, @@ -1171,7 +1258,8 @@ static int vidioc_decoder_reqbufs(struct file *file, void *priv, vb2_queue_release(q); v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, - "%s, type: %d\n", __func__, q->type); + "%s, type: %d, count: %d\n", + __func__, q->type, rb->count); if (!V4L2_TYPE_IS_OUTPUT(rb->type)) { /* driver needs match v4l buffer number with dpb_size */ @@ -1179,7 +1267,13 @@ static int vidioc_decoder_reqbufs(struct file *file, void *priv, v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "reqbufs (st:%d) %d -> %d\n", ctx->state, rb->count, ctx->dpb_size); - rb->count = ctx->dpb_size; + //rb->count = ctx->dpb_size; + } + } else { + if (rb->memory == VB2_MEMORY_DMABUF) { + v4l_dbg(ctx, V4L_DEBUG_CODEC_INPUT, + "%s, output_dma_mode set", __func__); + ctx->output_dma_mode = true; } } @@ -1225,6 +1319,7 @@ void aml_vcodec_dec_release(struct aml_vcodec_ctx *ctx) void aml_vcodec_dec_set_default_params(struct aml_vcodec_ctx *ctx) { struct aml_q_data *q_data; + u32 width, height; ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex; ctx->fh.m2m_ctx = ctx->m2m_ctx; @@ -1254,14 +1349,18 @@ void aml_vcodec_dec_set_default_params(struct aml_vcodec_ctx *ctx) q_data->coded_height = DFT_CFG_HEIGHT; q_data->fmt = &aml_video_formats[CAP_FMT_IDX]; q_data->field = V4L2_FIELD_NONE; + width = q_data->coded_width; + height = q_data->coded_height; - v4l_bound_align_image(&q_data->coded_width, + v4l_bound_align_image(&width, AML_VDEC_MIN_W, AML_VDEC_MAX_W, 4, - &q_data->coded_height, + &height, AML_VDEC_MIN_H, AML_VDEC_MAX_H, 5, 6); + q_data->coded_width = width; + q_data->coded_height = height; q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height; q_data->bytesperline[0] = q_data->coded_width; q_data->sizeimage[1] = q_data->sizeimage[0] / 2; @@ -1324,7 +1423,7 @@ static int vidioc_vdec_dqbuf(struct file *file, void *priv, ATRACE_COUNTER("v4l2_dqin_eagain", 0); else ATRACE_COUNTER("v4l2_dqin_ok", 0); - } else if (!V4L2_TYPE_IS_OUTPUT(buf->type)) { + } else { if (ret == -EAGAIN) ATRACE_COUNTER("v4l2_dqout_eagain", 0); } @@ -1335,7 +1434,9 @@ static int vidioc_vdec_dqbuf(struct file *file, void *priv, struct aml_video_dec_buf *aml_buf = NULL; struct file *file = NULL; - mutex_lock(&ctx->lock); + if (ctx->is_drm_mode && ctx->output_dma_mode) + aml_recycle_dma_buffers(ctx); + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, buf->type); vb2_v4l2 = to_vb2_v4l2_buffer(vq->bufs[buf->index]); aml_buf = container_of(vb2_v4l2, struct aml_video_dec_buf, vb); @@ -1354,7 +1455,6 @@ static int vidioc_vdec_dqbuf(struct file *file, void *priv, (ulong) v4l_get_vf_handle(vb2_v4l2->private)); } fput(file); - mutex_unlock(&ctx->lock); } return ret; @@ -1406,6 +1506,7 @@ static int vidioc_vdec_event_unsubscribe(struct v4l2_fh *fh, static int vidioc_try_fmt(struct v4l2_format *f, struct aml_video_fmt *fmt) { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + u32 width, height; int i; pix_fmt_mp->field = V4L2_FIELD_NONE; @@ -1431,13 +1532,19 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct aml_video_fmt *fmt) */ tmp_w = pix_fmt_mp->width; tmp_h = pix_fmt_mp->height; - v4l_bound_align_image(&pix_fmt_mp->width, + width = pix_fmt_mp->width; + height = pix_fmt_mp->height; + + v4l_bound_align_image(&width, AML_VDEC_MIN_W, AML_VDEC_MAX_W, 6, - &pix_fmt_mp->height, + &height, AML_VDEC_MIN_H, AML_VDEC_MAX_H, 6, 9); + pix_fmt_mp->width = width; + pix_fmt_mp->height = height; + if (pix_fmt_mp->width < tmp_w && (pix_fmt_mp->width + 64) <= AML_VDEC_MAX_W) pix_fmt_mp->width += 64; @@ -1586,6 +1693,40 @@ static int vidioc_vdec_s_selection(struct file *file, void *priv, return 0; } +static void copy_v4l2_format_dimention(struct v4l2_pix_format_mplane *pix_mp, + struct aml_q_data *q_data, u32 type) +{ + if (!pix_mp || !q_data) + return; + + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + pix_mp->width = q_data->visible_width; + pix_mp->height = q_data->visible_height; + } else { + /* + * Width and height are set to the dimensions + * of the movie, the buffer is bigger and + * further processing stages should crop to this + * rectangle. + */ + pix_mp->width = q_data->coded_width; + pix_mp->height = q_data->coded_height; + } + + /* + * Set pixelformat to the format in which mt vcodec + * outputs the decoded frame + */ + pix_mp->num_planes = q_data->fmt->num_planes; + pix_mp->pixelformat = q_data->fmt->fourcc; + pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0]; + pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0]; + if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1]; + pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1]; + } +} + static int vidioc_vdec_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { @@ -1633,6 +1774,8 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, q_data->fmt = fmt; vidioc_try_fmt(f, q_data->fmt); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (ctx->is_drm_mode) + pix_mp->plane_fmt[0].sizeimage = 1; q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage; q_data->coded_width = pix_mp->width; q_data->coded_height = pix_mp->height; @@ -1664,6 +1807,12 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, mutex_unlock(&ctx->state_lock); } + if (!V4L2_TYPE_IS_OUTPUT(f->type)) { + ctx->cap_pix_fmt = pix_mp->pixelformat; + if (ctx->state >= AML_STATE_PROBE) + copy_v4l2_format_dimention(pix_mp, q_data, f->type); + } + return 0; } @@ -1673,7 +1822,8 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, int i = 0; struct aml_vcodec_ctx *ctx = fh_to_ctx(priv); - v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s\n", __func__); + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s, idx: %d, pix fmt: %x\n", + __func__, fsize->index, fsize->pixel_format); if (fsize->index != 0) return -EINVAL; @@ -1791,25 +1941,7 @@ static int vidioc_vdec_g_fmt(struct file *file, void *priv, q_data->bytesperline[0] = ctx->picinfo.coded_width; q_data->bytesperline[1] = ctx->picinfo.coded_width; - /* - * Width and height are set to the dimensions - * of the movie, the buffer is bigger and - * further processing stages should crop to this - * rectangle. - */ - pix_mp->width = q_data->coded_width; - pix_mp->height = q_data->coded_height; - - /* - * Set pixelformat to the format in which mt vcodec - * outputs the decoded frame - */ - pix_mp->num_planes = q_data->fmt->num_planes; - pix_mp->pixelformat = q_data->fmt->fourcc; - pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0]; - pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0]; - pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1]; - pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1]; + copy_v4l2_format_dimention(pix_mp, q_data, f->type); } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { /* * This is run on OUTPUT @@ -1817,21 +1949,9 @@ static int vidioc_vdec_g_fmt(struct file *file, void *priv, * so width and height have no meaning. * Assign value here to pass v4l2-compliance test */ - pix_mp->width = q_data->visible_width; - pix_mp->height = q_data->visible_height; - pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0]; - pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0]; - pix_mp->pixelformat = q_data->fmt->fourcc; - pix_mp->num_planes = q_data->fmt->num_planes; + copy_v4l2_format_dimention(pix_mp, q_data, f->type); } else { - pix_mp->width = q_data->coded_width; - pix_mp->height = q_data->coded_height; - pix_mp->num_planes = q_data->fmt->num_planes; - pix_mp->pixelformat = q_data->fmt->fourcc; - pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0]; - pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0]; - pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1]; - pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1]; + copy_v4l2_format_dimention(pix_mp, q_data, f->type); v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, "type=%d state=%d Format information could not be read, not ready yet!\n", @@ -1864,8 +1984,13 @@ static int vidioc_vdec_create_bufs(struct file *file, void *priv, { struct aml_vcodec_ctx *ctx = fh_to_ctx(fh); + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, id: %d\n", __func__, a->id); + if (a->id == V4L2_CID_MIN_BUFFERS_FOR_CAPTURE) - a->value = 20; + a->value = 4; + else if (a->id == V4L2_CID_MIN_BUFFERS_FOR_OUTPUT) + a->value = 8; return 0; }*/ @@ -1904,6 +2029,8 @@ static int vb2ops_vdec_queue_setup(struct vb2_queue *vq, for (i = 0; i < *nplanes; i++) { sizes[i] = q_data->sizeimage[i]; + if (V4L2_TYPE_IS_OUTPUT(vq->type) && ctx->output_dma_mode) + sizes[i] = 0; //alloc_devs[i] = &ctx->dev->plat_dev->dev; alloc_devs[i] = v4l_get_dev_from_codec_mm();//alloc mm from the codec mm } @@ -1926,6 +2053,10 @@ static int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) "%s, type: %d, idx: %d\n", __func__, vb->vb2_queue->type, vb->index); + if (vb->memory == VB2_MEMORY_DMABUF + && V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) + return 0; + q_data = aml_vdec_get_q_data(ctx, vb->vb2_queue->type); for (i = 0; i < q_data->fmt->num_planes; i++) { @@ -2015,15 +2146,31 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) return; } - src_mem.vaddr = vb2_plane_vaddr(vb, 0); - src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); - src_mem.size = vb->planes[0].bytesused; + src_mem.index = vb->index; + src_mem.vaddr = vb2_plane_vaddr(vb, 0); + src_mem.addr = vb2_dma_contig_plane_dma_addr(vb, 0); + src_mem.size = vb->planes[0].bytesused; + src_mem.model = vb->memory; + if (vdec_if_probe(ctx, &src_mem, NULL)) { v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_DONE); + + if (ctx->is_drm_mode && src_mem.model == VB2_MEMORY_DMABUF) + aml_recycle_dma_buffers(ctx); + else + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_DONE); return; } + /* + * If on model dmabuf must remove the buffer + * because this data has been consumed by hw. + */ + if (ctx->is_drm_mode && src_mem.model == VB2_MEMORY_DMABUF) { + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + aml_recycle_dma_buffers(ctx); + } + if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo)) { v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "GET_PARAM_PICTURE_INFO err\n"); @@ -2107,17 +2254,19 @@ static int vb2ops_vdec_buf_init(struct vb2_buffer *vb) /* codec_mm buffers count */ if (V4L2_TYPE_IS_OUTPUT(vb->type)) { - size = vb->planes[0].length; - phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0); - snprintf(owner, PATH_MAX, "%s-%d", "v4l-input", ctx->id); - strncpy(buf->mem_onwer, owner, sizeof(buf->mem_onwer)); - buf->mem_onwer[sizeof(buf->mem_onwer) - 1] = '\0'; + if (vb->memory == VB2_MEMORY_MMAP) { + size = vb->planes[0].length; + phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + snprintf(owner, PATH_MAX, "%s-%d", "v4l-input", ctx->id); + strncpy(buf->mem_onwer, owner, sizeof(buf->mem_onwer)); + buf->mem_onwer[sizeof(buf->mem_onwer) - 1] = '\0'; - buf->mem[0] = v4l_reqbufs_from_codec_mm(buf->mem_onwer, + buf->mem[0] = v4l_reqbufs_from_codec_mm(buf->mem_onwer, + phy_addr, size, vb->index); + v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, + "IN alloc, addr: %x, size: %u, idx: %u\n", phy_addr, size, vb->index); - v4l_dbg(ctx, V4L_DEBUG_CODEC_BUFMGR, - "IN alloc, addr: %x, size: %u, idx: %u\n", - phy_addr, size, vb->index); + } } else { snprintf(owner, PATH_MAX, "%s-%d", "v4l-output", ctx->id); strncpy(buf->mem_onwer, owner, sizeof(buf->mem_onwer)); @@ -2223,9 +2372,13 @@ static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) if (V4L2_TYPE_IS_OUTPUT(q->type)) { while ((vb2_v4l2 = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) v4l2_m2m_buf_done(vb2_v4l2, VB2_BUF_STATE_ERROR); + + if (ctx->is_drm_mode && q->memory == VB2_MEMORY_DMABUF) + aml_recycle_dma_buffers(ctx); } else { - /* stop decoder. */ - wait_vcodec_ending(ctx); + /* clean output cache and decoder status . */ + if (ctx->state > AML_STATE_INIT) + aml_vdec_reset(ctx); for (i = 0; i < q->num_buffers; ++i) { vb2_v4l2 = to_vb2_v4l2_buffer(q->bufs[i]); @@ -2241,6 +2394,7 @@ static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) q->bufs[i]->index, q->bufs[i]->state);*/ } } + ctx->buf_used_count = 0; ctx->cap_pool.in = 0; ctx->cap_pool.out = 0; @@ -2251,7 +2405,8 @@ static void m2mops_vdec_device_run(void *priv) struct aml_vcodec_ctx *ctx = priv; struct aml_vcodec_dev *dev = ctx->dev; - queue_work(dev->decode_workqueue, &ctx->decode_work); + if (ctx->output_thread_ready) + queue_work(dev->decode_workqueue, &ctx->decode_work); } void vdec_device_vf_run(struct aml_vcodec_ctx *ctx) @@ -2286,7 +2441,8 @@ static int aml_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl) struct aml_vcodec_ctx *ctx = ctrl_to_ctx(ctrl); int ret = 0; - v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s\n", __func__); + v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, + "%s, id: %d\n", __func__, ctrl->id); switch (ctrl->id) { case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: @@ -2299,6 +2455,9 @@ static int aml_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl) ret = -EINVAL; } break; + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: + ctrl->val = 4; + break; default: ret = -EINVAL; } @@ -2311,9 +2470,10 @@ static int aml_vdec_try_s_v_ctrl(struct v4l2_ctrl *ctrl) v4l_dbg(ctx, V4L_DEBUG_CODEC_PROT, "%s\n", __func__); - if (ctrl->id == AML_V4L2_SET_DECMODE) { + if (ctrl->id == AML_V4L2_SET_DRMMODE) { ctx->is_drm_mode = ctrl->val; - v4l_dbg(ctx, V4L_DEBUG_CODEC_EXINFO, + ctx->param_sets_from_ucode = true; + v4l_dbg(ctx, V4L_DEBUG_CODEC_PRINFO, "set stream mode: %x\n", ctrl->val); } @@ -2326,8 +2486,8 @@ static const struct v4l2_ctrl_ops aml_vcodec_dec_ctrl_ops = { }; static const struct v4l2_ctrl_config ctrl_st_mode = { - .name = "stream mode", - .id = AML_V4L2_SET_DECMODE, + .name = "drm mode", + .id = AML_V4L2_SET_DRMMODE, .ops = &aml_vcodec_dec_ctrl_ops, .type = V4L2_CTRL_TYPE_BOOLEAN, .flags = V4L2_CTRL_FLAG_WRITE_ONLY, @@ -2342,11 +2502,21 @@ int aml_vcodec_dec_ctrls_setup(struct aml_vcodec_ctx *ctx) int ret; struct v4l2_ctrl *ctrl; - v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 1); + v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 3); ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl, &aml_vcodec_dec_ctrl_ops, V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, - 0, 32, 1, 1); + 0, 32, 1, 2); + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + if (ctx->ctrl_hdl.error) { + ret = ctx->ctrl_hdl.error; + goto err; + } + + ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl, + &aml_vcodec_dec_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, 32, 1, 8); ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; if (ctx->ctrl_hdl.error) { ret = ctx->ctrl_hdl.error; @@ -2420,6 +2590,8 @@ static int vidioc_vdec_s_parm(struct file *file, void *fh, return 0; } +//fixme +/* static void m2mops_vdec_lock(void *m2m_priv) { struct aml_vcodec_ctx *ctx = m2m_priv; @@ -2433,13 +2605,13 @@ static void m2mops_vdec_unlock(void *m2m_priv) mutex_unlock(&ctx->dev->dev_mutex); } - +*/ const struct v4l2_m2m_ops aml_vdec_m2m_ops = { .device_run = m2mops_vdec_device_run, .job_ready = m2mops_vdec_job_ready, .job_abort = m2mops_vdec_job_abort, - .lock = m2mops_vdec_lock, - .unlock = m2mops_vdec_unlock, + //.lock = m2mops_vdec_lock, //fixme + //.unlock = m2mops_vdec_unlock, }; static const struct vb2_ops aml_vdec_vb2_ops = { @@ -2459,7 +2631,7 @@ const struct v4l2_ioctl_ops aml_vdec_ioctl_ops = { .vidioc_streamoff = vidioc_decoder_streamoff, .vidioc_reqbufs = vidioc_decoder_reqbufs, .vidioc_querybuf = vidioc_vdec_querybuf, - .vidioc_expbuf = vidioc_vdec_expbuf,//?? + .vidioc_expbuf = vidioc_vdec_expbuf, //.vidioc_g_ctrl = vidioc_vdec_g_ctrl, .vidioc_qbuf = vidioc_vdec_qbuf, @@ -2481,17 +2653,18 @@ const struct v4l2_ioctl_ops aml_vdec_ioctl_ops = { .vidioc_create_bufs = vidioc_vdec_create_bufs, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_vdec_enum_fmt_vid_cap_mplane, + //fixme + //.vidioc_enum_fmt_vid_cap_mplane = vidioc_vdec_enum_fmt_vid_cap_mplane, + //.vidioc_enum_fmt_vid_out_mplane = vidioc_vdec_enum_fmt_vid_out_mplane, .vidioc_enum_fmt_vid_cap = vidioc_vdec_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_vdec_enum_fmt_vid_out_mplane, .vidioc_enum_fmt_vid_out = vidioc_vdec_enum_fmt_vid_out_mplane, .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_querycap = vidioc_vdec_querycap, .vidioc_subscribe_event = vidioc_vdec_subscribe_evt, .vidioc_unsubscribe_event = vidioc_vdec_event_unsubscribe, - .vidioc_g_selection = vidioc_vdec_g_selection, - .vidioc_s_selection = vidioc_vdec_s_selection, + .vidioc_g_selection = vidioc_vdec_g_selection, + .vidioc_s_selection = vidioc_vdec_s_selection, .vidioc_decoder_cmd = vidioc_decoder_cmd, .vidioc_try_decoder_cmd = vidioc_try_decoder_cmd, diff --git a/drivers/amvdec_ports/aml_vcodec_dec.h b/drivers/amvdec_ports/aml_vcodec_dec.h index 68f878a..3406e9f 100644 --- a/drivers/amvdec_ports/aml_vcodec_dec.h +++ b/drivers/amvdec_ports/aml_vcodec_dec.h @@ -38,8 +38,6 @@ #define VDEC_GATHER_MEMORY_TYPE 0 #define VDEC_SCATTER_MEMORY_TYPE 1 -#define AML_V4L2_SET_DECMODE (V4L2_CID_USER_AMLOGIC_BASE + 0) - /** * struct vdec_fb - decoder frame buffer * @mem_type : gather or scatter memory. diff --git a/drivers/amvdec_ports/aml_vcodec_dec_drv.c b/drivers/amvdec_ports/aml_vcodec_dec_drv.c index beb5c00..7758ca8 100644 --- a/drivers/amvdec_ports/aml_vcodec_dec_drv.c +++ b/drivers/amvdec_ports/aml_vcodec_dec_drv.c @@ -48,8 +48,8 @@ #define V4LVIDEO_IOCTL_SET_CONFIG_PARAMS _IOWR(V4LVIDEO_IOC_MAGIC, 0x04, struct v4l2_config_parm) #define V4LVIDEO_IOCTL_GET_CONFIG_PARAMS _IOWR(V4LVIDEO_IOC_MAGIC, 0x05, struct v4l2_config_parm) -bool scatter_mem_enable; -bool param_sets_from_ucode; +bool param_sets_from_ucode = 1; +bool enable_drm_mode; static int fops_vcodec_open(struct file *file) { @@ -82,12 +82,15 @@ static int fops_vcodec_open(struct file *file) mutex_init(&ctx->state_lock); mutex_init(&ctx->lock); spin_lock_init(&ctx->slock); - init_waitqueue_head(&ctx->wq); init_completion(&ctx->comp); - ctx->scatter_mem_enable = scatter_mem_enable ? 1 : 0; ctx->param_sets_from_ucode = param_sets_from_ucode ? 1 : 0; + if (enable_drm_mode) { + ctx->is_drm_mode = true; + ctx->param_sets_from_ucode = true; + } + ctx->type = AML_INST_DECODER; ret = aml_vcodec_dec_ctrls_setup(ctx); if (ret) { @@ -105,6 +108,7 @@ static int fops_vcodec_open(struct file *file) } src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + ctx->output_thread_ready = true; ctx->empty_flush_buf->vb.vb2_buf.vb2_queue = src_vq; ctx->empty_flush_buf->lastframe = true; aml_vcodec_dec_set_default_params(ctx); @@ -612,12 +616,12 @@ bool dump_capture_frame; EXPORT_SYMBOL(dump_capture_frame); module_param(dump_capture_frame, bool, 0644); -EXPORT_SYMBOL(scatter_mem_enable); -module_param(scatter_mem_enable, bool, 0644); - EXPORT_SYMBOL(param_sets_from_ucode); module_param(param_sets_from_ucode, bool, 0644); +EXPORT_SYMBOL(enable_drm_mode); +module_param(enable_drm_mode, bool, 0644); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("AML video codec V4L2 decoder driver"); diff --git a/drivers/amvdec_ports/aml_vcodec_dec_pm.c b/drivers/amvdec_ports/aml_vcodec_dec_pm.c deleted file mode 100644 index c801e87..0000000 --- a/drivers/amvdec_ports/aml_vcodec_dec_pm.c +++ b/dev/null @@ -1,206 +0,0 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ -#include <linux/clk.h> -#include <linux/of_address.h> -#include <linux/of_platform.h> -#include <linux/pm_runtime.h> - -#include "aml_vcodec_dec_pm.h" -#include "aml_vcodec_util.h" -//#include "aml_vpu.h" - -int aml_vcodec_init_dec_pm(struct aml_vcodec_dev *amldev) -{ - struct device_node *node; - struct platform_device *pdev; - struct aml_vcodec_pm *pm; - int ret = 0; - - pdev = amldev->plat_dev; - pm = &amldev->pm; - pm->amldev = amldev; - node = of_parse_phandle(pdev->dev.of_node, "larb", 0); - if (!node) { - aml_v4l2_err("of_parse_phandle larb fail!"); - return -1; - } - - pdev = of_find_device_by_node(node); - if (WARN_ON(!pdev)) { - of_node_put(node); - return -1; - } - pm->larbvdec = &pdev->dev; - pdev = amldev->plat_dev; - pm->dev = &pdev->dev; - - pm->vcodecpll = devm_clk_get(&pdev->dev, "vcodecpll"); - if (IS_ERR(pm->vcodecpll)) { - aml_v4l2_err("devm_clk_get vcodecpll fail"); - ret = PTR_ERR(pm->vcodecpll); - } - - pm->univpll_d2 = devm_clk_get(&pdev->dev, "univpll_d2"); - if (IS_ERR(pm->univpll_d2)) { - aml_v4l2_err("devm_clk_get univpll_d2 fail"); - ret = PTR_ERR(pm->univpll_d2); - } - - pm->clk_cci400_sel = devm_clk_get(&pdev->dev, "clk_cci400_sel"); - if (IS_ERR(pm->clk_cci400_sel)) { - aml_v4l2_err("devm_clk_get clk_cci400_sel fail"); - ret = PTR_ERR(pm->clk_cci400_sel); - } - - pm->vdec_sel = devm_clk_get(&pdev->dev, "vdec_sel"); - if (IS_ERR(pm->vdec_sel)) { - aml_v4l2_err("devm_clk_get vdec_sel fail"); - ret = PTR_ERR(pm->vdec_sel); - } - - pm->vdecpll = devm_clk_get(&pdev->dev, "vdecpll"); - if (IS_ERR(pm->vdecpll)) { - aml_v4l2_err("devm_clk_get vdecpll fail"); - ret = PTR_ERR(pm->vdecpll); - } - - pm->vencpll = devm_clk_get(&pdev->dev, "vencpll"); - if (IS_ERR(pm->vencpll)) { - aml_v4l2_err("devm_clk_get vencpll fail"); - ret = PTR_ERR(pm->vencpll); - } - - pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel"); - if (IS_ERR(pm->venc_lt_sel)) { - aml_v4l2_err("devm_clk_get venc_lt_sel fail"); - ret = PTR_ERR(pm->venc_lt_sel); - } - - pm->vdec_bus_clk_src = devm_clk_get(&pdev->dev, "vdec_bus_clk_src"); - if (IS_ERR(pm->vdec_bus_clk_src)) { - aml_v4l2_err("devm_clk_get vdec_bus_clk_src"); - ret = PTR_ERR(pm->vdec_bus_clk_src); - } - - pm_runtime_enable(&pdev->dev); - - return ret; -} - -void aml_vcodec_release_dec_pm(struct aml_vcodec_dev *dev) -{ - pm_runtime_disable(dev->pm.dev); -} - -void aml_vcodec_dec_pw_on(struct aml_vcodec_pm *pm) -{ - int ret; - - ret = pm_runtime_get_sync(pm->dev); - if (ret) - aml_v4l2_err("pm_runtime_get_sync fail %d", ret); -} - -void aml_vcodec_dec_pw_off(struct aml_vcodec_pm *pm) -{ - int ret; - - ret = pm_runtime_put_sync(pm->dev); - if (ret) - aml_v4l2_err("pm_runtime_put_sync fail %d", ret); -} - -void aml_vcodec_dec_clock_on(struct aml_vcodec_pm *pm) -{ - int ret; - - ret = clk_set_rate(pm->vcodecpll, 1482 * 1000000); - if (ret) - aml_v4l2_err("clk_set_rate vcodecpll fail %d", ret); - - ret = clk_set_rate(pm->vencpll, 800 * 1000000); - if (ret) - aml_v4l2_err("clk_set_rate vencpll fail %d", ret); - - ret = clk_prepare_enable(pm->vcodecpll); - if (ret) - aml_v4l2_err("clk_prepare_enable vcodecpll fail %d", ret); - - ret = clk_prepare_enable(pm->vencpll); - if (ret) - aml_v4l2_err("clk_prepare_enable vencpll fail %d", ret); - - ret = clk_prepare_enable(pm->vdec_bus_clk_src); - if (ret) - aml_v4l2_err("clk_prepare_enable vdec_bus_clk_src fail %d", - ret); - - ret = clk_prepare_enable(pm->venc_lt_sel); - if (ret) - aml_v4l2_err("clk_prepare_enable venc_lt_sel fail %d", ret); - - ret = clk_set_parent(pm->venc_lt_sel, pm->vdec_bus_clk_src); - if (ret) - aml_v4l2_err("clk_set_parent venc_lt_sel vdec_bus_clk_src fail %d", - ret); - - ret = clk_prepare_enable(pm->univpll_d2); - if (ret) - aml_v4l2_err("clk_prepare_enable univpll_d2 fail %d", ret); - - ret = clk_prepare_enable(pm->clk_cci400_sel); - if (ret) - aml_v4l2_err("clk_prepare_enable clk_cci400_sel fail %d", ret); - - ret = clk_set_parent(pm->clk_cci400_sel, pm->univpll_d2); - if (ret) - aml_v4l2_err("clk_set_parent clk_cci400_sel univpll_d2 fail %d", - ret); - - ret = clk_prepare_enable(pm->vdecpll); - if (ret) - aml_v4l2_err("clk_prepare_enable vdecpll fail %d", ret); - - ret = clk_prepare_enable(pm->vdec_sel); - if (ret) - aml_v4l2_err("clk_prepare_enable vdec_sel fail %d", ret); - - ret = clk_set_parent(pm->vdec_sel, pm->vdecpll); - if (ret) - aml_v4l2_err("clk_set_parent vdec_sel vdecpll fail %d", ret); - - //ret = aml_smi_larb_get(pm->larbvdec); - if (ret) - aml_v4l2_err("aml_smi_larb_get larbvdec fail %d", ret); - -} - -void aml_vcodec_dec_clock_off(struct aml_vcodec_pm *pm) -{ - //aml_smi_larb_put(pm->larbvdec); - clk_disable_unprepare(pm->vdec_sel); - clk_disable_unprepare(pm->vdecpll); - clk_disable_unprepare(pm->univpll_d2); - clk_disable_unprepare(pm->clk_cci400_sel); - clk_disable_unprepare(pm->venc_lt_sel); - clk_disable_unprepare(pm->vdec_bus_clk_src); - clk_disable_unprepare(pm->vencpll); - clk_disable_unprepare(pm->vcodecpll); -} diff --git a/drivers/amvdec_ports/aml_vcodec_dec_pm.h b/drivers/amvdec_ports/aml_vcodec_dec_pm.h deleted file mode 100644 index ccdf313..0000000 --- a/drivers/amvdec_ports/aml_vcodec_dec_pm.h +++ b/dev/null @@ -1,34 +0,0 @@ -/* -* Copyright (C) 2017 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. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -* -* Description: -*/ - -#ifndef _AML_VCODEC_DEC_PM_H_ -#define _AML_VCODEC_DEC_PM_H_ - -#include "aml_vcodec_drv.h" - -int aml_vcodec_init_dec_pm(struct aml_vcodec_dev *dev); -void aml_vcodec_release_dec_pm(struct aml_vcodec_dev *dev); - -void aml_vcodec_dec_pw_on(struct aml_vcodec_pm *pm); -void aml_vcodec_dec_pw_off(struct aml_vcodec_pm *pm); -void aml_vcodec_dec_clock_on(struct aml_vcodec_pm *pm); -void aml_vcodec_dec_clock_off(struct aml_vcodec_pm *pm); - -#endif /* _AML_VCODEC_DEC_PM_H_ */ diff --git a/drivers/amvdec_ports/aml_vcodec_drv.h b/drivers/amvdec_ports/aml_vcodec_drv.h index d3d8284..f28dc51 100644 --- a/drivers/amvdec_ports/aml_vcodec_drv.h +++ b/drivers/amvdec_ports/aml_vcodec_drv.h @@ -58,6 +58,9 @@ #define V4L2_EVENT_REQUEST_RESET (1 << 8) #define V4L2_EVENT_REQUEST_EXIT (1 << 9) +/* eos event */ +#define V4L2_EVENT_SEND_EOS (1 << 16) + /* v4l buffer pool */ #define V4L_CAP_BUFF_MAX (32) #define V4L_CAP_BUFF_INVALID (0) @@ -68,6 +71,14 @@ #define V4L_RESET_MODE_NORMAL (1 << 0) /* reset vdec_input and decoder. */ #define V4L_RESET_MODE_LIGHT (1 << 1) /* just only reset decoder. */ +/* m2m job queue's status */ +/* Instance is already queued on the job_queue */ +#define TRANS_QUEUED (1 << 0) +/* Instance is currently running in hardware */ +#define TRANS_RUNNING (1 << 1) +/* Instance is currently aborting */ +#define TRANS_ABORT (1 << 2) + /** * enum aml_hw_reg_idx - AML hw register base index */ @@ -370,101 +381,93 @@ struct aml_vdec_thread { /** * struct aml_vcodec_ctx - Context (instance) private data. * - * @type: type of the instance - decoder or encoder - * @dev: pointer to the aml_vcodec_dev of the device - * @list: link to ctx_list of aml_vcodec_dev - * @fh: struct v4l2_fh - * @m2m_ctx: pointer to the v4l2_m2m_ctx of the context - * @q_data: store information of input and output queue - * of the context - * @id: index of the context that this structure describes - * @state: state of the context - * @param_change: indicate encode parameter type - * @enc_params: encoding parameters - * @dec_if: hooked decoder driver interface - * @enc_if: hoooked encoder driver interface - * @drv_handle: driver handle for specific decode/encode instance - * - * @picinfo: store picture info after header parsing + * @id: index of the context that this structure describes. + * @type: type of the instance - decoder or encoder. + * @dev: pointer to the aml_vcodec_dev of the device. + * @m2m_ctx: pointer to the v4l2_m2m_ctx of the context. + * @ada_ctx: pointer to the aml_vdec_adapt of the context. + * @dec_if: hooked decoder driver interface. + * @drv_handle: driver handle for specific decode instance + * @fh: struct v4l2_fh. + * @ctrl_hdl: handler for v4l2 framework. + * @slock: protect v4l2 codec context. + * @empty_flush_buf: a fake size-0 capture buffer that indicates flush. + * @list: link to ctx_list of aml_vcodec_dev. + * @q_data: store information of input and output queue of the context. + * @queue: waitqueue that can be used to wait for this context to finish. + * @lock: protect the vdec thread. + * @state_lock: protect the codec status. + * @state: state of the context. + * @decode_work: decoder work be used to output buffer. + * @output_thread_ready: indicate the output thread ready. + * @cap_pool: capture buffers are remark in the pool. + * @vdec_thread_list: vdec thread be used to capture. * @dpb_size: store dpb count after header parsing - * @int_cond: variable used by the waitqueue - * @int_type: type of the last interrupt - * @queue: waitqueue that can be used to wait for this context to - * finish - * @irq_status: irq status - * - * @ctrl_hdl: handler for v4l2 framework - * @decode_work: worker for the decoding - * @encode_work: worker for the encoding - * @last_decoded_picinfo: pic information get from latest decode - * @empty_flush_buf: a fake size-0 capture buffer that indicates flush - * - * @colorspace: enum v4l2_colorspace; supplemental to pixelformat - * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding - * @quantization: enum v4l2_quantization, colorspace quantization - * @xfer_func: enum v4l2_xfer_func, colorspace transfer function - * @lock: protect variables accessed by V4L2 threads and worker thread such as - * aml_video_dec_buf. + * @param_change: indicate encode parameter type + * @param_sets_from_ucode: if true indicate ps from ucode. + * @v4l_codec_dpb_ready: queue buffer number greater than dpb. + * @comp: comp be used for sync picture information with decoder. + * @config: used to set or get parms for application. + * @picinfo: store picture info after header parsing. + * @last_decoded_picinfo: pic information get from latest decode. + * @colorspace: enum v4l2_colorspace; supplemental to pixelformat. + * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding. + * @quantization: enum v4l2_quantization, colorspace quantization. + * @xfer_func: enum v4l2_xfer_func, colorspace transfer function. + * @cap_pix_fmt: the picture format used to switch nv21 or nv12. + * @has_receive_eos: if receive last frame of capture that be set. + * @is_drm_mode: decoding work on drm mode if that set. + * @is_stream_mode: vdec input used to stream mode, default frame mode. + * @is_stream_off: the value used to handle reset active. + * @receive_cmd_stop: if receive the cmd flush decoder. + * @reset_flag: reset mode includes lightly and normal mode. + * @decoded_frame_cnt: the capture buffer deque number to be count. + * @buf_used_count: means that decode allocate how many buffs from v4l. */ struct aml_vcodec_ctx { - enum aml_instance_type type; - struct aml_vcodec_dev *dev; - struct list_head list; - - struct v4l2_fh fh; - struct v4l2_m2m_ctx *m2m_ctx; - struct aml_vdec_adapt *ada_ctx; - struct aml_q_data q_data[2]; - int id; - struct mutex state_lock; - enum aml_instance_state state; - enum aml_encode_param param_change; - struct aml_enc_params enc_params; - - const struct vdec_common_if *dec_if; - const struct venc_common_if *enc_if; - unsigned long drv_handle; - - struct vdec_pic_info picinfo; - int dpb_size; - - int int_cond; - int int_type; - wait_queue_head_t queue; - unsigned int irq_status; - - struct v4l2_ctrl_handler ctrl_hdl; - struct work_struct decode_work; - struct work_struct encode_work; - struct vdec_pic_info last_decoded_picinfo; - struct aml_video_dec_buf *empty_flush_buf; - - enum v4l2_colorspace colorspace; - enum v4l2_ycbcr_encoding ycbcr_enc; - enum v4l2_quantization quantization; - enum v4l2_xfer_func xfer_func; - - int decoded_frame_cnt; - struct mutex lock; - struct completion comp; - bool has_receive_eos; - struct list_head vdec_thread_list; - bool is_drm_mode; - bool is_stream_mode; - int buf_used_count; - bool receive_cmd_stop; - bool scatter_mem_enable; - bool param_sets_from_ucode; - bool v4l_codec_ready; - bool v4l_codec_dpb_ready; - wait_queue_head_t wq; - spinlock_t slock; - struct v4l2_config_parm config; - bool is_stream_off; - int reset_flag; - int stop_cmd; - u32 display_count; - struct v4l_buff_pool cap_pool; + int id; + enum aml_instance_type type; + struct aml_vcodec_dev *dev; + struct v4l2_m2m_ctx *m2m_ctx; + struct aml_vdec_adapt *ada_ctx; + const struct vdec_common_if *dec_if; + ulong drv_handle; + struct v4l2_fh fh; + struct v4l2_ctrl_handler ctrl_hdl; + spinlock_t slock; + struct aml_video_dec_buf *empty_flush_buf; + struct list_head list; + + struct aml_q_data q_data[2]; + wait_queue_head_t queue; + struct mutex lock, state_lock; + enum aml_instance_state state; + struct work_struct decode_work; + bool output_thread_ready; + struct v4l_buff_pool cap_pool; + struct list_head vdec_thread_list; + + int dpb_size; + bool param_sets_from_ucode; + bool v4l_codec_dpb_ready; + struct completion comp; + struct v4l2_config_parm config; + struct vdec_pic_info picinfo; + struct vdec_pic_info last_decoded_picinfo; + enum v4l2_colorspace colorspace; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_quantization quantization; + enum v4l2_xfer_func xfer_func; + u32 cap_pix_fmt; + + bool has_receive_eos; + bool is_drm_mode; + bool output_dma_mode; + bool is_stream_off; + bool receive_cmd_stop; + int reset_flag; + int decoded_frame_cnt; + int buf_used_count; }; /** diff --git a/drivers/amvdec_ports/aml_vcodec_util.h b/drivers/amvdec_ports/aml_vcodec_util.h index da8d725..8e479a6 100644 --- a/drivers/amvdec_ports/aml_vcodec_util.h +++ b/drivers/amvdec_ports/aml_vcodec_util.h @@ -34,13 +34,18 @@ typedef unsigned char u8; #define CODEC_MODE(a, b, c, d)\ (((u8)(a) << 24) | ((u8)(b) << 16) | ((u8)(c) << 8) | (u8)(d)) +#define BUFF_IDX(h, i)\ + (((ulong)(h) << 8) | (u8)(i)) + struct aml_vcodec_mem { + int index; ulong addr; u32 size; void *vaddr; u32 bytes_used; u32 offset; dma_addr_t dma_addr; + u32 model; }; struct aml_vcodec_ctx; diff --git a/drivers/amvdec_ports/decoder/h264_parse.c b/drivers/amvdec_ports/decoder/h264_parse.c deleted file mode 100644 index 1c3b73d..0000000 --- a/drivers/amvdec_ports/decoder/h264_parse.c +++ b/dev/null @@ -1,389 +0,0 @@ -/* - * drivers/amlogic/media_modules/amvdec_ports/decoder/h264_parse.c - * - * Copyright (C) 2017 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. - * - */ - -#include <linux/kernel.h> -#include "h264_parse.h" -#include "h264_stream.h" - -static unsigned char h264_exp_golomb_bits[256] = { - 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, -}; - -static unsigned char ZZ_SCAN[16] = { - 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 -}; - -static unsigned char ZZ_SCAN8[64] = { - 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 -}; - -unsigned int h264_u(struct h264_stream_t *s, unsigned int n) -{ - //if (n % 8 == 0) { - // return h264_stream_read_bytes(s, n / 8); - //} - return h264_stream_read_bits(s, n); -} - -unsigned int h264_ue(struct h264_stream_t *s) -{ - unsigned int bits, read; - unsigned char coded; - - bits = 0; - while (true) { - if (h264_stream_bytes_remaining(s) < 1) { - read = h264_stream_peek_bits(s, s->bit_pos) << - (8 - s->bit_pos); - break; - } - - read = h264_stream_peek_bits(s, 8); - if (bits > 16) - break; - - if (read) - break; - - h264_stream_read_bits(s, 8); - bits += 8; - } - - coded = h264_exp_golomb_bits[read]; - h264_stream_read_bits(s, coded); - bits += coded; - return h264_stream_read_bits(s, bits + 1) - 1; -} - -int h264_se(struct h264_stream_t *s) -{ - unsigned int ret; - - ret = h264_ue(s); - if (!(ret & 0x1)) { - ret >>= 1; - return (int)(-ret); - } - - return (ret + 1) >> 1; -} - -void h264_f(struct h264_stream_t *s, unsigned int n, unsigned int pattern) -{ - unsigned int val = h264_u(s, n); - - if (val != pattern) { - pr_err("fixed-pattern doesn't match. expected: %x actual: %x\n", - pattern, (unsigned int)val); - return; - } -} - -void h264_rbsp_trailing_bits(struct h264_stream_t *s) -{ - h264_f(s, 1, 1); - h264_f(s, s->bit_pos, 0); -} - -// syntax for scaling list matrix values -void Scaling_List(int *scalingList, int sizeOfScalingList, - bool *UseDefaultScalingMatrix, struct h264_stream_t *s) -{ - int j, scanj; - int delta_scale, lastScale, nextScale; - - lastScale = 8; - nextScale = 8; - - for (j = 0; j < sizeOfScalingList; j++) { - scanj = (sizeOfScalingList == 16) ? ZZ_SCAN[j] : ZZ_SCAN8[j]; - - if (nextScale != 0) { - delta_scale = h264_ue(s); - nextScale = (lastScale + delta_scale + 256) % 256; - *UseDefaultScalingMatrix = - (bool) (scanj == 0 && nextScale == 0); - } - - scalingList[scanj] = (nextScale == 0) ? lastScale : nextScale; - lastScale = scalingList[scanj]; - } -} - -void h264_sps_parse(struct h264_stream_t *s, struct h264_SPS_t *sps) -{ - unsigned int i, n_ScalingList; - - sps->profile_idc = h264_u(s, 8); - - if ((sps->profile_idc != BASELINE) && - (sps->profile_idc != MAIN) && - (sps->profile_idc != EXTENDED) && - (sps->profile_idc != FREXT_HP) && - (sps->profile_idc != FREXT_Hi10P) && - (sps->profile_idc != FREXT_Hi422) && - (sps->profile_idc != FREXT_Hi444) && - (sps->profile_idc != FREXT_CAVLC444) - && (sps->profile_idc != MVC_HIGH) - && (sps->profile_idc != STEREO_HIGH)) { - pr_err("Invalid Profile IDC (%d) encountered.\n", - sps->profile_idc); - return; - } - - sps->constrained_set0_flag = h264_u(s, 1); - sps->constrained_set1_flag = h264_u(s, 1); - sps->constrained_set2_flag = h264_u(s, 1); - h264_u(s, 5); // reserved_zero_5bits - sps->level_idc = h264_u(s, 8); - sps->seq_parameter_set_id = h264_ue(s); - - // Fidelity Range Extensions stuff - sps->chroma_format_idc = 1; - sps->bit_depth_luma_minus8 = 0; - sps->bit_depth_chroma_minus8 = 0; - sps->lossless_qpprime_flag = 0; - sps->separate_colour_plane_flag = 0; - - if ((sps->profile_idc == FREXT_HP) || - (sps->profile_idc == FREXT_Hi10P) || - (sps->profile_idc == FREXT_Hi422) || - (sps->profile_idc == FREXT_Hi444) || - (sps->profile_idc == FREXT_CAVLC444)) { - sps->chroma_format_idc = h264_ue(s); - - if (sps->chroma_format_idc == YUV444) - sps->separate_colour_plane_flag = h264_u(s, 1); - - sps->bit_depth_luma_minus8 = h264_ue(s); - sps->bit_depth_chroma_minus8 = h264_ue(s); - //checking; - if ((sps->bit_depth_luma_minus8 + 8 > sizeof(unsigned short) * 8) || - (sps->bit_depth_chroma_minus8 + 8 > sizeof(unsigned short) * 8)) { - pr_err("Source picture has higher bit depth than imgpel data type.\n"); - pr_err("Please recompile with larger data type for imgpel.\n"); - } - - sps->lossless_qpprime_flag = h264_u(s, 1); - sps->seq_scaling_matrix_present_flag = h264_u(s, 1); - if (sps->seq_scaling_matrix_present_flag) { - n_ScalingList = (sps->chroma_format_idc != YUV444) ? 8 : 12; - for (i = 0; i < n_ScalingList; i++) { - sps->seq_scaling_list_present_flag[i] = h264_u(s, 1); - if (sps->seq_scaling_list_present_flag[i]) { - if (i < 6) - Scaling_List(sps->ScalingList4x4[i], 16, - &sps->UseDefaultScalingMatrix4x4Flag[i], s); - else - Scaling_List(sps->ScalingList8x8[i - 6], - 64, &sps->UseDefaultScalingMatrix8x8Flag[i - 6], s); - } - } - } - } - - sps->log2_max_frame_num_minus4 = h264_ue(s); - sps->pic_order_cnt_type = h264_ue(s); - if (sps->pic_order_cnt_type == 0) { - sps->log2_max_pic_order_cnt_lsb_minus4 = h264_ue(s); - } else if (sps->pic_order_cnt_type == 1) { - sps->delta_pic_order_always_zero_flag = h264_se(s); - sps->offset_for_non_ref_pic = h264_se(s); - sps->offset_for_top_to_bottom_field = h264_se(s); - sps->num_ref_frames_in_poc_cycle = h264_se(s); - for (i = 0; i < sps->num_ref_frames_in_poc_cycle; ++i) - sps->offset_for_ref_frame[i] = h264_se(s); - } - - sps->num_ref_frames = h264_ue(s); - sps->gaps_in_frame_num_value_allowed_flag = h264_u(s, 1); - sps->pic_width_in_mbs_minus1 = h264_ue(s); - sps->pic_height_in_map_units_minus1 = h264_ue(s); - sps->frame_mbs_only_flag = h264_u(s, 1); - if (!sps->frame_mbs_only_flag) - sps->mb_adaptive_frame_field_flag = h264_u(s, 1); - - sps->direct_8x8_inference_flag = h264_u(s, 1); - sps->frame_cropping_flag = h264_u(s, 1); - if (sps->frame_cropping_flag) { - sps->frame_crop_left_offset = h264_ue(s); - sps->frame_crop_right_offset = h264_ue(s); - sps->frame_crop_top_offset = h264_ue(s); - sps->frame_crop_bottom_offset = h264_ue(s); - } - - sps->vui_parameters_present_flag = h264_u(s, 1); - //if (sps->vui_parameters_present_flag) { - // sps->vui_parameters = h264_vui_parameters(s); - //} - h264_rbsp_trailing_bits(s); -} - -void h264_pps_parse(struct h264_stream_t *s, struct h264_PPS_t *pps) -{ - pps->pic_parameter_set_id = h264_ue(s); - pps->seq_parameter_set_id = h264_ue(s); - pps->entropy_coding_mode_flag = h264_u(s, 1); - pps->pic_order_present_flag = h264_u(s, 1); - pps->num_slice_groups_minus1 = h264_ue(s); - if (pps->num_slice_groups_minus1 > 0) { - pps->slice_group_map_type = h264_ue(s); - if (pps->slice_group_map_type == 0) { - pps->run_length_minus1 = h264_ue(s); - } else if (pps->slice_group_map_type == 2) { - pps->top_left = h264_ue(s); - pps->bottom_right = h264_ue(s); - } else if (pps->slice_group_map_type == 3 || - pps->slice_group_map_type == 4 || - pps->slice_group_map_type == 5) { - pps->slice_group_change_direction_flag = h264_u(s, 1); - pps->slice_group_change_rate_minus1 = h264_ue(s); - } else if (pps->slice_group_map_type == 6) { - pps->pic_size_in_map_units_minus1 = h264_ue(s); - pps->slice_group_id = h264_ue(s); - } - } - pps->num_ref_idx_l0_active_minus1 = h264_ue(s); - pps->num_ref_idx_l1_active_minus1 = h264_ue(s); - pps->weighted_pred_flag = h264_u(s, 1); - pps->weighted_bipred_idc = h264_u(s, 2); - pps->pic_init_qp_minus26 = h264_se(s); - pps->pic_init_qs_minus26 = h264_se(s); - pps->chroma_qp_index_offset = h264_se(s); - pps->deblocking_filter_control_present_flag = h264_u(s, 1); - pps->constrained_intra_pred_flag = h264_u(s, 1); - pps->redundant_pic_cnt_present_flag = h264_u(s, 1); - h264_rbsp_trailing_bits(s); -} - -void h264_sps_info(struct h264_SPS_t *sps) -{ - int i; - - pr_info("sequence_parameter_set {\n"); - pr_info(" profile_idc: %d\n", sps->profile_idc); - pr_info(" constraint_set0_flag: %d\n", sps->constrained_set0_flag); - pr_info(" constraint_set1_flag: %d\n", sps->constrained_set1_flag); - pr_info(" constraint_set2_flag: %d\n", sps->constrained_set2_flag); - pr_info(" level_idc: %d\n", sps->level_idc); - pr_info(" seq_parameter_set_id: %d\n", sps->seq_parameter_set_id); - - pr_info(" log2_max_frame_num_minus4: %d\n", - sps->log2_max_frame_num_minus4); - pr_info(" pic_order_cnt_type: %d\n", sps->pic_order_cnt_type); - if (sps->pic_order_cnt_type == 0) { - pr_info(" log2_max_pic_order_cnt_lsb_minus4: %d\n", - sps->log2_max_pic_order_cnt_lsb_minus4); - } else if (sps->pic_order_cnt_type == 1) { - pr_info(" delta_pic_order_always_zero_flag: %d\n", - sps->delta_pic_order_always_zero_flag); - pr_info(" offset_for_non_ref_pic: %d\n", - sps->offset_for_non_ref_pic); - pr_info(" offset_for_top_to_bottom_field: %d\n", - sps->offset_for_top_to_bottom_field); - pr_info(" num_ref_frames_in_pic_order_cnt_cycle: %d\n", - sps->num_ref_frames_in_poc_cycle); - for (i = 0; i < sps->num_ref_frames_in_poc_cycle; ++i) { - pr_info(" offset_for_ref_frame[%d]: %d\n", i, - sps->offset_for_ref_frame[i]); - } - } - pr_info(" num_ref_frames: %d\n", sps->num_ref_frames); - pr_info(" gaps_in_frame_num_value_allowed_flag: %d\n", - sps->gaps_in_frame_num_value_allowed_flag); - pr_info(" pic_width_in_mbs_minus1: %d\n", - sps->pic_width_in_mbs_minus1); - pr_info(" pic_height_in_map_units_minus1: %d\n", - sps->pic_height_in_map_units_minus1); - pr_info(" frame_mbs_only_flag: %d\n", - sps->frame_mbs_only_flag); - pr_info(" mb_adaptive_frame_field_flag: %d\n", - sps->mb_adaptive_frame_field_flag); - pr_info(" direct_8x8_inference_flag: %d\n", - sps->direct_8x8_inference_flag); - pr_info(" frame_cropping_flag: %d\n", - sps->frame_cropping_flag); - if (sps->frame_cropping_flag) { - pr_info(" frame_crop_left_offset: %d\n", - sps->frame_crop_left_offset); - pr_info(" frame_crop_right_offset: %d\n", - sps->frame_crop_right_offset); - pr_info(" frame_crop_top_offset: %d\n", - sps->frame_crop_top_offset); - pr_info(" frame_crop_bottom_offset: %d\n", - sps->frame_crop_bottom_offset); - } - pr_info(" vui_parameters_present_flag: %d\n", - sps->vui_parameters_present_flag); - //if (sps->vui_parameters_present_flag) { - // h264_print_vui_parameters(sps->vui_parameters); - //} - - pr_info(" }\n"); -} - -void h264_pps_info(struct h264_PPS_t *pps) -{ - pr_info("pic_parameter_set {\n"); - pr_info(" pic_parameter_set_id: %d\n", - pps->pic_parameter_set_id); - pr_info(" seq_parameter_set_id: %d\n", - pps->seq_parameter_set_id); - pr_info(" entropy_coding_mode_flag: %d\n", - pps->entropy_coding_mode_flag); - pr_info(" pic_order_present_flag: %d\n", - pps->pic_order_present_flag); - pr_info(" num_slice_groups_minus1: %d\n", - pps->num_slice_groups_minus1); - // FIXME: Code for slice groups is missing here. - pr_info(" num_ref_idx_l0_active_minus1: %d\n", - pps->num_ref_idx_l0_active_minus1); - pr_info(" num_ref_idx_l1_active_minus1: %d\n", - pps->num_ref_idx_l1_active_minus1); - pr_info(" weighted_pred_flag: %d\n", pps->weighted_pred_flag); - pr_info(" weighted_bipred_idc: %d\n", pps->weighted_bipred_idc); - pr_info(" pic_init_qp_minus26: %d\n", pps->pic_init_qp_minus26); - pr_info(" pic_init_qs_minus26: %d\n", pps->pic_init_qs_minus26); - pr_info(" chroma_qp_index_offset: %d\n", - pps->chroma_qp_index_offset); - pr_info(" deblocking_filter_control_present_flag: %d\n", - pps->deblocking_filter_control_present_flag); - pr_info(" constrained_intra_pred_flag: %d\n", - pps->constrained_intra_pred_flag); - pr_info(" redundant_pic_cnt_present_flag: %d\n", - pps->redundant_pic_cnt_present_flag); - pr_info(" }\n"); -} - diff --git a/drivers/amvdec_ports/decoder/h264_parse.h b/drivers/amvdec_ports/decoder/h264_parse.h deleted file mode 100644 index e54e4d3..0000000 --- a/drivers/amvdec_ports/decoder/h264_parse.h +++ b/dev/null @@ -1,141 +0,0 @@ -/* - * drivers/amlogic/media_modules/amvdec_ports/decoder/h264_parse.h - * - * Copyright (C) 2017 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. - * - */ - -#ifndef _H264_PARSE_H -#define _H264_PARSE_H - -#include "h264_stream.h" - -enum color_model { - CM_UNKNOWN = -1, - CM_YUV = 0, - CM_RGB = 1, - CM_XYZ = 2 -}; - -enum color_format { - CF_UNKNOWN = -1, //!< Unknown color format - YUV400 = 0, //!< Monochrome - YUV420 = 1, //!< 4:2:0 - YUV422 = 2, //!< 4:2:2 - YUV444 = 3 //!< 4:4:4 -}; - -enum pixel_format { - PF_UNKNOWN = -1, //!< Unknown color ordering - UYVY = 0, //!< UYVY - YUY2 = 1, //!< YUY2 - YUYV = 1, //!< YUYV - YVYU = 2, //!< YVYU - BGR = 3, //!< BGR - V210 = 4 //!< Video Clarity 422 format (10 bits) -}; - -//AVC Profile IDC definitions -enum profile_idc{ - NO_PROFILE = 0, //!< disable profile checking for experimental coding (enables FRExt, but disables MV) - FREXT_CAVLC444 = 44, //!< YUV 4:4:4/14 "CAVLC 4:4:4" - BASELINE = 66, //!< YUV 4:2:0/8 "Baseline" - MAIN = 77, //!< YUV 4:2:0/8 "Main" - EXTENDED = 88, //!< YUV 4:2:0/8 "Extended" - FREXT_HP = 100, //!< YUV 4:2:0/8 "High" - FREXT_Hi10P = 110, //!< YUV 4:2:0/10 "High 10" - FREXT_Hi422 = 122, //!< YUV 4:2:2/10 "High 4:2:2" - FREXT_Hi444 = 244, //!< YUV 4:4:4/14 "High 4:4:4" - MVC_HIGH = 118, //!< YUV 4:2:0/8 "Multiview High" - STEREO_HIGH = 128 //!< YUV 4:2:0/8 "Stereo High" -}; - -/* sequence parameter set */ -struct h264_SPS_t { - bool vailid; - unsigned int profile_idc; - bool constrained_set0_flag; - bool constrained_set1_flag; - bool constrained_set2_flag; - bool constrained_set3_flag; - unsigned int level_idc; - unsigned int seq_parameter_set_id; - unsigned int chroma_format_idc; - bool seq_scaling_matrix_present_flag; - int seq_scaling_list_present_flag[12]; - int ScalingList4x4[6][16]; - int ScalingList8x8[6][64]; - bool UseDefaultScalingMatrix4x4Flag[6]; - bool UseDefaultScalingMatrix8x8Flag[6]; - unsigned int bit_depth_luma_minus8; - unsigned int bit_depth_chroma_minus8; - unsigned int log2_max_frame_num_minus4; - unsigned int pic_order_cnt_type; - unsigned int log2_max_pic_order_cnt_lsb_minus4; - bool delta_pic_order_always_zero_flag; - int offset_for_non_ref_pic; - int offset_for_top_to_bottom_field; - unsigned int num_ref_frames_in_poc_cycle; - int offset_for_ref_frame[255]; - int num_ref_frames; - bool gaps_in_frame_num_value_allowed_flag; - unsigned int pic_width_in_mbs_minus1; - unsigned int pic_height_in_map_units_minus1; - bool frame_mbs_only_flag; - bool mb_adaptive_frame_field_flag; - bool direct_8x8_inference_flag; - bool frame_cropping_flag; - unsigned int frame_crop_left_offset; - unsigned int frame_crop_right_offset; - unsigned int frame_crop_top_offset; - unsigned int frame_crop_bottom_offset; - bool vui_parameters_present_flag; - //h264_vui_parameters_t *vui_parameters; - unsigned separate_colour_plane_flag; - int lossless_qpprime_flag; -}; - -/* pic parameter set */ -struct h264_PPS_t { - int pic_parameter_set_id; - int seq_parameter_set_id; - int entropy_coding_mode_flag; - int pic_order_present_flag; - int num_slice_groups_minus1; - int slice_group_map_type; - int run_length_minus1; - int top_left; - int bottom_right; - int slice_group_change_direction_flag; - int slice_group_change_rate_minus1; - int pic_size_in_map_units_minus1; - int slice_group_id; - int num_ref_idx_l0_active_minus1; - int num_ref_idx_l1_active_minus1; - int weighted_pred_flag; - int weighted_bipred_idc; - int pic_init_qp_minus26; - int pic_init_qs_minus26; - int chroma_qp_index_offset; - int deblocking_filter_control_present_flag; - int constrained_intra_pred_flag; - int redundant_pic_cnt_present_flag; -}; - -void h264_sps_parse(struct h264_stream_t *s, struct h264_SPS_t *sps); -void h264_pps_parse(struct h264_stream_t *s, struct h264_PPS_t *pps); - -void h264_sps_info(struct h264_SPS_t *sps); -void h264_pps_info(struct h264_PPS_t *pps); - -#endif //_H264_PARSE_H diff --git a/drivers/amvdec_ports/decoder/h264_stream.c b/drivers/amvdec_ports/decoder/h264_stream.c deleted file mode 100644 index 3061568..0000000 --- a/drivers/amvdec_ports/decoder/h264_stream.c +++ b/dev/null @@ -1,111 +0,0 @@ -/* - * drivers/amlogic/media_modules/amvdec_ports/decoder/h264_stream.c - * - * Copyright (C) 2017 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. - * - */ - -#include <linux/mm.h> -#include <linux/slab.h> -#include "h264_stream.h" - -void h264_stream_set(struct h264_stream_t *s, unsigned char *data, int size) -{ - s->data = data; - s->size = size; - s->bit_pos = 7; - s->byte_pos = 0; -} - -unsigned int h264_stream_read_bits(struct h264_stream_t *s, unsigned int n) -{ - unsigned int ret = 0; - unsigned char b = 0; - int i; - - if (n == 0) - return 0; - - for (i = 0; i < n; ++i) { - if (h264_stream_bits_remaining(s) == 0) - ret <<= n - i - 1; - - b = s->data[s->byte_pos]; - if (n - i <= 32) - ret = ret << 1 | BITAT(b, s->bit_pos); - - if (s->bit_pos == 0) { - s->bit_pos = 7; - s->byte_pos++; - } else - s->bit_pos--; - } - - return ret; -} - -unsigned int h264_stream_peek_bits(struct h264_stream_t *s, unsigned int n) -{ - int prev_bit_pos = s->bit_pos; - int prev_byte_pos = s->byte_pos; - unsigned int ret = h264_stream_read_bits(s, n); - - s->bit_pos = prev_bit_pos; - s->byte_pos = prev_byte_pos; - - return ret; -} - -unsigned int h264_stream_read_bytes(struct h264_stream_t *s, unsigned int n) -{ - unsigned int ret = 0; - int i; - - if (n == 0) - return 0; - - for (i = 0; i < n; ++i) { - if (h264_stream_bytes_remaining(s) == 0) { - ret <<= (n - i - 1) * 8; - break; - } - - if (n - i <= 4) - ret = ret << 8 | s->data[s->byte_pos]; - - s->byte_pos++; - } - - return ret; -} - -unsigned int h264_stream_peek_bytes(struct h264_stream_t *s, unsigned int n) -{ - int prev_byte_pos = s->byte_pos; - unsigned int ret = h264_stream_read_bytes(s, n); - - s->byte_pos = prev_byte_pos; - - return ret; -} - -int h264_stream_bits_remaining(struct h264_stream_t *s) -{ - return (s->size - s->byte_pos) * 8 + s->bit_pos; -} - -int h264_stream_bytes_remaining(struct h264_stream_t *s) -{ - return s->size - s->byte_pos; -} - diff --git a/drivers/amvdec_ports/decoder/h264_stream.h b/drivers/amvdec_ports/decoder/h264_stream.h deleted file mode 100644 index d6d2eac..0000000 --- a/drivers/amvdec_ports/decoder/h264_stream.h +++ b/dev/null @@ -1,39 +0,0 @@ -/* - * drivers/amlogic/media_modules/amvdec_ports/decoder/h264_stream.h - * - * Copyright (C) 2017 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. - * - */ - -#ifndef _H264_STREAM_H -#define _H264_STREAM_H - -#include "utils.h" - -struct h264_stream_t { - unsigned char *data; - unsigned int size; - int bit_pos; - int byte_pos; -}; - -void h264_stream_set(struct h264_stream_t *s, unsigned char *data, int size); -unsigned int h264_stream_read_bits(struct h264_stream_t *s, unsigned int n); -unsigned int h264_stream_peek_bits(struct h264_stream_t *s, unsigned int n); -unsigned int h264_stream_read_bytes(struct h264_stream_t *s, unsigned int n); -unsigned int h264_stream_peek_bytes(struct h264_stream_t *s, unsigned int n); -int h264_stream_bits_remaining(struct h264_stream_t *s); -int h264_stream_bytes_remaining(struct h264_stream_t *s); - -#endif //_H264_STREAM_H - diff --git a/drivers/amvdec_ports/decoder/vdec_h264_if.c b/drivers/amvdec_ports/decoder/vdec_h264_if.c index b1e4945..cc2d880 100644 --- a/drivers/amvdec_ports/decoder/vdec_h264_if.c +++ b/drivers/amvdec_ports/decoder/vdec_h264_if.c @@ -211,11 +211,11 @@ static void get_pic_info(struct vdec_h264_inst *inst, { *pic = inst->vsi->pic; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "pic(%d, %d), buf(%d, %d)\n", pic->visible_width, pic->visible_height, pic->coded_width, pic->coded_height); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "Y(%d, %d), C(%d, %d)\n", pic->y_bs_sz, pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); } @@ -227,7 +227,7 @@ static void get_crop_info(struct vdec_h264_inst *inst, struct v4l2_rect *cr) cr->width = inst->vsi->crop.width; cr->height = inst->vsi->crop.height; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "l=%d, t=%d, w=%d, h=%d\n", cr->left, cr->top, cr->width, cr->height); } @@ -235,7 +235,7 @@ static void get_crop_info(struct vdec_h264_inst *inst, struct v4l2_rect *cr) static void get_dpb_size(struct vdec_h264_inst *inst, unsigned int *dpb_sz) { *dpb_sz = inst->vsi->dec.dpb_sz; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "sz=%d\n", *dpb_sz); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "sz=%d\n", *dpb_sz); } static void skip_aud_data(u8 **data, u32 *size) @@ -300,7 +300,7 @@ static int vdec_h264_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) if (!inst) return -ENOMEM; - inst->vdec.video_type = VFORMAT_H264; + inst->vdec.format = VFORMAT_H264; inst->vdec.dev = ctx->dev->vpu_plat_dev; inst->vdec.filp = ctx->dev->filp; inst->vdec.ctx = ctx; @@ -338,7 +338,7 @@ static int vdec_h264_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) /* alloc the header buffer to be used cache sps or spp etc.*/ inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL); - if (!inst->vsi) { + if (!inst->vsi->header_buf) { ret = -ENOMEM; goto err; } @@ -509,7 +509,7 @@ static void fill_vdec_params(struct vdec_h264_inst *inst, struct h264_SPS_t *sps vdec_config_dw_mode(pic, dw); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_BUFMGR, "The stream infos, dw: %d, coded:(%d x %d), visible:(%d x %d), DPB: %d, margin: %d\n", dw, pic->coded_width, pic->coded_height, pic->visible_width, pic->visible_height, @@ -559,7 +559,7 @@ static int vdec_search_startcode(u8 *buf, u32 range) return pos; } -static int stream_parse_by_ucode(struct vdec_h264_inst *inst, u8 *buf, u32 size) +static int parse_stream_ucode(struct vdec_h264_inst *inst, u8 *buf, u32 size) { int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; @@ -578,7 +578,27 @@ static int stream_parse_by_ucode(struct vdec_h264_inst *inst, u8 *buf, u32 size) return inst->vsi->dec.dpb_sz ? 0 : -1; } -static int stream_parse(struct vdec_h264_inst *inst, u8 *buf, u32 size) +static int parse_stream_ucode_dma(struct vdec_h264_inst *inst, + ulong buf, u32 size, u32 handle) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write_with_dma(vdec, buf, size, 0, handle); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->dec.dpb_sz ? 0 : -1; +} + +static int parse_stream_cpu(struct vdec_h264_inst *inst, u8 *buf, u32 size) { int ret = 0; struct h264_param_sets *ps; @@ -619,26 +639,38 @@ static int vdec_h264_probe(unsigned long h_vdec, { struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; - struct stream_info *st; - u8 *buf = (u8 *)bs->vaddr; + u8 *buf = (u8 *) bs->vaddr; u32 size = bs->size; int ret = 0; - st = (struct stream_info *)buf; - if (inst->ctx->is_drm_mode && (st->magic == DRMe || st->magic == DRMn)) - return 0; - - if (st->magic == NORe || st->magic == NORn) { - buf = st->data; - size = st->length; - } + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; - skip_aud_data(&buf, &size); + if ((s->magic != AML_VIDEO_MAGIC) && + (s->type != V4L_STREAM_TYPE_MATEDATA)) + return -1; - if (inst->ctx->param_sets_from_ucode) - ret = stream_parse_by_ucode(inst, buf, size); - else - ret = stream_parse(inst, buf, size); + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, s->data, s->len); + } else { + skip_aud_data((u8 **)&s->data, &s->len); + ret = parse_stream_cpu(inst, s->data, s->len); + } + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = parse_stream_ucode_dma(inst, bs->addr, size, + BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, buf, size); + } else { + skip_aud_data(&buf, &size); + ret = parse_stream_cpu(inst, buf, size); + } + } inst->vsi->cur_pic = inst->vsi->pic; @@ -699,8 +731,10 @@ static void vdec_h264_get_vf(struct vdec_h264_inst *inst, struct vdec_v4l2_buffe atomic_set(&vf->use_cnt, 1); fb = (struct vdec_v4l2_buffer *)vf->v4l_mem_handle; - fb->vf_handle = (unsigned long)vf; - fb->status = FB_ST_DISPLAY; + if (fb) { + fb->vf_handle = (unsigned long)vf; + fb->status = FB_ST_DISPLAY; + } *out = fb; @@ -805,7 +839,7 @@ static bool monitor_res_change(struct vdec_h264_inst *inst, u8 *buf, u32 size) break; if (type == NAL_H264_SPS) { - ret = stream_parse(inst, p, len); + ret = parse_stream_cpu(inst, p, len); if (ret) break; } @@ -835,9 +869,8 @@ static int vdec_h264_decode(unsigned long h_vdec, struct aml_vcodec_mem *bs, { struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; struct aml_vdec_adapt *vdec = &inst->vdec; - struct stream_info *st; - u8 *buf; - u32 size; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; int ret = -1; if (bs == NULL) @@ -846,23 +879,44 @@ static int vdec_h264_decode(unsigned long h_vdec, struct aml_vcodec_mem *bs, if (vdec_input_full(vdec)) return -EAGAIN; - buf = (u8 *)bs->vaddr; - size = bs->size; - st = (struct stream_info *)buf; - - if (inst->ctx->is_drm_mode && (st->magic == DRMe || st->magic == DRMn)) - ret = vdec_vbuf_write(vdec, st->m.buf, sizeof(st->m.drm)); - else if (st->magic == NORe) - ret = vdec_vbuf_write(vdec, st->data, st->length); - else if (st->magic == NORn) - 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 { - /*checked whether the resolution changes.*/ - if ((*res_chg = monitor_res_change(inst, buf, size))) - return 0; + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if (s->magic != AML_VIDEO_MAGIC) + return -1; + if (!inst->ctx->param_sets_from_ucode && + (s->type == V4L_STREAM_TYPE_MATEDATA)) { + if ((*res_chg = monitor_res_change(inst, + s->data, s->len))) + return 0; + } + + ret = vdec_vframe_write(vdec, + s->data, + s->len, + timestamp); + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = vdec_vframe_write_with_dma(vdec, + bs->addr, size, timestamp, + BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + int nal_idx = 0; + /* if the st compose from csd + slice that is the combine data. */ + inst->vsi->is_combine = check_frame_combine(buf, size, &nal_idx); + /*if (nal_idx < 0) + return -1;*/ + } 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); } @@ -943,6 +997,7 @@ static void set_param_ps_info(struct vdec_h264_inst *inst, struct vdec_pic_info *pic = &inst->vsi->pic; struct vdec_h264_dec_info *dec = &inst->vsi->dec; struct v4l2_rect *rect = &inst->vsi->crop; + int dw = inst->parms.cfg.double_write_mode; /* fill visible area size that be used for EGL. */ pic->visible_width = ps->visible_width; @@ -959,13 +1014,16 @@ static void set_param_ps_info(struct vdec_h264_inst *inst, pic->coded_height = ps->coded_height; pic->y_len_sz = pic->coded_width * pic->coded_height; pic->c_len_sz = pic->y_len_sz >> 1; - + pic->profile_idc = ps->profile; + pic->ref_frame_count = ps->ref_frames; dec->dpb_sz = ps->dpb_size; inst->parms.ps = *ps; inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_PSINFO; + vdec_config_dw_mode(pic, dw); + /*wake up*/ complete(&inst->comp); diff --git a/drivers/amvdec_ports/decoder/vdec_hevc_if.c b/drivers/amvdec_ports/decoder/vdec_hevc_if.c index 025d521..e47acb9 100644 --- a/drivers/amvdec_ports/decoder/vdec_hevc_if.c +++ b/drivers/amvdec_ports/decoder/vdec_hevc_if.c @@ -122,11 +122,11 @@ static void get_pic_info(struct vdec_hevc_inst *inst, { *pic = inst->vsi->pic; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "pic(%d, %d), buf(%d, %d)\n", pic->visible_width, pic->visible_height, pic->coded_width, pic->coded_height); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "Y(%d, %d), C(%d, %d)\n", pic->y_bs_sz, pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); } @@ -138,7 +138,7 @@ static void get_crop_info(struct vdec_hevc_inst *inst, struct v4l2_rect *cr) cr->width = inst->vsi->crop.width; cr->height = inst->vsi->crop.height; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "l=%d, t=%d, w=%d, h=%d\n", cr->left, cr->top, cr->width, cr->height); } @@ -146,7 +146,7 @@ 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 = inst->vsi->dec.dpb_sz; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "sz=%d\n", *dpb_sz); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "sz=%d\n", *dpb_sz); } static u32 vdec_config_default_parms(u8 *parm) @@ -206,7 +206,7 @@ static int vdec_hevc_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) if (!inst) return -ENOMEM; - inst->vdec.video_type = VFORMAT_HEVC; + inst->vdec.format = VFORMAT_HEVC; inst->vdec.dev = ctx->dev->vpu_plat_dev; inst->vdec.filp = ctx->dev->filp; inst->vdec.ctx = ctx; @@ -247,7 +247,7 @@ static int vdec_hevc_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) /* alloc the header buffer to be used cache sps or spp etc.*/ inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL); - if (!inst->vsi) { + if (!inst->vsi->header_buf) { ret = -ENOMEM; goto err; } @@ -292,7 +292,7 @@ static int refer_buffer_num(struct h265_SPS_t *sps) 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; + sps->temporal_layer[0].num_reorder_pics - 1; if (sps_pic_buf_diff >= 4) used_buf_num += 1; @@ -402,14 +402,14 @@ static void fill_vdec_params(struct vdec_hevc_inst *inst, struct h265_SPS_t *sps inst->parms.ps.dpb_size = dec->dpb_sz; inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_PSINFO; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_BUFMGR, "The stream infos, dw: %d, coded:(%d x %d), visible:(%d x %d), DPB: %d, margin: %d\n", dw, pic->coded_width, pic->coded_height, pic->visible_width, pic->visible_height, dec->dpb_sz - margin, margin); } -static int stream_parse_by_ucode(struct vdec_hevc_inst *inst, u8 *buf, u32 size) +static int parse_stream_ucode(struct vdec_hevc_inst *inst, u8 *buf, u32 size) { int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; @@ -428,7 +428,27 @@ static int stream_parse_by_ucode(struct vdec_hevc_inst *inst, u8 *buf, u32 size) return inst->vsi->dec.dpb_sz ? 0 : -1; } -static int stream_parse(struct vdec_hevc_inst *inst, u8 *buf, u32 size) +static int parse_stream_ucode_dma(struct vdec_hevc_inst *inst, + ulong buf, u32 size, u32 handle) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write_with_dma(vdec, buf, size, 0, handle); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->dec.dpb_sz ? 0 : -1; +} + +static int parse_stream_cpu(struct vdec_hevc_inst *inst, u8 *buf, u32 size) { int ret = 0; struct h265_param_sets *ps = NULL; @@ -459,22 +479,35 @@ 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->vaddr; u32 size = bs->size; int ret = 0; - st = (struct stream_info *)buf; - if (inst->ctx->is_drm_mode && (st->magic == DRMe || st->magic == DRMn)) - return 0; - - if (st->magic == NORe || st->magic == NORn) - ret = stream_parse(inst, st->data, st->length); - else { - if (inst->ctx->param_sets_from_ucode) - ret = stream_parse_by_ucode(inst, buf, size); - else - ret = stream_parse(inst, buf, size); + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if ((s->magic != AML_VIDEO_MAGIC) && + (s->type != V4L_STREAM_TYPE_MATEDATA)) + return -1; + + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, s->data, s->len); + } else { + ret = parse_stream_cpu(inst, s->data, s->len); + } + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = parse_stream_ucode_dma(inst, bs->addr, size, + BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, buf, size); + } else { + ret = parse_stream_cpu(inst, buf, size); + } } inst->vsi->cur_pic = inst->vsi->pic; @@ -577,7 +610,7 @@ static bool monitor_res_change(struct vdec_hevc_inst *inst, u8 *buf, u32 size) break; if (type == HEVC_NAL_SPS) { - ret = stream_parse(inst, p, len); + ret = parse_stream_cpu(inst, p, len); if (ret) break; } @@ -602,9 +635,8 @@ static int vdec_hevc_decode(unsigned long h_vdec, struct aml_vcodec_mem *bs, { 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; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; int ret = -1; if (bs == NULL) @@ -613,23 +645,37 @@ static int vdec_hevc_decode(unsigned long h_vdec, struct aml_vcodec_mem *bs, if (vdec_input_full(vdec)) return -EAGAIN; - buf = (u8 *)bs->vaddr; - size = bs->size; - st = (struct stream_info *)buf; - - if (inst->ctx->is_drm_mode && (st->magic == DRMe || st->magic == DRMn)) - ret = vdec_vbuf_write(vdec, st->m.buf, sizeof(st->m.drm)); - else if (st->magic == NORe) - ret = vdec_vbuf_write(vdec, st->data, st->length); - else if (st->magic == NORn) - 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 { - /*checked whether the resolution changes.*/ - if ((*res_chg = monitor_res_change(inst, buf, size))) - return 0; + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if (s->magic != AML_VIDEO_MAGIC) + return -1; + + if (!inst->ctx->param_sets_from_ucode && + (s->type == V4L_STREAM_TYPE_MATEDATA)) { + if ((*res_chg = monitor_res_change(inst, + s->data, s->len))) + return 0; + } + ret = vdec_vframe_write(vdec, + s->data, + s->len, + timestamp); + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = vdec_vframe_write_with_dma(vdec, + bs->addr, size, timestamp, + BUFF_IDX(bs, bs->index)); + } + } else { + if (!inst->ctx->param_sets_from_ucode) { + /*checked whether the resolution changes.*/ + if ((*res_chg = monitor_res_change(inst, buf, size))) + return 0; + } ret = vdec_write_nalu(inst, buf, size, timestamp); } @@ -722,8 +768,9 @@ static void set_param_ps_info(struct vdec_hevc_inst *inst, rect->height = pic->visible_height; /* config canvas size that be used for decoder. */ - pic->coded_width = ALIGN(ps->coded_width, 64); - pic->coded_height = ALIGN(ps->coded_height, 64); + + pic->coded_width = ps->coded_width; + pic->coded_height = ps->coded_height; pic->y_len_sz = pic->coded_width * pic->coded_height; pic->c_len_sz = pic->y_len_sz >> 1; diff --git a/drivers/amvdec_ports/decoder/vdec_mjpeg_if.c b/drivers/amvdec_ports/decoder/vdec_mjpeg_if.c index 6a7a4d8..c4c9fa7 100644 --- a/drivers/amvdec_ports/decoder/vdec_mjpeg_if.c +++ b/drivers/amvdec_ports/decoder/vdec_mjpeg_if.c @@ -93,6 +93,7 @@ struct vdec_mjpeg_vsi { int head_offset; struct vdec_mjpeg_dec_info dec; struct vdec_pic_info pic; + struct vdec_pic_info cur_pic; struct v4l2_rect crop; bool is_combine; int nalu_pos; @@ -111,6 +112,7 @@ struct vdec_mjpeg_inst { struct aml_vdec_adapt vdec; struct vdec_mjpeg_vsi *vsi; struct vcodec_vfm_s vfm; + struct completion comp; }; static void get_pic_info(struct vdec_mjpeg_inst *inst, @@ -118,11 +120,11 @@ static void get_pic_info(struct vdec_mjpeg_inst *inst, { *pic = inst->vsi->pic; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "pic(%d, %d), buf(%d, %d)\n", pic->visible_width, pic->visible_height, pic->coded_width, pic->coded_height); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "Y(%d, %d), C(%d, %d)\n", pic->y_bs_sz, pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); @@ -135,7 +137,7 @@ static void get_crop_info(struct vdec_mjpeg_inst *inst, struct v4l2_rect *cr) cr->width = inst->vsi->crop.width; cr->height = inst->vsi->crop.height; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "l=%d, t=%d, w=%d, h=%d\n", cr->left, cr->top, cr->width, cr->height); } @@ -143,7 +145,7 @@ static void get_crop_info(struct vdec_mjpeg_inst *inst, struct v4l2_rect *cr) static void get_dpb_size(struct vdec_mjpeg_inst *inst, unsigned int *dpb_sz) { *dpb_sz = 20;//inst->vsi->dec.dpb_sz; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "sz=%d\n", *dpb_sz); } @@ -156,7 +158,7 @@ static int vdec_mjpeg_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) if (!inst) return -ENOMEM; - inst->vdec.video_type = VFORMAT_MJPEG; + inst->vdec.format = VFORMAT_MJPEG; inst->vdec.dev = ctx->dev->vpu_plat_dev; inst->vdec.filp = ctx->dev->filp; inst->vdec.config = ctx->config; @@ -173,27 +175,32 @@ static int vdec_mjpeg_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) /* init vfm */ inst->vfm.ctx = ctx; inst->vfm.ada_ctx = &inst->vdec; - vcodec_vfm_init(&inst->vfm); + ret = vcodec_vfm_init(&inst->vfm); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "init vfm failed.\n"); + goto err; + } ret = video_decoder_init(&inst->vdec); if (ret) { v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "vdec_mjpeg init err=%d\n", ret); - goto error_free_inst; + goto err; } /* probe info from the stream */ inst->vsi = kzalloc(sizeof(struct vdec_mjpeg_vsi), GFP_KERNEL); if (!inst->vsi) { ret = -ENOMEM; - goto error_free_inst; + goto err; } /* alloc the header buffer to be used cache sps or spp etc.*/ inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL); - if (!inst->vsi) { + if (!inst->vsi->header_buf) { ret = -ENOMEM; - goto error_free_vsi; + goto err; } inst->vsi->pic.visible_width = 1920; @@ -215,10 +222,15 @@ static int vdec_mjpeg_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) return 0; -error_free_vsi: - kfree(inst->vsi); -error_free_inst: - kfree(inst); +err: + if (inst) + vcodec_vfm_release(&inst->vfm); + if (inst && inst->vsi && inst->vsi->header_buf) + kfree(inst->vsi->header_buf); + if (inst && inst->vsi) + kfree(inst->vsi); + if (inst) + kfree(inst); *h_vdec = 0; return ret; @@ -259,13 +271,52 @@ static void fill_vdec_params(struct vdec_mjpeg_inst *inst, /* calc DPB size */ dec->dpb_sz = 9;//refer_buffer_num(sps->level_idc, poc_cnt, mb_w, mb_h); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_BUFMGR, "The stream infos, coded:(%d x %d), visible:(%d x %d), DPB: %d\n", pic->coded_width, pic->coded_height, pic->visible_width, pic->visible_height, dec->dpb_sz); } -static int stream_parse(struct vdec_mjpeg_inst *inst, u8 *buf, u32 size) +static int parse_stream_ucode(struct vdec_mjpeg_inst *inst, u8 *buf, u32 size) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write(vdec, buf, size, 0); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->dec.dpb_sz ? 0 : -1; +} + +static int parse_stream_ucode_dma(struct vdec_mjpeg_inst *inst, + ulong buf, u32 size, u32 handle) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write_with_dma(vdec, buf, size, 0, handle); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->dec.dpb_sz ? 0 : -1; +} + +static int parse_stream_cpu(struct vdec_mjpeg_inst *inst, u8 *buf, u32 size) { int ret = 0; struct mjpeg_param_sets *ps = NULL; @@ -296,19 +347,38 @@ static int vdec_mjpeg_probe(unsigned long h_vdec, { struct vdec_mjpeg_inst *inst = (struct vdec_mjpeg_inst *)h_vdec; - struct stream_info *st; u8 *buf = (u8 *)bs->vaddr; u32 size = bs->size; int ret = 0; - st = (struct stream_info *)buf; - if (inst->ctx->is_drm_mode && (st->magic == DRMe || st->magic == DRMn)) - return 0; + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if ((s->magic != AML_VIDEO_MAGIC) && + (s->type != V4L_STREAM_TYPE_MATEDATA)) + return -1; + + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, s->data, s->len); + } else { + ret = parse_stream_cpu(inst, s->data, s->len); + } + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = parse_stream_ucode_dma(inst, bs->addr, size, + BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, buf, size); + } else { + ret = parse_stream_cpu(inst, buf, size); + } + } - if (st->magic == NORe || st->magic == NORn) - ret = stream_parse(inst, st->data, st->length); - else - ret = stream_parse(inst, buf, size); + inst->vsi->cur_pic = inst->vsi->pic; return ret; } @@ -393,29 +463,34 @@ static int vdec_mjpeg_decode(unsigned long h_vdec, struct aml_vcodec_mem *bs, { struct vdec_mjpeg_inst *inst = (struct vdec_mjpeg_inst *)h_vdec; struct aml_vdec_adapt *vdec = &inst->vdec; - struct stream_info *st; - u8 *buf; - u32 size; - int ret = 0; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; + int ret = -1; - /* bs NULL means flush decoder */ - if (bs == NULL) - return 0; - - buf = (u8 *)bs->vaddr; - size = bs->size; - st = (struct stream_info *)buf; - - if (inst->ctx->is_drm_mode && (st->magic == DRMe || st->magic == DRMn)) - ret = vdec_vbuf_write(vdec, st->m.buf, sizeof(st->m.drm)); - else if (st->magic == NORe) - ret = vdec_vbuf_write(vdec, st->data, st->length); - else if (st->magic == NORn) - 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 + if (vdec_input_full(vdec)) + return -EAGAIN; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if (s->magic != AML_VIDEO_MAGIC) + return -1; + + ret = vdec_vframe_write(vdec, + s->data, + s->len, + timestamp); + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = vdec_vframe_write_with_dma(vdec, + bs->addr, size, timestamp, + BUFF_IDX(bs, bs->index)); + } + } else { ret = vdec_write_nalu(inst, buf, size, timestamp); + } return ret; } diff --git a/drivers/amvdec_ports/decoder/vdec_mpeg12_if.c b/drivers/amvdec_ports/decoder/vdec_mpeg12_if.c index 89725fa..804296b 100644 --- a/drivers/amvdec_ports/decoder/vdec_mpeg12_if.c +++ b/drivers/amvdec_ports/decoder/vdec_mpeg12_if.c @@ -93,6 +93,7 @@ struct vdec_mpeg12_vsi { int head_offset; struct vdec_mpeg12_dec_info dec; struct vdec_pic_info pic; + struct vdec_pic_info cur_pic; struct v4l2_rect crop; bool is_combine; int nalu_pos; @@ -120,11 +121,11 @@ static void get_pic_info(struct vdec_mpeg12_inst *inst, { *pic = inst->vsi->pic; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "pic(%d, %d), buf(%d, %d)\n", pic->visible_width, pic->visible_height, pic->coded_width, pic->coded_height); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "Y(%d, %d), C(%d, %d)\n", pic->y_bs_sz, pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); @@ -137,7 +138,7 @@ static void get_crop_info(struct vdec_mpeg12_inst *inst, struct v4l2_rect *cr) cr->width = inst->vsi->crop.width; cr->height = inst->vsi->crop.height; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "l=%d, t=%d, w=%d, h=%d\n", cr->left, cr->top, cr->width, cr->height); } @@ -145,7 +146,7 @@ static void get_crop_info(struct vdec_mpeg12_inst *inst, struct v4l2_rect *cr) static void get_dpb_size(struct vdec_mpeg12_inst *inst, unsigned int *dpb_sz) { *dpb_sz = inst->vsi->dec.dpb_sz; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "sz=%d\n", *dpb_sz); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "sz=%d\n", *dpb_sz); } static u32 vdec_config_default_parms(u8 *parm) @@ -181,6 +182,7 @@ static void vdec_parser_parms(struct vdec_mpeg12_inst *inst) inst->parms.cfg = ctx->config.parm.dec.cfg; inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_CFGINFO; } + static int vdec_mpeg12_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) { struct vdec_mpeg12_inst *inst = NULL; @@ -190,7 +192,7 @@ static int vdec_mpeg12_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) if (!inst) return -ENOMEM; - inst->vdec.video_type = VFORMAT_MPEG12; + inst->vdec.format = VFORMAT_MPEG12; inst->vdec.dev = ctx->dev->vpu_plat_dev; inst->vdec.filp = ctx->dev->filp; inst->vdec.config = ctx->config; @@ -209,41 +211,37 @@ static int vdec_mpeg12_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) /* init vfm */ inst->vfm.ctx = ctx; inst->vfm.ada_ctx = &inst->vdec; - vcodec_vfm_init(&inst->vfm); + ret = vcodec_vfm_init(&inst->vfm); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "init vfm failed.\n"); + goto err; + } ret = video_decoder_init(&inst->vdec); if (ret) { v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "vdec_mpeg12 init err=%d\n", ret); - goto error_free_inst; + goto err; } /* probe info from the stream */ inst->vsi = kzalloc(sizeof(struct vdec_mpeg12_vsi), GFP_KERNEL); if (!inst->vsi) { ret = -ENOMEM; - goto error_free_inst; + goto err; } /* alloc the header buffer to be used cache sps or spp etc.*/ inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL); - if (!inst->vsi) { + if (!inst->vsi->header_buf) { ret = -ENOMEM; - goto error_free_vsi; + goto err; } - inst->vsi->pic.visible_width = 1920; - inst->vsi->pic.visible_height = 1080; - inst->vsi->pic.coded_width = 1920; - inst->vsi->pic.coded_height = 1088; - inst->vsi->pic.y_bs_sz = 0; - inst->vsi->pic.y_len_sz = (1920 * 1088); - inst->vsi->pic.c_bs_sz = 0; - inst->vsi->pic.c_len_sz = (1920 * 1088 / 2); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "mpeg12 Instance >> %lx\n", (ulong) inst); - + init_completion(&inst->comp); ctx->ada_ctx = &inst->vdec; *h_vdec = (unsigned long)inst; @@ -251,10 +249,15 @@ static int vdec_mpeg12_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) return 0; -error_free_vsi: - kfree(inst->vsi); -error_free_inst: - kfree(inst); +err: + if (inst) + vcodec_vfm_release(&inst->vfm); + if (inst && inst->vsi && inst->vsi->header_buf) + kfree(inst->vsi->header_buf); + if (inst && inst->vsi) + kfree(inst->vsi); + if (inst) + kfree(inst); *h_vdec = 0; return ret; @@ -284,23 +287,44 @@ static void fill_vdec_params(struct vdec_mpeg12_inst *inst, pic->y_len_sz = pic->coded_width * pic->coded_height; pic->c_len_sz = pic->y_len_sz >> 1; - /*1(EOS) + 8(DECODE_BUFFER_NUM_DEF)*/ - dec->dpb_sz = 9; + /*7(parm_v4l_buffer_margin) + 8(DECODE_BUFFER_NUM_DEF)*/ + dec->dpb_sz = 15; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_BUFMGR, "The stream infos, coded:(%d x %d), visible:(%d x %d), DPB: %d\n", pic->coded_width, pic->coded_height, pic->visible_width, pic->visible_height, dec->dpb_sz); } -static int stream_parse_by_ucode(struct vdec_mpeg12_inst *inst, u8 *buf, u32 size) +static int parse_stream_ucode(struct vdec_mpeg12_inst *inst, u8 *buf, u32 size) { int ret = 0; struct aml_vdec_adapt *vdec = &inst->vdec; ret = vdec_vframe_write(vdec, buf, size, 0); if (ret < 0) { - pr_err("write frame data failed. err: %d\n", ret); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->dec.dpb_sz ? 0 : -1; +} + +static int parse_stream_ucode_dma(struct vdec_mpeg12_inst *inst, + ulong buf, u32 size, u32 handle) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write_with_dma(vdec, buf, size, 0, handle); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); return ret; } @@ -311,7 +335,7 @@ static int stream_parse_by_ucode(struct vdec_mpeg12_inst *inst, u8 *buf, u32 siz return inst->vsi->dec.dpb_sz ? 0 : -1; } -static int stream_parse(struct vdec_mpeg12_inst *inst, u8 *buf, u32 size) +static int parse_stream_cpu(struct vdec_mpeg12_inst *inst, u8 *buf, u32 size) { int ret = 0; struct mpeg12_param_sets *ps = NULL; @@ -342,21 +366,38 @@ static int vdec_mpeg12_probe(unsigned long h_vdec, { struct vdec_mpeg12_inst *inst = (struct vdec_mpeg12_inst *)h_vdec; - struct stream_info *st; u8 *buf = (u8 *)bs->vaddr; u32 size = bs->size; int ret = 0; - st = (struct stream_info *)buf; - if (inst->ctx->is_drm_mode && (st->magic == DRMe || st->magic == DRMn)) - return 0; + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if ((s->magic != AML_VIDEO_MAGIC) && + (s->type != V4L_STREAM_TYPE_MATEDATA)) + return -1; + + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, s->data, s->len); + } else { + ret = parse_stream_cpu(inst, s->data, s->len); + } + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = parse_stream_ucode_dma(inst, bs->addr, size, + BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, buf, size); + } else { + ret = parse_stream_cpu(inst, buf, size); + } + } - if (inst->ctx->param_sets_from_ucode) - ret = stream_parse_by_ucode(inst, buf, size); - else if (st->magic == NORe || st->magic == NORn) - ret = stream_parse(inst, st->data, st->length); - else - ret = stream_parse(inst, buf, size); + inst->vsi->cur_pic = inst->vsi->pic; return ret; } @@ -441,29 +482,34 @@ static int vdec_mpeg12_decode(unsigned long h_vdec, struct aml_vcodec_mem *bs, { struct vdec_mpeg12_inst *inst = (struct vdec_mpeg12_inst *)h_vdec; struct aml_vdec_adapt *vdec = &inst->vdec; - struct stream_info *st; - u8 *buf; - u32 size; - int ret = 0; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; + int ret = -1; - /* bs NULL means flush decoder */ - if (bs == NULL) - return 0; - - buf = (u8 *)bs->vaddr; - size = bs->size; - st = (struct stream_info *)buf; - - if (inst->ctx->is_drm_mode && (st->magic == DRMe || st->magic == DRMn)) - ret = vdec_vbuf_write(vdec, st->m.buf, sizeof(st->m.drm)); - else if (st->magic == NORe) - ret = vdec_vbuf_write(vdec, st->data, st->length); - else if (st->magic == NORn) - 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 + if (vdec_input_full(vdec)) + return -EAGAIN; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if (s->magic != AML_VIDEO_MAGIC) + return -1; + + ret = vdec_vframe_write(vdec, + s->data, + s->len, + timestamp); + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = vdec_vframe_write_with_dma(vdec, + bs->addr, size, timestamp, + BUFF_IDX(bs, bs->index)); + } + } else { ret = vdec_write_nalu(inst, buf, size, timestamp); + } return ret; } @@ -538,7 +584,7 @@ static void set_param_ps_info(struct vdec_mpeg12_inst *inst, pic->y_len_sz = pic->coded_width * pic->coded_height; pic->c_len_sz = pic->y_len_sz >> 1; - dec->dpb_sz = ps->dpb_size + 1; + dec->dpb_sz = ps->dpb_size; inst->parms.ps = *ps; inst->parms.parms_status |= diff --git a/drivers/amvdec_ports/decoder/vdec_mpeg4_if.c b/drivers/amvdec_ports/decoder/vdec_mpeg4_if.c index d031c0e..660178c 100644 --- a/drivers/amvdec_ports/decoder/vdec_mpeg4_if.c +++ b/drivers/amvdec_ports/decoder/vdec_mpeg4_if.c @@ -93,6 +93,7 @@ struct vdec_mpeg4_vsi { int head_offset; struct vdec_mpeg4_dec_info dec; struct vdec_pic_info pic; + struct vdec_pic_info cur_pic; struct v4l2_rect crop; bool is_combine; int nalu_pos; @@ -111,6 +112,8 @@ struct vdec_mpeg4_inst { struct aml_vdec_adapt vdec; struct vdec_mpeg4_vsi *vsi; struct vcodec_vfm_s vfm; + struct aml_dec_params parms; + struct completion comp; }; static void get_pic_info(struct vdec_mpeg4_inst *inst, @@ -118,11 +121,11 @@ static void get_pic_info(struct vdec_mpeg4_inst *inst, { *pic = inst->vsi->pic; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "pic(%d, %d), buf(%d, %d)\n", pic->visible_width, pic->visible_height, pic->coded_width, pic->coded_height); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "Y(%d, %d), C(%d, %d)\n", pic->y_bs_sz, pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); @@ -135,17 +138,52 @@ static void get_crop_info(struct vdec_mpeg4_inst *inst, struct v4l2_rect *cr) cr->width = inst->vsi->crop.width; cr->height = inst->vsi->crop.height; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "l=%d, t=%d, w=%d, h=%d\n", cr->left, cr->top, cr->width, cr->height); } static void get_dpb_size(struct vdec_mpeg4_inst *inst, unsigned int *dpb_sz) { - *dpb_sz = 9;//inst->vsi->dec.dpb_sz; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "sz=%d\n", *dpb_sz); + *dpb_sz = inst->vsi->dec.dpb_sz; + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "sz=%d\n", *dpb_sz); +} + +static u32 vdec_config_default_parms(u8 *parm) +{ + u8 *pbuf = parm; + + pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:0;"); + pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:0;"); + + return pbuf - parm; } +static void vdec_parser_parms(struct vdec_mpeg4_inst *inst) +{ + struct aml_vcodec_ctx *ctx = inst->ctx; + + if (ctx->config.parm.dec.parms_status & + V4L2_CONFIG_PARM_DECODE_CFGINFO) { + u8 *pbuf = ctx->config.buf; + + pbuf += sprintf(pbuf, "parm_v4l_codec_enable:1;"); + pbuf += sprintf(pbuf, "parm_v4l_canvas_mem_mode:%d;", + ctx->config.parm.dec.cfg.canvas_mem_mode); + pbuf += sprintf(pbuf, "parm_v4l_buffer_margin:%d;", + ctx->config.parm.dec.cfg.ref_buf_margin); + ctx->config.length = pbuf - ctx->config.buf; + } else { + ctx->config.length = vdec_config_default_parms(ctx->config.buf); + } + + inst->vdec.config = ctx->config; + inst->parms.cfg = ctx->config.parm.dec.cfg; + inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_CFGINFO; +} + + static int vdec_mpeg4_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) { struct vdec_mpeg4_inst *inst = NULL; @@ -155,14 +193,15 @@ static int vdec_mpeg4_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) if (!inst) return -ENOMEM; - inst->vdec.video_type = VFORMAT_MPEG4; - inst->vdec.format = VIDEO_DEC_FORMAT_MPEG4_5; + inst->vdec.format = VFORMAT_MPEG4; + inst->vdec.dec_type = VIDEO_DEC_FORMAT_MPEG4_5; inst->vdec.dev = ctx->dev->vpu_plat_dev; inst->vdec.filp = ctx->dev->filp; inst->vdec.config = ctx->config; inst->vdec.ctx = ctx; inst->ctx = ctx; + vdec_parser_parms(inst); /* set play mode.*/ if (ctx->is_drm_mode) inst->vdec.port.flag |= PORT_FLAG_DRM; @@ -173,41 +212,38 @@ static int vdec_mpeg4_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) /* init vfm */ inst->vfm.ctx = ctx; inst->vfm.ada_ctx = &inst->vdec; - vcodec_vfm_init(&inst->vfm); + ret = vcodec_vfm_init(&inst->vfm); + if (ret) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "init vfm failed.\n"); + goto err; + } ret = video_decoder_init(&inst->vdec); if (ret) { v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, "vdec_mpeg4 init err=%d\n", ret); - goto error_free_inst; + goto err; } /* probe info from the stream */ inst->vsi = kzalloc(sizeof(struct vdec_mpeg4_vsi), GFP_KERNEL); if (!inst->vsi) { ret = -ENOMEM; - goto error_free_inst; + goto err; } /* alloc the header buffer to be used cache sps or spp etc.*/ inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL); - if (!inst->vsi) { + if (!inst->vsi->header_buf) { ret = -ENOMEM; - goto error_free_vsi; + goto err; } - inst->vsi->pic.visible_width = 1920; - inst->vsi->pic.visible_height = 1080; - inst->vsi->pic.coded_width = 1920; - inst->vsi->pic.coded_height = 1088; - inst->vsi->pic.y_bs_sz = 0; - inst->vsi->pic.y_len_sz = (1920 * 1088); - inst->vsi->pic.c_bs_sz = 0; - inst->vsi->pic.c_len_sz = (1920 * 1088 / 2); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "mpeg4 Instance >> %lx\n", (ulong) inst); + init_completion(&inst->comp); ctx->ada_ctx = &inst->vdec; *h_vdec = (unsigned long)inst; @@ -215,10 +251,15 @@ static int vdec_mpeg4_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) return 0; -error_free_vsi: - kfree(inst->vsi); -error_free_inst: - kfree(inst); +err: + if (inst) + vcodec_vfm_release(&inst->vfm); + if (inst && inst->vsi && inst->vsi->header_buf) + kfree(inst->vsi->header_buf); + if (inst && inst->vsi) + kfree(inst->vsi); + if (inst) + kfree(inst); *h_vdec = 0; return ret; @@ -256,16 +297,55 @@ static void fill_vdec_params(struct vdec_mpeg4_inst *inst, 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 = 9;//refer_buffer_num(sps->level_idc, poc_cnt, mb_w, mb_h); + /*8(DECODE_BUFFER_NUM_DEF) */ + dec->dpb_sz = 8; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_BUFMGR, "The stream infos, coded:(%d x %d), visible:(%d x %d), DPB: %d\n", pic->coded_width, pic->coded_height, pic->visible_width, pic->visible_height, dec->dpb_sz); } -static int stream_parse(struct vdec_mpeg4_inst *inst, u8 *buf, u32 size) +static int parse_stream_ucode(struct vdec_mpeg4_inst *inst, u8 *buf, u32 size) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write(vdec, buf, size, 0); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->dec.dpb_sz ? 0 : -1; +} + +static int parse_stream_ucode_dma(struct vdec_mpeg4_inst *inst, + ulong buf, u32 size, u32 handle) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write_with_dma(vdec, buf, size, 0, handle); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->dec.dpb_sz ? 0 : -1; +} + +static int parse_stream_cpu(struct vdec_mpeg4_inst *inst, u8 *buf, u32 size) { int ret = 0; struct mpeg4_param_sets *ps = NULL; @@ -296,19 +376,38 @@ static int vdec_mpeg4_probe(unsigned long h_vdec, { struct vdec_mpeg4_inst *inst = (struct vdec_mpeg4_inst *)h_vdec; - struct stream_info *st; u8 *buf = (u8 *)bs->vaddr; u32 size = bs->size; int ret = 0; - st = (struct stream_info *)buf; - if (inst->ctx->is_drm_mode && (st->magic == DRMe || st->magic == DRMn)) - return 0; + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if ((s->magic != AML_VIDEO_MAGIC) && + (s->type != V4L_STREAM_TYPE_MATEDATA)) + return -1; + + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, s->data, s->len); + } else { + ret = parse_stream_cpu(inst, s->data, s->len); + } + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = parse_stream_ucode_dma(inst, bs->addr, size, + BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, buf, size); + } else { + ret = parse_stream_cpu(inst, buf, size); + } + } - if (st->magic == NORe || st->magic == NORn) - ret = stream_parse(inst, st->data, st->length); - else - ret = stream_parse(inst, buf, size); + inst->vsi->cur_pic = inst->vsi->pic; return ret; } @@ -393,29 +492,34 @@ static int vdec_mpeg4_decode(unsigned long h_vdec, struct aml_vcodec_mem *bs, { struct vdec_mpeg4_inst *inst = (struct vdec_mpeg4_inst *)h_vdec; struct aml_vdec_adapt *vdec = &inst->vdec; - struct stream_info *st; - u8 *buf; - u32 size; - int ret = 0; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; + int ret = -1; - /* bs NULL means flush decoder */ - if (bs == NULL) - return 0; - - buf = (u8 *)bs->vaddr; - size = bs->size; - st = (struct stream_info *)buf; - - if (inst->ctx->is_drm_mode && (st->magic == DRMe || st->magic == DRMn)) - ret = vdec_vbuf_write(vdec, st->m.buf, sizeof(st->m.drm)); - else if (st->magic == NORe) - ret = vdec_vbuf_write(vdec, st->data, st->length); - else if (st->magic == NORn) - 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 + if (vdec_input_full(vdec)) + return -EAGAIN; + + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if (s->magic != AML_VIDEO_MAGIC) + return -1; + + ret = vdec_vframe_write(vdec, + s->data, + s->len, + timestamp); + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = vdec_vframe_write_with_dma(vdec, + bs->addr, size, timestamp, + BUFF_IDX(bs, bs->index)); + } + } else { ret = vdec_write_nalu(inst, buf, size, timestamp); + } return ret; } @@ -465,7 +569,46 @@ static int vdec_mpeg4_get_param(unsigned long h_vdec, static void set_param_ps_info(struct vdec_mpeg4_inst *inst, struct aml_vdec_ps_infos *ps) { - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "\n"); + struct vdec_pic_info *pic = &inst->vsi->pic; + struct vdec_mpeg4_dec_info *dec = &inst->vsi->dec; + struct v4l2_rect *rect = &inst->vsi->crop; + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "%s in\n", __func__); + /* fill visible area size that be used for EGL. */ + pic->visible_width = ps->visible_width; + pic->visible_height = ps->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 = ps->coded_width; + pic->coded_height = ps->coded_height; + pic->y_len_sz = pic->coded_width * pic->coded_height; + pic->c_len_sz = pic->y_len_sz >> 1; + + dec->dpb_sz = ps->dpb_size; + + inst->parms.ps = *ps; + inst->parms.parms_status |= + V4L2_CONFIG_PARM_DECODE_PSINFO; + + /*wake up*/ + complete(&inst->comp); + + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + "Parse from ucode, crop(%d x %d), coded(%d x %d) dpb: %d\n", + ps->visible_width, ps->visible_height, + ps->coded_width, ps->coded_height, + dec->dpb_sz); +} + +static void set_param_write_sync(struct vdec_mpeg4_inst *inst) +{ + complete(&inst->comp); } static int vdec_mpeg4_set_param(unsigned long h_vdec, @@ -481,6 +624,9 @@ static int vdec_mpeg4_set_param(unsigned long h_vdec, } switch (type) { + case SET_PARAM_WRITE_FRAME_SYNC: + set_param_write_sync(inst); + break; case SET_PARAM_PS_INFO: set_param_ps_info(inst, in); break; diff --git a/drivers/amvdec_ports/decoder/vdec_vp9_if.c b/drivers/amvdec_ports/decoder/vdec_vp9_if.c index 3952ae7..2cb568d 100644 --- a/drivers/amvdec_ports/decoder/vdec_vp9_if.c +++ b/drivers/amvdec_ports/decoder/vdec_vp9_if.c @@ -136,11 +136,11 @@ static void get_pic_info(struct vdec_vp9_inst *inst, { *pic = inst->vsi->pic; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "pic(%d, %d), buf(%d, %d)\n", pic->visible_width, pic->visible_height, pic->coded_width, pic->coded_height); - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "Y(%d, %d), C(%d, %d)\n", pic->y_bs_sz, pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); @@ -153,7 +153,7 @@ static void get_crop_info(struct vdec_vp9_inst *inst, struct v4l2_rect *cr) cr->width = inst->vsi->crop.width; cr->height = inst->vsi->crop.height; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "l=%d, t=%d, w=%d, h=%d\n", cr->left, cr->top, cr->width, cr->height); } @@ -161,7 +161,7 @@ static void get_crop_info(struct vdec_vp9_inst *inst, struct v4l2_rect *cr) static void get_dpb_size(struct vdec_vp9_inst *inst, unsigned int *dpb_sz) { *dpb_sz = inst->vsi->dec.dpb_sz; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, "sz=%d\n", *dpb_sz); + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_EXINFO, "sz=%d\n", *dpb_sz); } static u32 vdec_config_default_parms(u8 *parm) @@ -261,7 +261,7 @@ static int vdec_vp9_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) if (!inst) return -ENOMEM; - inst->vdec.video_type = VFORMAT_VP9; + inst->vdec.format = VFORMAT_VP9; inst->vdec.dev = ctx->dev->vpu_plat_dev; inst->vdec.filp = ctx->dev->filp; inst->vdec.ctx = ctx; @@ -295,7 +295,7 @@ static int vdec_vp9_init(struct aml_vcodec_ctx *ctx, unsigned long *h_vdec) /* alloc the header buffer to be used cache sps or spp etc.*/ inst->vsi->header_buf = kzalloc(HEADER_BUFFER_SIZE, GFP_KERNEL); - if (!inst->vsi) { + if (!inst->vsi->header_buf) { ret = -ENOMEM; goto err; } @@ -432,14 +432,14 @@ static void fill_vdec_params(struct vdec_vp9_inst *inst, inst->parms.ps.dpb_size = dec->dpb_sz; inst->parms.parms_status |= V4L2_CONFIG_PARM_DECODE_PSINFO; - v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_PRINFO, + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_BUFMGR, "The stream infos, dw: %d, coded:(%d x %d), visible:(%d x %d), DPB: %d, margin: %d\n", dw, pic->coded_width, pic->coded_height, pic->visible_width, pic->visible_height, dec->dpb_sz - margin, margin); } -static int stream_parse_by_ucode(struct vdec_vp9_inst *inst, u8 *buf, u32 size) +static int parse_stream_ucode(struct vdec_vp9_inst *inst, u8 *buf, u32 size) { int ret = 0; @@ -457,7 +457,27 @@ static int stream_parse_by_ucode(struct vdec_vp9_inst *inst, u8 *buf, u32 size) return inst->vsi->dec.dpb_sz ? 0 : -1; } -static int stream_parse(struct vdec_vp9_inst *inst, u8 *buf, u32 size) +static int parse_stream_ucode_dma(struct vdec_vp9_inst *inst, + ulong buf, u32 size, u32 handle) +{ + int ret = 0; + struct aml_vdec_adapt *vdec = &inst->vdec; + + ret = vdec_vframe_write_with_dma(vdec, buf, size, 0, handle); + if (ret < 0) { + v4l_dbg(inst->ctx, V4L_DEBUG_CODEC_ERROR, + "write frame data failed. err: %d\n", ret); + return ret; + } + + /* wait ucode parse ending. */ + wait_for_completion_timeout(&inst->comp, + msecs_to_jiffies(1000)); + + return inst->vsi->dec.dpb_sz ? 0 : -1; +} + +static int parse_stream_cpu(struct vdec_vp9_inst *inst, u8 *buf, u32 size) { int ret = 0; struct vp9_param_sets *ps = NULL; @@ -488,22 +508,35 @@ static int vdec_vp9_probe(unsigned long h_vdec, { struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; - struct stream_info *st; u8 *buf = (u8 *)bs->vaddr; u32 size = bs->size; int ret = 0; - st = (struct stream_info *)buf; - if (inst->ctx->is_drm_mode && (st->magic == DRMe || st->magic == DRMn)) - return 0; - - if (st->magic == NORe || st->magic == NORn) - ret = stream_parse(inst, st->data, st->length); - else { - if (inst->ctx->param_sets_from_ucode) - ret = stream_parse_by_ucode(inst, buf, size); - else - ret = stream_parse(inst, buf, size); + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if ((s->magic != AML_VIDEO_MAGIC) && + (s->type != V4L_STREAM_TYPE_MATEDATA)) + return -1; + + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, s->data, s->len); + } else { + ret = parse_stream_cpu(inst, s->data, s->len); + } + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = parse_stream_ucode_dma(inst, bs->addr, size, + BUFF_IDX(bs, bs->index)); + } + } else { + if (inst->ctx->param_sets_from_ucode) { + ret = parse_stream_ucode(inst, buf, size); + } else { + ret = parse_stream_cpu(inst, buf, size); + } } inst->vsi->cur_pic = inst->vsi->pic; @@ -698,7 +731,7 @@ static bool monitor_res_change(struct vdec_vp9_inst *inst, u8 *buf, u32 size) ((p[17] << 16) | (p[18] << 8) | p[19]); if (synccode == SYNC_CODE) { - ret = stream_parse(inst, p, len); + ret = parse_stream_cpu(inst, p, len); if (!ret && (inst->vsi->cur_pic.coded_width != inst->vsi->pic.coded_width || inst->vsi->cur_pic.coded_height != @@ -716,9 +749,8 @@ static int vdec_vp9_decode(unsigned long h_vdec, struct aml_vcodec_mem *bs, { struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; struct aml_vdec_adapt *vdec = &inst->vdec; - struct stream_info *st; - u8 *buf; - u32 size; + u8 *buf = (u8 *) bs->vaddr; + u32 size = bs->size; int ret = -1; if (bs == NULL) @@ -729,21 +761,35 @@ static int vdec_vp9_decode(unsigned long h_vdec, struct aml_vcodec_mem *bs, return -EAGAIN; } - buf = (u8 *)bs->vaddr; - size = bs->size; - st = (struct stream_info *)buf; - - if (inst->ctx->is_drm_mode && (st->magic == DRMe || st->magic == DRMn)) - ret = vdec_vbuf_write(vdec, st->m.buf, sizeof(st->m.drm)); - else if (st->magic == NORe) - ret = vdec_vbuf_write(vdec, st->data, st->length); - else if (st->magic == NORn) - 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 { + if (inst->ctx->is_drm_mode) { + if (bs->model == VB2_MEMORY_MMAP) { + struct aml_video_stream *s = + (struct aml_video_stream *) buf; + + if (s->magic != AML_VIDEO_MAGIC) + return -1; + + if (!inst->ctx->param_sets_from_ucode && + (s->type == V4L_STREAM_TYPE_MATEDATA)) { + if ((*res_chg = monitor_res_change(inst, + s->data, s->len))) + return 0; + } + + ret = vdec_vframe_write(vdec, + s->data, + s->len, + timestamp); + } else if (bs->model == VB2_MEMORY_DMABUF || + bs->model == VB2_MEMORY_USERPTR) { + ret = vdec_vframe_write_with_dma(vdec, + bs->addr, size, timestamp, + BUFF_IDX(bs, bs->index)); + } + } else { /*checked whether the resolution changes.*/ - if ((*res_chg = monitor_res_change(inst, buf, size))) + if ((!inst->ctx->param_sets_from_ucode) && + (*res_chg = monitor_res_change(inst, buf, size))) return 0; ret = vdec_write_nalu(inst, buf, size, timestamp); @@ -846,7 +892,7 @@ static void set_param_ps_info(struct vdec_vp9_inst *inst, pic->c_len_sz = pic->y_len_sz >> 1; /* calc DPB size */ - dec->dpb_sz = 5; + dec->dpb_sz = ps->dpb_size; inst->parms.ps = *ps; inst->parms.parms_status |= diff --git a/drivers/amvdec_ports/vdec_drv_if.c b/drivers/amvdec_ports/vdec_drv_if.c index 96b0c93..e870da4 100644 --- a/drivers/amvdec_ports/vdec_drv_if.c +++ b/drivers/amvdec_ports/vdec_drv_if.c @@ -82,7 +82,7 @@ int vdec_if_decode(struct aml_vcodec_ctx *ctx, struct aml_vcodec_mem *bs, int ret = 0; if (bs) { - if ((bs->dma_addr & 63) != 0) { + if ((bs->addr & 63) != 0) { v4l_dbg(ctx, V4L_DEBUG_CODEC_ERROR, "bs dma_addr should 64 byte align\n"); return -EINVAL; diff --git a/drivers/amvdec_ports/vdec_drv_if.h b/drivers/amvdec_ports/vdec_drv_if.h index d3ccef2..a5ab735 100644 --- a/drivers/amvdec_ports/vdec_drv_if.h +++ b/drivers/amvdec_ports/vdec_drv_if.h @@ -25,19 +25,26 @@ #include "aml_vcodec_util.h" #include "../stream_input/parser/streambuf.h" -#define NORe CODEC_MODE('N', 'O', 'R', 'e') // normal es -#define NORn CODEC_MODE('N', 'O', 'R', 'n') // normal nalu -#define DRMe CODEC_MODE('D', 'R', 'M', 'e') // drm es -#define DRMn CODEC_MODE('D', 'R', 'M', 'n') // drm nalu +#define AML_VIDEO_MAGIC CODEC_MODE('A', 'M', 'L', 'V') + +#define V4L_STREAM_TYPE_MATEDATA (0) +#define V4L_STREAM_TYPE_FRAME (1) struct stream_info { + u32 stream_width; + u32 stream_height; + u32 stream_field; + u32 stream_dpb; +}; + +struct aml_video_stream { u32 magic; u32 type; union { - struct drm_info drm; - u8 buf[128]; + struct stream_info s; + u8 buf[64]; } m; - u32 length; + u32 len; u8 data[0]; }; diff --git a/drivers/frame_provider/decoder/h264_multi/vmh264.c b/drivers/frame_provider/decoder/h264_multi/vmh264.c index a850134..2cef4da 100644 --- a/drivers/frame_provider/decoder/h264_multi/vmh264.c +++ b/drivers/frame_provider/decoder/h264_multi/vmh264.c @@ -874,6 +874,7 @@ struct vdec_h264_hw_s { unsigned int last_picture_slice_count; unsigned int first_pre_frame_num; #endif + unsigned int res_ch_flag; }; static u32 again_threshold; @@ -2609,6 +2610,8 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame) struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; struct vframe_s *vf = NULL; int buffer_index = frame->buf_spec_num; + struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + ulong nv_order = VIDTYPE_VIU_NV21; int vf_count = 1; int i; int bForceInterlace = 0; @@ -2619,6 +2622,14 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame) __func__, buffer_index); return -1; } + + /* swap uv */ + if (hw->is_used_v4l) { + if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || + (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M)) + nv_order = VIDTYPE_VIU_NV12; + } + if (force_disp_bufspec_num & 0x100) { /*recycle directly*/ if (hw->buffer_spec[frame->buf_spec_num].used != 3 && @@ -2780,7 +2791,7 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame) if (hw->double_write_mode) { vf->type |= VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; - vf->type |= VIDTYPE_VIU_NV21; + vf->type |= nv_order; if (hw->double_write_mode == 3) vf->type |= VIDTYPE_COMPRESS; @@ -2813,7 +2824,7 @@ int prepare_display_buf(struct vdec_s *vdec, struct FrameStore *frame) vf->compHeight = hw->frame_height; } else { vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD | - VIDTYPE_VIU_NV21; + nv_order; vf->canvas0Addr = vf->canvas1Addr = spec2canvas(&hw->buffer_spec[buffer_index]); @@ -3827,10 +3838,19 @@ static struct vframe_s *vh264_vf_get(void *op_arg) struct vframe_s *vf; struct vdec_s *vdec = op_arg; struct vdec_h264_hw_s *hw = (struct vdec_h264_hw_s *)vdec->private; + struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + ulong nv_order = VIDTYPE_VIU_NV21; if (!hw) return NULL; + /* swap uv */ + if (hw->is_used_v4l) { + if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || + (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M)) + nv_order = VIDTYPE_VIU_NV12; + } + if (force_disp_bufspec_num & 0x100) { int buffer_index = force_disp_bufspec_num & 0xff; if (force_disp_bufspec_num & 0x200) @@ -3861,7 +3881,7 @@ static struct vframe_s *vh264_vf_get(void *op_arg) if (hw->double_write_mode) { vf->type |= VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; - vf->type |= VIDTYPE_VIU_NV21; + vf->type |= nv_order; if (hw->double_write_mode == 3) vf->type |= VIDTYPE_COMPRESS; @@ -3899,7 +3919,7 @@ static struct vframe_s *vh264_vf_get(void *op_arg) } } else { vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD | - VIDTYPE_VIU_NV21; + nv_order; vf->canvas0Addr = vf->canvas1Addr = spec2canvas(&hw->buffer_spec[buffer_index]); } @@ -5767,17 +5787,6 @@ static irqreturn_t vh264_isr_thread_fn(struct vdec_s *vdec, int irq) unsigned short *p = (unsigned short *)hw->lmem_addr; reset_process_time(hw); - if (hw->is_used_v4l) { - struct aml_vcodec_ctx *ctx = - (struct aml_vcodec_ctx *)(hw->v4l2_ctx); - - if (ctx->param_sets_from_ucode && !ctx->v4l_codec_ready) { - //amvdec_stop(); - hw->dec_result = DEC_RESULT_DONE; - vdec_schedule_work(&hw->work); - return IRQ_HANDLED; - } - } #ifdef DETECT_WRONG_MULTI_SLICE hw->cur_picture_slice_count++; if (hw->multi_slice_pic_flag == 1 && @@ -6765,7 +6774,8 @@ static void check_timer_func(struct timer_list *timer) return; } - if (vdec->next_status == VDEC_STATUS_DISCONNECTED) { + if (vdec->next_status == VDEC_STATUS_DISCONNECTED && + !hw->is_used_v4l) { hw->dec_result = DEC_RESULT_FORCE_EXIT; vdec_schedule_work(&hw->work); pr_debug("vdec requested to be disconnected\n"); @@ -6937,6 +6947,8 @@ static int vh264_hw_ctx_restore(struct vdec_h264_hw_s *hw) && (v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21 || v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21M)) SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); + else + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); SET_VREG_MASK(MDEC_PIC_DC_CTRL, 0xbf << 24); CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 0xbf << 24); @@ -8087,6 +8099,117 @@ static void vmh264_wakeup_userdata_poll(struct vdec_s *vdec) #endif +static int vmh264_get_ps_info(struct vdec_h264_hw_s *hw, u32 param1, u32 param4, struct aml_vdec_ps_infos *ps) +{ + struct vdec_s *vdec = hw_to_vdec(hw); + int mb_width, mb_total; + int mb_height = 0; + int active_buffer_spec_num; + int max_reference_size ,level_idc; + unsigned int used_reorder_dpb_size_margin + = hw->reorder_dpb_size_margin; + int reorder_pic_num; + + level_idc = param4 & 0xff; + max_reference_size = (param4 >> 8) & 0xff; + +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + if (vdec->master || vdec->slave) + used_reorder_dpb_size_margin = + reorder_dpb_size_margin_dv; +#endif + mb_width = param1 & 0xff; + mb_total = (param1 >> 8) & 0xffff; + if (!mb_width && mb_total) /*for 4k2k*/ + mb_width = 256; + if (mb_width) + mb_height = mb_total/mb_width; + if (mb_width <= 0 || mb_height <= 0 || + is_oversize(mb_width << 4, mb_height << 4)) { + dpb_print(DECODE_ID(hw), 0, + "!!!wrong param1 0x%x mb_width/mb_height (0x%x/0x%x) %x\r\n", + param1, + mb_width, + mb_height); + return -1; + } + + reorder_pic_num = + get_max_dec_frame_buf_size(level_idc, + max_reference_size, mb_width, mb_height); + + if ((hw->bitstream_restriction_flag) && + (hw->max_dec_frame_buffering < + reorder_pic_num)) { + reorder_pic_num = hw->max_dec_frame_buffering; + dpb_print(DECODE_ID(hw), 0, + "set reorder_pic_num to %d\n", + reorder_pic_num); + } + + active_buffer_spec_num = + reorder_pic_num + + used_reorder_dpb_size_margin; + + if (active_buffer_spec_num > MAX_VF_BUF_NUM) { + active_buffer_spec_num = MAX_VF_BUF_NUM; + reorder_pic_num = active_buffer_spec_num + - used_reorder_dpb_size_margin; + } + + if (hw->no_poc_reorder_flag) + reorder_pic_num = 1; + + ps->profile = level_idc; + ps->ref_frames = max_reference_size; + ps->mb_width = mb_width; + ps->mb_height = mb_height; + ps->visible_width = mb_width << 4; + ps->visible_height = mb_height << 4; + ps->coded_width = ALIGN(mb_width << 4, 64); + ps->coded_height = ALIGN(mb_height << 4, 64); + ps->reorder_frames = reorder_pic_num; + ps->dpb_size = active_buffer_spec_num; + + return 0; +} + +static int v4l_res_change(struct vdec_h264_hw_s *hw, u32 param1, u32 param4) +{ + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + int ret = 0; + + if (ctx->param_sets_from_ucode && + hw->res_ch_flag == 0) { + if (param1 != 0 && + hw->seq_info2 != (param1 & (~0x80000000)) && + hw->seq_info2 != 0) /*picture size changed*/ { + struct aml_vdec_ps_infos ps; + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, "h264 res_change\n"); + if (vmh264_get_ps_info(hw, param1, param4, &ps) < 0) { + dpb_print(DECODE_ID(hw), 0, "set parameters error\n"); + } + hw->v4l_params_parsed = false; + vdec_v4l_set_ps_infos(ctx, &ps); + vdec_v4l_res_ch_event(ctx); + hw->res_ch_flag = 1; + amvdec_stop(); + if (hw->mmu_enable) + amhevc_stop(); + hw->eos = 1; + flush_dpb(p_H264_Dpb); + //del_timer_sync(&hw->check_timer); + if (hw->is_used_v4l) + notify_v4l_eos(hw_to_vdec(hw)); + ret = 1; + } + } + + return ret; + +} static void vh264_work_implement(struct vdec_h264_hw_s *hw, struct vdec_s *vdec, int from) @@ -8112,34 +8235,48 @@ static void vh264_work_implement(struct vdec_h264_hw_s *hw, u32 param2 = READ_VREG(AV_SCRATCH_2); u32 param3 = READ_VREG(AV_SCRATCH_6); u32 param4 = READ_VREG(AV_SCRATCH_B); - - if (vh264_set_params(hw, param1, - param2, param3, param4) < 0) - dpb_print(DECODE_ID(hw), 0, "set parameters error\n"); - - WRITE_VREG(AV_SCRATCH_0, (hw->max_reference_size<<24) | - (hw->dpb.mDPB.size<<16) | - (hw->dpb.mDPB.size<<8)); - - if (hw->is_used_v4l) { - struct aml_vcodec_ctx *ctx = + struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); - if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) { - struct aml_vdec_ps_infos ps; - - ps.visible_width = hw->frame_width; - ps.visible_height = hw->frame_height; - ps.coded_width = ALIGN(hw->frame_width, 64); - ps.coded_height = ALIGN(hw->frame_height, 64); - ps.dpb_size = hw->dpb.mDPB.size; - hw->v4l_params_parsed = true; - vdec_v4l_set_ps_infos(ctx, &ps); + if (hw->is_used_v4l && + ctx->param_sets_from_ucode) { + if (!v4l_res_change(hw, param1, param4)) { + if (!hw->v4l_params_parsed) { + struct aml_vdec_ps_infos ps; + dpb_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, "h264 parsered csd data\n"); + if (vmh264_get_ps_info(hw, param1, param4, &ps) < 0) { + dpb_print(DECODE_ID(hw), 0, "set parameters error\n"); + } + hw->v4l_params_parsed = true; + vdec_v4l_set_ps_infos(ctx, &ps); + amvdec_stop(); + if (hw->mmu_enable) + amhevc_stop(); + } + else { + if (vh264_set_params(hw, param1, + param2, param3, param4) < 0) + dpb_print(DECODE_ID(hw), 0, "set parameters error\n"); + + WRITE_VREG(AV_SCRATCH_0, (hw->max_reference_size<<24) | + (hw->dpb.mDPB.size<<16) | + (hw->dpb.mDPB.size<<8)); + hw->res_ch_flag = 0; + start_process_time(hw); + return; + } } - } + } else { + if (vh264_set_params(hw, param1, + param2, param3, param4) < 0) + dpb_print(DECODE_ID(hw), 0, "set parameters error\n"); - start_process_time(hw); - return; + WRITE_VREG(AV_SCRATCH_0, (hw->max_reference_size<<24) | + (hw->dpb.mDPB.size<<16) | + (hw->dpb.mDPB.size<<8)); + start_process_time(hw); + return; + } } else if (((hw->dec_result == DEC_RESULT_GET_DATA) || (hw->dec_result == DEC_RESULT_GET_DATA_RETRY)) @@ -8520,10 +8657,18 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); - if (ctx->param_sets_from_ucode && - !ctx->v4l_codec_ready && - hw->v4l_params_parsed) { - ret = 0; /*the params has parsed.*/ + if (ctx->param_sets_from_ucode) { + if (hw->v4l_params_parsed) { + if (!ctx->v4l_codec_dpb_ready && + v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < + run_ready_min_buf_num) + ret = 0; + } else { + if ((hw->res_ch_flag == 1) && + ((ctx->state <= AML_STATE_INIT) || + (ctx->state >= AML_STATE_FLUSHING))) + ret = 0; + } } else if (!ctx->v4l_codec_dpb_ready) { if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < run_ready_min_buf_num) diff --git a/drivers/frame_provider/decoder/h265/vh265.c b/drivers/frame_provider/decoder/h265/vh265.c index 4edefe1..790cc9a 100644 --- a/drivers/frame_provider/decoder/h265/vh265.c +++ b/drivers/frame_provider/decoder/h265/vh265.c @@ -1740,6 +1740,7 @@ struct hevc_state_s { bool v4l_params_parsed; u32 mem_map_mode; struct vdec_info *gvs; + unsigned int res_ch_flag; } /*hevc_stru_t */; #ifdef AGAIN_HAS_THRESHOLD @@ -1951,6 +1952,31 @@ static int get_double_write_mode(struct hevc_state_s *hevc) return dw; } +static int v4l_parser_get_double_write_mode(struct hevc_state_s *hevc, int w, int h) +{ + u32 valid_dw_mode = get_valid_double_write_mode(hevc); + u32 dw = 0x1; /*1:1*/ + switch (valid_dw_mode) { + case 0x100: + if (w > 1920 && h > 1088) + dw = 0x4; /*1:2*/ + break; + case 0x200: + if (w > 1920 && h > 1088) + dw = 0x2; /*1:4*/ + break; + case 0x300: + if (w > 1280 && h > 720) + dw = 0x4; /*1:2*/ + break; + default: + dw = valid_dw_mode; + break; + } + return dw; +} + + static int get_double_write_ratio(struct hevc_state_s *hevc, int dw_mode) { @@ -3286,7 +3312,57 @@ static int get_work_pic_num(struct hevc_state_s *hevc) sps_pic_buf_diff = hevc->param.p.sps_max_dec_pic_buffering_minus1_0 - hevc->sps_num_reorder_pics_0; +#ifdef MULTI_INSTANCE_SUPPORT + /* + need one more for multi instance, as + apply_ref_pic_set() has no chanch to run to + to clear referenced flag in some case + */ + if (hevc->m_ins_flag) + used_buf_num++; +#endif + } else + used_buf_num = max_buf_num; + + if (hevc->save_buffer_mode) + hevc_print(hevc, 0, + "save buf _mode : dynamic_buf_num_margin %d ----> %d \n", + dynamic_buf_num_margin, hevc->dynamic_buf_num_margin); + + if (sps_pic_buf_diff >= 4) + used_buf_num += sps_pic_buf_diff; + + if (hevc->is_used_v4l) { + /* for eos add more buffer to flush.*/ + used_buf_num++; + } + + if (used_buf_num > MAX_BUF_NUM) + used_buf_num = MAX_BUF_NUM; + return used_buf_num; +} + +static int v4l_parser_work_pic_num(struct hevc_state_s *hevc) +{ + int used_buf_num = 0; + int sps_pic_buf_diff = 0; + pr_debug("margin = %d, sps_max_dec_pic_buffering_minus1_0 = %d, sps_num_reorder_pics_0 = %d\n", + get_dynamic_buf_num_margin(hevc), + hevc->param.p.sps_max_dec_pic_buffering_minus1_0, + hevc->param.p.sps_num_reorder_pics_0); + if (get_dynamic_buf_num_margin(hevc) > 0) { + if ((!hevc->param.p.sps_num_reorder_pics_0) && + (hevc->param.p.sps_max_dec_pic_buffering_minus1_0)) { + /* the range of sps_num_reorder_pics_0 is in + [0, sps_max_dec_pic_buffering_minus1_0] */ + used_buf_num = get_dynamic_buf_num_margin(hevc) + + hevc->param.p.sps_max_dec_pic_buffering_minus1_0; + } else + used_buf_num = hevc->param.p.sps_num_reorder_pics_0 + + get_dynamic_buf_num_margin(hevc); + sps_pic_buf_diff = hevc->param.p.sps_max_dec_pic_buffering_minus1_0 + - hevc->param.p.sps_num_reorder_pics_0; #ifdef MULTI_INSTANCE_SUPPORT /* need one more for multi instance, as @@ -3309,6 +3385,9 @@ static int get_work_pic_num(struct hevc_state_s *hevc) used_buf_num += 1; } + /* for eos add more buffer to flush.*/ + used_buf_num++; + if (used_buf_num > MAX_BUF_NUM) used_buf_num = MAX_BUF_NUM; return used_buf_num; @@ -5268,8 +5347,8 @@ static void config_sao_hw(struct hevc_state_s *hevc, union param_u *params) /* swap uv */ if (hevc->is_used_v4l) { - if ((v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21) || - (v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21M)) + if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV21) || + (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV21M)) data32 &= ~(1 << 8); /* NV21 */ else data32 |= (1 << 8); /* NV12 */ @@ -5311,8 +5390,8 @@ static void config_sao_hw(struct hevc_state_s *hevc, union param_u *params) /* swap uv */ if (hevc->is_used_v4l) { - if ((v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21) || - (v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21M)) + if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV21) || + (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV21M)) data32 |= (1 << 12); /* NV21 */ else data32 &= ~(1 << 12); /* NV12 */ @@ -6693,6 +6772,11 @@ static int hevc_slice_segment_header_process(struct hevc_state_s *hevc, int lcu_y_num_div; int Col_ref; int dbg_skip_flag = 0; + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hevc->v4l2_ctx); + + if (hevc->is_used_v4l && ctx->param_sets_from_ucode) + hevc->res_ch_flag = 0; if (hevc->wait_buf == 0) { hevc->sps_num_reorder_pics_0 = @@ -8549,7 +8633,16 @@ static int prepare_display_buf(struct hevc_state_s *hevc, struct PIC_s *pic) struct vframe_s *vf = NULL; int stream_offset = pic->stream_offset; unsigned short slice_type = pic->slice_type; + ulong nv_order = VIDTYPE_VIU_NV21; u32 frame_size = 0; + struct aml_vcodec_ctx * v4l2_ctx = hevc->v4l2_ctx; + + /* swap uv */ + if (hevc->is_used_v4l) { + if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || + (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M)) + nv_order = VIDTYPE_VIU_NV12; + } if (force_disp_pic_index & 0x100) { /*recycle directly*/ @@ -8709,7 +8802,8 @@ static int prepare_display_buf(struct hevc_state_s *hevc, struct PIC_s *pic) } if (pic->double_write_mode) { vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; - vf->type |= VIDTYPE_VIU_NV21; + vf->type |= nv_order; + if ((pic->double_write_mode == 3) && (!(IS_8K_SIZE(pic->width, pic->height)))) { vf->type |= VIDTYPE_COMPRESS; @@ -8774,7 +8868,7 @@ static int prepare_display_buf(struct hevc_state_s *hevc, struct PIC_s *pic) vf->bitdepth |= BITDEPTH_SAVING_MODE; #else vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; - vf->type |= VIDTYPE_VIU_NV21; + vf->type |= nv_order; vf->canvas0Addr = vf->canvas1Addr = spec2canvas(pic); #endif set_frame_info(hevc, vf, pic); @@ -8875,14 +8969,14 @@ static int prepare_display_buf(struct hevc_state_s *hevc, struct PIC_s *pic) if (pic->pic_struct == 3) { vf->type = VIDTYPE_INTERLACE_TOP - | VIDTYPE_VIU_NV21; + | nv_order; vf2->type = VIDTYPE_INTERLACE_BOTTOM - | VIDTYPE_VIU_NV21; + | nv_order; } else { vf->type = VIDTYPE_INTERLACE_BOTTOM - | VIDTYPE_VIU_NV21; + | nv_order; vf2->type = VIDTYPE_INTERLACE_TOP - | VIDTYPE_VIU_NV21; + | nv_order; } hevc->vf_pre_count++; decoder_do_frame_check(vdec, vf); @@ -8920,18 +9014,18 @@ static int prepare_display_buf(struct hevc_state_s *hevc, struct PIC_s *pic) if (pic->pic_struct == 5) { vf->type = VIDTYPE_INTERLACE_TOP - | VIDTYPE_VIU_NV21; + | nv_order; vf2->type = VIDTYPE_INTERLACE_BOTTOM - | VIDTYPE_VIU_NV21; + | nv_order; vf3->type = VIDTYPE_INTERLACE_TOP - | VIDTYPE_VIU_NV21; + | nv_order; } else { vf->type = VIDTYPE_INTERLACE_BOTTOM - | VIDTYPE_VIU_NV21; + | nv_order; vf2->type = VIDTYPE_INTERLACE_TOP - | VIDTYPE_VIU_NV21; + | nv_order; vf3->type = VIDTYPE_INTERLACE_BOTTOM - | VIDTYPE_VIU_NV21; + | nv_order; } hevc->vf_pre_count++; decoder_do_frame_check(vdec, vf); @@ -8967,12 +9061,12 @@ static int prepare_display_buf(struct hevc_state_s *hevc, struct PIC_s *pic) vf->height <<= 1; if (pic->pic_struct == 9) { vf->type = VIDTYPE_INTERLACE_TOP - | VIDTYPE_VIU_NV21 | VIDTYPE_VIU_FIELD; + | nv_order | VIDTYPE_VIU_FIELD; process_pending_vframe(hevc, hevc->pre_bot_pic, 0); } else { vf->type = VIDTYPE_INTERLACE_BOTTOM | - VIDTYPE_VIU_NV21 | VIDTYPE_VIU_FIELD; + nv_order | VIDTYPE_VIU_FIELD; vf->index = (pic->index << 8) | 0xff; process_pending_vframe(hevc, hevc->pre_top_pic, 1); @@ -9003,10 +9097,10 @@ static int prepare_display_buf(struct hevc_state_s *hevc, struct PIC_s *pic) vf->height <<= 1; if (pic->pic_struct == 11) vf->type = VIDTYPE_INTERLACE_TOP | - VIDTYPE_VIU_NV21 | VIDTYPE_VIU_FIELD; + nv_order | VIDTYPE_VIU_FIELD; else { vf->type = VIDTYPE_INTERLACE_BOTTOM | - VIDTYPE_VIU_NV21 | VIDTYPE_VIU_FIELD; + nv_order | VIDTYPE_VIU_FIELD; vf->index = (pic->index << 8) | 0xff; } decoder_do_frame_check(vdec, vf); @@ -9040,14 +9134,14 @@ static int prepare_display_buf(struct hevc_state_s *hevc, struct PIC_s *pic) case 1: vf->height <<= 1; vf->type = VIDTYPE_INTERLACE_TOP | - VIDTYPE_VIU_NV21 | VIDTYPE_VIU_FIELD; + nv_order | VIDTYPE_VIU_FIELD; process_pending_vframe(hevc, pic, 1); hevc->pre_top_pic = pic; break; case 2: vf->height <<= 1; vf->type = VIDTYPE_INTERLACE_BOTTOM - | VIDTYPE_VIU_NV21 + | nv_order | VIDTYPE_VIU_FIELD; process_pending_vframe(hevc, pic, 0); hevc->pre_bot_pic = pic; @@ -9468,6 +9562,59 @@ static void read_decode_info(struct hevc_state_s *hevc) hevc->rps_set_id = (decode_info >> 8) & 0xff; } +static int vh265_get_ps_info(struct hevc_state_s *hevc, int width, int height, struct aml_vdec_ps_infos *ps) +{ + int dw_mode = v4l_parser_get_double_write_mode(hevc, width, height); + + ps->visible_width = width / get_double_write_ratio(hevc, dw_mode); + ps->visible_height = height / get_double_write_ratio(hevc, dw_mode); + ps->coded_width = ALIGN(width, 32) / get_double_write_ratio(hevc, dw_mode); + ps->coded_height = ALIGN(height, 32) / get_double_write_ratio(hevc, dw_mode); + ps->dpb_size = v4l_parser_work_pic_num(hevc); + + return 0; +} + +static int v4l_res_change(struct hevc_state_s *hevc, union param_u *rpm_param) +{ + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hevc->v4l2_ctx); + int ret = 0; + + if (ctx->param_sets_from_ucode && + hevc->res_ch_flag == 0) { + struct aml_vdec_ps_infos ps; + int width = rpm_param->p.pic_width_in_luma_samples; + int height = rpm_param->p.pic_height_in_luma_samples; + if ((hevc->pic_w != 0 && + hevc->pic_h != 0) && + (hevc->pic_w != width || + hevc->pic_h != height)) { + hevc_print(hevc, 0, + "v4l_res_change Pic Width/Height Change (%d,%d)=>(%d,%d), interlace %d\n", + hevc->pic_w, hevc->pic_h, + width, + height, + hevc->interlace_flag); + + vh265_get_ps_info(hevc, width, height, &ps); + vdec_v4l_set_ps_infos(ctx, &ps); + vdec_v4l_res_ch_event(ctx); + hevc->v4l_params_parsed = false; + hevc->res_ch_flag = 1; + hevc->eos = 1; + flush_output(hevc, NULL); + //del_timer_sync(&hevc->timer); + notify_v4l_eos(hw_to_vdec(hevc)); + + ret = 1; + } + } + + return ret; +} + + static irqreturn_t vh265_isr_thread_fn(int irq, void *data) { struct hevc_state_s *hevc = (struct hevc_state_s *) data; @@ -10147,20 +10294,33 @@ force_output: if (hevc->is_used_v4l) { struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hevc->v4l2_ctx); + if (!v4l_res_change(hevc, &hevc->param)) { + if (ctx->param_sets_from_ucode && !hevc->v4l_params_parsed) { + struct aml_vdec_ps_infos ps; + int width = hevc->param.p.pic_width_in_luma_samples; + int height = hevc->param.p.pic_height_in_luma_samples; + + pr_debug("set ucode parse\n"); + vh265_get_ps_info(hevc, width, height, &ps); + /*notice the v4l2 codec.*/ + vdec_v4l_set_ps_infos(ctx, &ps); + hevc->v4l_params_parsed = true; + hevc->dec_result = DEC_RESULT_AGAIN; + amhevc_stop(); + restore_decode_state(hevc); + reset_process_time(hevc); + vdec_schedule_work(&hevc->work); + return IRQ_HANDLED; + } + }else { + pr_debug("resolution change\n"); + hevc->dec_result = DEC_RESULT_AGAIN; + amhevc_stop(); + restore_decode_state(hevc); + reset_process_time(hevc); + vdec_schedule_work(&hevc->work); + return IRQ_HANDLED; - if (ctx->param_sets_from_ucode && !hevc->v4l_params_parsed) { - struct aml_vdec_ps_infos ps; - - hevc->frame_width = hevc->param.p.pic_width_in_luma_samples; - hevc->frame_height = hevc->param.p.pic_height_in_luma_samples; - ps.visible_width = hevc->frame_width; - ps.visible_height = hevc->frame_height; - ps.coded_width = ALIGN(hevc->frame_width, 32); - ps.coded_height = ALIGN(hevc->frame_height, 32); - ps.dpb_size = get_work_pic_num(hevc); - hevc->v4l_params_parsed = true; - /*notice the v4l2 codec.*/ - vdec_v4l_set_ps_infos(ctx, &ps); } } @@ -10536,7 +10696,8 @@ static void vh265_check_timer_func(struct timer_list *timer) (get_dbg_flag(hevc) & H265_DEBUG_WAIT_DECODE_DONE_WHEN_STOP) == 0 && hw_to_vdec(hevc)->next_status == - VDEC_STATUS_DISCONNECTED) { + VDEC_STATUS_DISCONNECTED && + !hevc->is_used_v4l) { hevc->dec_result = DEC_RESULT_FORCE_EXIT; vdec_schedule_work(&hevc->work); hevc_print(hevc, @@ -12247,10 +12408,18 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hevc->v4l2_ctx); - if (ctx->param_sets_from_ucode && - !ctx->v4l_codec_ready && - hevc->v4l_params_parsed) { - ret = 0; /*the params has parsed.*/ + if (ctx->param_sets_from_ucode) { + if (hevc->v4l_params_parsed) { + if (!ctx->v4l_codec_dpb_ready && + v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < + run_ready_min_buf_num) + ret = 0; + } else { + if ((hevc->res_ch_flag == 1) && + ((ctx->state <= AML_STATE_INIT) || + (ctx->state >= AML_STATE_FLUSHING))) + ret = 0; + } } else if (!ctx->v4l_codec_dpb_ready) { if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < run_ready_min_buf_num) diff --git a/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c b/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c index 5c9884c..35a6c75 100644 --- a/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c +++ b/drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c @@ -313,9 +313,6 @@ static irqreturn_t vmjpeg_isr(struct vdec_s *vdec, int irq) hw->v4l_params_parsed = true; vdec_v4l_set_ps_infos(ctx, &ps); } - - if (!ctx->v4l_codec_ready) - return IRQ_HANDLED; } if (hw->is_used_v4l) { diff --git a/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c index c806cde..92abc02 100644 --- a/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c +++ b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c @@ -50,6 +50,7 @@ #include "../utils/firmware.h" #include "../utils/vdec_v4l2_buffer_ops.h" #include "../utils/config_parser.h" +#include <media/v4l2-mem2mem.h> #define MEM_NAME "codec_mmpeg12" #define CHECK_INTERVAL (HZ/100) @@ -171,6 +172,9 @@ static struct vframe_s *vmpeg_vf_get(void *); static void vmpeg_vf_put(struct vframe_s *, void *); static int vmpeg_vf_states(struct vframe_states *states, void *); static int vmpeg_event_cb(int type, void *data, void *private_data); +static int notify_v4l_eos(struct vdec_s *vdec); + + struct mmpeg2_userdata_record_t { struct userdata_meta_info_t meta_info; @@ -311,16 +315,19 @@ struct vdec_mpeg12_hw_s { u32 dynamic_buf_num_margin; struct vdec_info gvs; struct vframe_qos_s vframe_qos; + unsigned int res_ch_flag; }; static void vmpeg12_local_init(struct vdec_mpeg12_hw_s *hw); static int vmpeg12_hw_ctx_restore(struct vdec_mpeg12_hw_s *hw); static void reset_process_time(struct vdec_mpeg12_hw_s *hw); +static void flush_output(struct vdec_mpeg12_hw_s *hw); static int debug_enable; /*static struct work_struct userdata_push_work;*/ #undef pr_info #define pr_info printk unsigned int mpeg12_debug_mask = 0xff; /*static int counter_max = 5;*/ +static u32 run_ready_min_buf_num = 2; #define PRINT_FLAG_ERROR 0x0 #define PRINT_FLAG_RUN_FLOW 0X0001 @@ -412,8 +419,8 @@ static int vmpeg12_v4l_alloc_buff_config_canvas(struct vdec_mpeg12_hw_s *hw, int if (!hw->frame_width || !hw->frame_height) { struct vdec_pic_info pic; vdec_v4l_get_pic_info(ctx, &pic); - hw->frame_width = pic.coded_width; - hw->frame_height = pic.coded_height; + hw->frame_width = pic.visible_width; + hw->frame_height = pic.visible_height; debug_print(DECODE_ID(hw), 0, "[%d] set %d x %d from IF layer\n", ctx->id, hw->frame_width, hw->frame_height); @@ -523,9 +530,17 @@ static int find_free_buffer(struct vdec_mpeg12_hw_s *hw) if (i == hw->buf_num) return -1; - if (hw->is_used_v4l) - if (vmpeg12_v4l_alloc_buff_config_canvas(hw, i)) - return -1; + if (hw->is_used_v4l) { + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) { + /*run to parser csd data*/ + i = 0; + } else { + if (vmpeg12_v4l_alloc_buff_config_canvas(hw, i)) + return -1; + } + } return i; } @@ -1504,15 +1519,22 @@ static int prepare_display_buf(struct vdec_mpeg12_hw_s *hw, u32 index = pic->index; u32 info = pic->buffer_info; struct vdec_s *vdec = hw_to_vdec(hw); - + struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + ulong nv_order = VIDTYPE_VIU_NV21; user_data_ready_notify(hw, pic->pts, pic->pts_valid); #ifdef NV21 - type = VIDTYPE_VIU_NV21; + type = nv_order; #endif + /* swap uv */ + if (hw->is_used_v4l) { + if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || + (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M)) + nv_order = VIDTYPE_VIU_NV12; + } if (hw->frame_prog & PICINFO_PROG) { field_num = 1; - type |= VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; + type |= VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD | nv_order; } else { #ifdef INTERLACE_SEQ_ALWAYS /* once an interlace seq, force interlace, to make di easy. */ @@ -1551,7 +1573,7 @@ static int prepare_display_buf(struct vdec_mpeg12_hw_s *hw, vf->duration_pulldown = (field_num == 3) ? (vf->duration >> 1):0; if (i > 0) - type = VIDTYPE_VIU_NV21; + type = nv_order; if (i == 1) /* second field*/ type |= (first_field_type == VIDTYPE_INTERLACE_TOP) ? VIDTYPE_INTERLACE_BOTTOM : VIDTYPE_INTERLACE_TOP; @@ -1699,6 +1721,52 @@ static bool is_ref_error(struct vdec_mpeg12_hw_s *hw) return 0; } +static int vmpeg2_get_ps_info(struct vdec_mpeg12_hw_s *hw, int width, int height, struct aml_vdec_ps_infos *ps) +{ + ps->visible_width = width; + ps->visible_height = height; + ps->coded_width = ALIGN(width, 64); + ps->coded_height = ALIGN(height, 32); + ps->dpb_size = hw->buf_num; + + return 0; +} + +static int v4l_res_change(struct vdec_mpeg12_hw_s *hw, int width, int height) +{ + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + int ret = 0; + + if (ctx->param_sets_from_ucode && + hw->res_ch_flag == 0) { + struct aml_vdec_ps_infos ps; + + if ((hw->frame_width != 0 && + hw->frame_height != 0) && + (hw->frame_width != width || + hw->frame_height != height)) { + debug_print(DECODE_ID(hw), 0, + "v4l_res_change Pic Width/Height Change (%d,%d)=>(%d,%d)\n", + hw->frame_width, hw->frame_height, + width, + height); + vmpeg2_get_ps_info(hw, width, height, &ps); + vdec_v4l_set_ps_infos(ctx, &ps); + vdec_v4l_res_ch_event(ctx); + hw->v4l_params_parsed = false; + hw->res_ch_flag = 1; + hw->eos = 1; + flush_output(hw); + notify_v4l_eos(hw_to_vdec(hw)); + + ret = 1; + } + } + + return ret; +} + static irqreturn_t vmpeg12_isr_thread_fn(struct vdec_s *vdec, int irq) { @@ -1722,6 +1790,38 @@ static irqreturn_t vmpeg12_isr_thread_fn(struct vdec_s *vdec, int irq) return IRQ_HANDLED; } + reg = READ_VREG(AV_SCRATCH_G); + if (reg == 1) { + if (hw->is_used_v4l) { + int frame_width = READ_VREG(MREG_PIC_WIDTH); + int frame_height = READ_VREG(MREG_PIC_HEIGHT); + if (!v4l_res_change(hw, frame_width, frame_height)) { + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) { + struct aml_vdec_ps_infos ps; + + vmpeg2_get_ps_info(hw, frame_width, frame_height, &ps); + hw->v4l_params_parsed = true; + vdec_v4l_set_ps_infos(ctx, &ps); + userdata_pushed_drop(hw); + reset_process_time(hw); + hw->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hw->work); + } else { + WRITE_VREG(AV_SCRATCH_G, 0); + } + } else { + userdata_pushed_drop(hw); + reset_process_time(hw); + hw->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hw->work); + } + } else + WRITE_VREG(AV_SCRATCH_G, 0); + return IRQ_HANDLED; + } + reg = READ_VREG(AV_SCRATCH_J); if (reg & (1<<16)) { vdec_schedule_work(&hw->userdata_push_work); @@ -1794,26 +1894,6 @@ static irqreturn_t vmpeg12_isr_thread_fn(struct vdec_s *vdec, int irq) hw->frame_height = tmp; } - if (hw->is_used_v4l) { - struct aml_vcodec_ctx *ctx = - (struct aml_vcodec_ctx *)(hw->v4l2_ctx); - - if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) { - struct aml_vdec_ps_infos ps; - - ps.visible_width = hw->frame_width; - ps.visible_height = hw->frame_height; - ps.coded_width = ALIGN(hw->frame_width, 64); - ps.coded_height = ALIGN(hw->frame_height, 32); - ps.dpb_size = hw->buf_num; - hw->v4l_params_parsed = true; - vdec_v4l_set_ps_infos(ctx, &ps); - } - - if (!ctx->v4l_codec_ready) - return IRQ_HANDLED; - } - new_pic->buffer_info = info; new_pic->offset = offset; new_pic->index = index; @@ -1976,6 +2056,7 @@ static int notify_v4l_eos(struct vdec_s *vdec) struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); struct vframe_s *vf = NULL; struct vdec_v4l2_buffer *fb = NULL; + int index; if (hw->is_used_v4l && hw->eos) { if (kfifo_get(&hw->newframe_q, &vf) == 0 || vf == NULL) { @@ -1984,14 +2065,17 @@ static int notify_v4l_eos(struct vdec_s *vdec) __func__); return -1; } - - if (vdec_v4l_get_buffer(hw->v4l2_ctx, &fb)) { + index = find_free_buffer(hw); + if ((index == -1) && + vdec_v4l_get_buffer(hw->v4l2_ctx, &fb)) { pr_err("[%d] get fb fail.\n", ctx->id); return -1; } + vf->type |= VIDTYPE_V4L_EOS; vf->timestamp = ULONG_MAX; - vf->v4l_mem_handle = (unsigned long)fb; + vf->v4l_mem_handle = (index == -1) ? (ulong)fb : + hw->pics[index].v4l_ref_buf_addr; vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; kfifo_put(&hw->display_q, (const struct vframe_s *)vf); @@ -2632,7 +2716,13 @@ static int vmpeg12_hw_ctx_restore(struct vdec_mpeg12_hw_s *hw) /* clear error count */ WRITE_VREG(MREG_ERROR_COUNT, 0); - WRITE_VREG(MREG_FATAL_ERROR, 0); + /*Use MREG_FATAL_ERROR bit1, the ucode determine + whether to report the interruption of width and + height information,in order to be compatible + with the old version of ucode. + 1: Report the width and height information + 0: Not Report*/ + WRITE_VREG(MREG_FATAL_ERROR, 1 << 1); /* clear wait buffer status */ WRITE_VREG(MREG_WAIT_BUFFER, 0); #ifdef NV21 @@ -2644,6 +2734,8 @@ static int vmpeg12_hw_ctx_restore(struct vdec_mpeg12_hw_s *hw) && (v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21 || v4l2_ctx->q_data[AML_Q_DATA_DST].fmt->fourcc == V4L2_PIX_FMT_NV21M)) SET_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); + else + CLEAR_VREG_MASK(MDEC_PIC_DC_CTRL, 1 << 16); if (!hw->ctx_valid) WRITE_VREG(AV_SCRATCH_J, hw->userdata_wp_ctx); @@ -2815,6 +2907,30 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) } #endif + if (hw->is_used_v4l) { + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + + if (ctx->param_sets_from_ucode) { + if (hw->v4l_params_parsed) { + if (!ctx->v4l_codec_dpb_ready && + v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < + run_ready_min_buf_num) + if (!ctx->v4l_codec_dpb_ready) + return 0; + } else { + if ((hw->res_ch_flag == 1) && + ((ctx->state <= AML_STATE_INIT) || + (ctx->state >= AML_STATE_FLUSHING))) + return 0; + } + } else if (!ctx->v4l_codec_dpb_ready) { + if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < + run_ready_min_buf_num) + return 0; + } + } + if (!is_enough_free_buffer(hw)) { hw->buffer_not_ready++; return 0; diff --git a/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c b/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c index b1a5911..d53689d 100644 --- a/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c +++ b/drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c @@ -48,6 +48,7 @@ #include "../utils/firmware.h" #include "../utils/vdec_v4l2_buffer_ops.h" #include "../utils/config_parser.h" +#include <media/v4l2-mem2mem.h> #define DRIVER_NAME "ammvdec_mpeg4" #define MODULE_NAME "ammvdec_mpeg4" @@ -82,6 +83,7 @@ #define MP4_OFFSET_REG AV_SCRATCH_C #define MP4_SYS_RATE AV_SCRATCH_E #define MEM_OFFSET_REG AV_SCRATCH_F +#define MP4_PIC_INFO AV_SCRATCH_H #define PARC_FORBIDDEN 0 #define PARC_SQUARE 1 @@ -137,6 +139,8 @@ static struct vframe_s *vmpeg_vf_get(void *); static void vmpeg_vf_put(struct vframe_s *, void *); static int vmpeg_vf_states(struct vframe_states *states, void *); static int vmpeg_event_cb(int type, void *data, void *private_data); +static int notify_v4l_eos(struct vdec_s *vdec); + static int pre_decode_buf_level = 0x800; static int start_decode_buf_level = 0x4000; static int debug_enable; @@ -156,6 +160,8 @@ static u32 without_display_mode; #undef pr_info #define pr_info printk unsigned int mpeg4_debug_mask = 0xff; +static u32 run_ready_min_buf_num = 2; + #define PRINT_FLAG_ERROR 0x0 #define PRINT_FLAG_RUN_FLOW 0X0001 @@ -313,11 +319,13 @@ struct vdec_mpeg4_hw_s { bool v4l_params_parsed; u32 buf_num; u32 dynamic_buf_num_margin; + unsigned int res_ch_flag; }; static void vmpeg4_local_init(struct vdec_mpeg4_hw_s *hw); static int vmpeg4_hw_ctx_restore(struct vdec_mpeg4_hw_s *hw); static unsigned char get_data_check_sum(struct vdec_mpeg4_hw_s *hw, int size); +static void flush_output(struct vdec_mpeg4_hw_s * hw); #define PROVIDER_NAME "vdec.mpeg4" @@ -361,11 +369,13 @@ static int vmpeg4_v4l_alloc_buff_config_canvas(struct vdec_mpeg4_hw_s *hw, int i { int ret; u32 canvas; - ulong decbuf_start = 0; - int decbuf_y_size = 0; + ulong decbuf_start = 0, decbuf_uv_start = 0; + int decbuf_y_size = 0, decbuf_uv_size = 0; u32 canvas_width = 0, canvas_height = 0; struct vdec_s *vdec = hw_to_vdec(hw); struct vdec_v4l2_buffer *fb = NULL; + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); if (hw->pic[i].v4l_ref_buf_addr) return 0; @@ -379,20 +389,34 @@ static int vmpeg4_v4l_alloc_buff_config_canvas(struct vdec_mpeg4_hw_s *hw, int i return ret; } + if (!hw->frame_width || !hw->frame_height) { + struct vdec_pic_info pic; + vdec_v4l_get_pic_info(ctx, &pic); + hw->frame_width = pic.visible_width; + hw->frame_height = pic.visible_height; + mmpeg4_debug_print(DECODE_ID(hw), 0, + "[%d] set %d x %d from IF layer\n", ctx->id, + hw->frame_width, hw->frame_height); + } + hw->pic[i].v4l_ref_buf_addr = (ulong)fb; if (fb->num_planes == 1) { decbuf_start = fb->m.mem[0].addr; decbuf_y_size = fb->m.mem[0].offset; + decbuf_uv_start = decbuf_start + decbuf_y_size; + decbuf_uv_size = decbuf_y_size / 2; canvas_width = ALIGN(hw->frame_width, 64); - canvas_height = ALIGN(hw->frame_height, 32); + canvas_height = ALIGN(hw->frame_height, 64); fb->m.mem[0].bytes_used = fb->m.mem[0].size; } else if (fb->num_planes == 2) { decbuf_start = fb->m.mem[0].addr; decbuf_y_size = fb->m.mem[0].size; + decbuf_uv_start = fb->m.mem[1].addr; + decbuf_uv_size = fb->m.mem[1].size; canvas_width = ALIGN(hw->frame_width, 64); - canvas_height = ALIGN(hw->frame_height, 32); + canvas_height = ALIGN(hw->frame_height, 64); fb->m.mem[0].bytes_used = decbuf_y_size; - fb->m.mem[1].bytes_used = decbuf_y_size << 1; + fb->m.mem[1].bytes_used = decbuf_uv_size; } mmpeg4_debug_print(DECODE_ID(hw), 0, "[%d] %s(), v4l ref buf addr: 0x%x\n", @@ -429,7 +453,7 @@ static int vmpeg4_v4l_alloc_buff_config_canvas(struct vdec_mpeg4_hw_s *hw, int i &hw->canvas_config[i][0]); hw->canvas_config[i][1].phy_addr = - decbuf_start + decbuf_y_size; + decbuf_uv_start; hw->canvas_config[i][1].width = canvas_width; hw->canvas_config[i][1].height = (canvas_height >> 1); hw->canvas_config[i][1].block_mode = hw->blkmode; @@ -467,9 +491,18 @@ static int find_free_buffer(struct vdec_mpeg4_hw_s *hw) if (i == hw->buf_num) return -1; - if (hw->is_used_v4l) - if (vmpeg4_v4l_alloc_buff_config_canvas(hw, i)) - return -1; + if (hw->is_used_v4l) { + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) { + /*run to parser csd data*/ + i = 0; + } else { + if (vmpeg4_v4l_alloc_buff_config_canvas(hw, i)) + return -1; + } + } + return i; } @@ -618,8 +651,17 @@ static int prepare_display_buf(struct vdec_mpeg4_hw_s * hw, { struct vframe_s *vf = NULL; struct vdec_s *vdec = hw_to_vdec(hw); + struct aml_vcodec_ctx * v4l2_ctx = hw->v4l2_ctx; + ulong nv_order = VIDTYPE_VIU_NV21; int index = pic->index; + /* swap uv */ + if (hw->is_used_v4l) { + if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || + (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M)) + nv_order = VIDTYPE_VIU_NV12; + } + if (pic->pic_info & INTERLACE_FLAG) { if (kfifo_get(&hw->newframe_q, &vf) == 0) { mmpeg4_debug_print(DECODE_ID(hw), 0, @@ -649,7 +691,7 @@ static int prepare_display_buf(struct vdec_mpeg4_hw_s * hw, vf->type = (pic->pic_info & TOP_FIELD_FIRST_FLAG) ? VIDTYPE_INTERLACE_TOP : VIDTYPE_INTERLACE_BOTTOM; #ifdef NV21 - vf->type |= VIDTYPE_VIU_NV21; + vf->type |= nv_order; #endif set_frame_info(hw, vf, pic->index); @@ -701,7 +743,7 @@ static int prepare_display_buf(struct vdec_mpeg4_hw_s * hw, vf->type = (pic->pic_info & TOP_FIELD_FIRST_FLAG) ? VIDTYPE_INTERLACE_BOTTOM : VIDTYPE_INTERLACE_TOP; #ifdef NV21 - vf->type |= VIDTYPE_VIU_NV21; + vf->type |= nv_order; #endif set_frame_info(hw, vf, pic->index); @@ -762,7 +804,7 @@ static int prepare_display_buf(struct vdec_mpeg4_hw_s * hw, pic->duration; #ifdef NV21 vf->type = VIDTYPE_PROGRESSIVE | - VIDTYPE_VIU_FIELD | VIDTYPE_VIU_NV21; + VIDTYPE_VIU_FIELD | nv_order; #else vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; @@ -867,6 +909,53 @@ static void vmpeg4_prepare_input(struct vdec_mpeg4_hw_s *hw) } } +static int vmpeg4_get_ps_info(struct vdec_mpeg4_hw_s *hw, int width, int height, struct aml_vdec_ps_infos *ps) +{ + ps->visible_width = width; + ps->visible_height = height; + ps->coded_width = ALIGN(width, 64); + ps->coded_height = ALIGN(height, 64); + ps->dpb_size = hw->buf_num; + + return 0; +} + +static int v4l_res_change(struct vdec_mpeg4_hw_s *hw, int width, int height) +{ + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + int ret = 0; + + if (ctx->param_sets_from_ucode && + hw->res_ch_flag == 0) { + struct aml_vdec_ps_infos ps; + + if ((hw->frame_width != 0 && + hw->frame_height != 0) && + (hw->frame_width != width || + hw->frame_height != height)) { + mmpeg4_debug_print(DECODE_ID(hw), 0, + "v4l_res_change Pic Width/Height Change (%d,%d)=>(%d,%d)\n", + hw->frame_width, hw->frame_height, + width, + height); + vmpeg4_get_ps_info(hw, width, height, &ps); + vdec_v4l_set_ps_infos(ctx, &ps); + vdec_v4l_res_ch_event(ctx); + hw->v4l_params_parsed = false; + hw->res_ch_flag = 1; + hw->eos = 1; + flush_output(hw); + notify_v4l_eos(hw_to_vdec(hw)); + + ret = 1; + } + } + + return ret; +} + + static irqreturn_t vmpeg4_isr_thread_fn(struct vdec_s *vdec, int irq) { u32 reg; @@ -882,6 +971,35 @@ static irqreturn_t vmpeg4_isr_thread_fn(struct vdec_s *vdec, int irq) if (hw->eos) return IRQ_HANDLED; + if (READ_VREG(MP4_PIC_INFO) == 1) { + if (hw->is_used_v4l) { + int frame_width = READ_VREG(MP4_PIC_WH)>> 16; + int frame_height = READ_VREG(MP4_PIC_WH) & 0xffff; + if (!v4l_res_change(hw, frame_width, frame_height)) { + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) { + struct aml_vdec_ps_infos ps; + + vmpeg4_get_ps_info(hw, frame_width, frame_height, &ps); + hw->v4l_params_parsed = true; + vdec_v4l_set_ps_infos(ctx, &ps); + reset_process_time(hw); + hw->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hw->work); + } else { + WRITE_VREG(MP4_PIC_INFO, 0); + } + } else { + reset_process_time(hw); + hw->dec_result = DEC_RESULT_AGAIN; + vdec_schedule_work(&hw->work); + } + } else + WRITE_VREG(MP4_PIC_INFO, 0); + return IRQ_HANDLED; + } + WRITE_VREG(ASSIST_MBOX1_CLR_REG, 1); if (READ_VREG(AV_SCRATCH_M) != 0 && (debug_enable & PRINT_FLAG_UCODE_DETAIL)) { @@ -979,26 +1097,6 @@ static irqreturn_t vmpeg4_isr_thread_fn(struct vdec_s *vdec, int irq) if (dec_h != 0) hw->frame_height = dec_h; - if (hw->is_used_v4l) { - struct aml_vcodec_ctx *ctx = - (struct aml_vcodec_ctx *)(hw->v4l2_ctx); - - if (ctx->param_sets_from_ucode && !hw->v4l_params_parsed) { - struct aml_vdec_ps_infos ps; - - ps.visible_width = hw->frame_width; - ps.visible_height = hw->frame_height; - ps.coded_width = ALIGN(hw->frame_width, 64); - ps.coded_height = ALIGN(hw->frame_height, 64); - ps.dpb_size = hw->buf_num; - hw->v4l_params_parsed = true; - vdec_v4l_set_ps_infos(ctx, &ps); - } - - if (!ctx->v4l_codec_ready) - return IRQ_HANDLED; - } - if (hw->vmpeg4_amstream_dec_info.rate == 0) { if (vop_time_inc < hw->last_vop_time_inc) { duration = vop_time_inc + @@ -1293,6 +1391,7 @@ static int notify_v4l_eos(struct vdec_s *vdec) struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(hw->v4l2_ctx); struct vframe_s *vf = NULL; struct vdec_v4l2_buffer *fb = NULL; + int index; if (hw->is_used_v4l && hw->eos) { if (kfifo_get(&hw->newframe_q, &vf) == 0 || vf == NULL) { @@ -1302,13 +1401,18 @@ static int notify_v4l_eos(struct vdec_s *vdec) return -1; } - if (vdec_v4l_get_buffer(hw->v4l2_ctx, &fb)) { + index = find_free_buffer(hw); + + if ((index == -1) && + vdec_v4l_get_buffer(hw->v4l2_ctx, &fb)) { pr_err("[%d] get fb fail.\n", ctx->id); return -1; } + vf->type |= VIDTYPE_V4L_EOS; vf->timestamp = ULONG_MAX; - vf->v4l_mem_handle = (unsigned long)fb; + vf->v4l_mem_handle = (index == -1) ? (ulong)fb : + hw->pic[index].v4l_ref_buf_addr;; vf->flag = VFRAME_FLAG_EMPTY_FRAME_V4L; kfifo_put(&hw->display_q, (const struct vframe_s *)vf); @@ -1393,6 +1497,15 @@ static void vmpeg4_work(struct work_struct *work) del_timer_sync(&hw->check_timer); hw->stat &= ~STAT_TIMER_ARM; + if (hw->is_used_v4l) { + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + + if (ctx->param_sets_from_ucode && + !hw->v4l_params_parsed) + vdec_v4l_write_frame_sync(ctx); + } + /* mark itself has all HW resource released and input released */ if (vdec->parallel_dec == 1) vdec_core_finish_run(vdec, CORE_MASK_VDEC_1); @@ -1929,8 +2042,14 @@ static void vmpeg4_local_init(struct vdec_mpeg4_hw_s *hw) hw->vmpeg4_rotation = (((unsigned long)hw->vmpeg4_amstream_dec_info.param) >> 16) & 0xffff; hw->sys_mp4_rate = hw->vmpeg4_amstream_dec_info.rate; - hw->frame_width = hw->vmpeg4_amstream_dec_info.width; - hw->frame_height = hw->vmpeg4_amstream_dec_info.height; + if (hw->is_used_v4l) { + hw->frame_width = 0; + hw->frame_height = 0; + } else { + hw->frame_width = hw->vmpeg4_amstream_dec_info.width; + hw->frame_height = hw->vmpeg4_amstream_dec_info.height; + } + hw->frame_dur = 0; hw->frame_prog = 0; hw->unstable_pts = @@ -2072,6 +2191,29 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) } } + if (hw->is_used_v4l) { + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(hw->v4l2_ctx); + + if (ctx->param_sets_from_ucode) { + if (hw->v4l_params_parsed) { + if (!ctx->v4l_codec_dpb_ready && + v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < + run_ready_min_buf_num) + return 0; + } else { + if ((hw->res_ch_flag == 1) && + ((ctx->state <= AML_STATE_INIT) || + (ctx->state >= AML_STATE_FLUSHING))) + return 0; + } + } else if (!ctx->v4l_codec_dpb_ready) { + if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < + run_ready_min_buf_num) + return 0; + } + } + if (!is_enough_free_buffer(hw)) { hw->buffer_not_ready++; return 0; @@ -2348,9 +2490,29 @@ static int ammvdec_mpeg4_probe(struct platform_device *pdev) hw->vmpeg4_amstream_dec_info.width, hw->vmpeg4_amstream_dec_info.height, hw->vmpeg4_amstream_dec_info.rate); - hw->is_used_v4l = (((unsigned long) - hw->vmpeg4_amstream_dec_info.param & 0x80) >> 7); } + if (((debug_enable & IGNORE_PARAM_FROM_CONFIG) == 0) && pdata->config_len) { + mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, + "pdata->config: %s\n", pdata->config); + if (get_config_int(pdata->config, "parm_v4l_buffer_margin", + &config_val) == 0) + hw->dynamic_buf_num_margin = config_val; + else + hw->dynamic_buf_num_margin = dynamic_buf_num_margin; + + if (get_config_int(pdata->config, + "parm_v4l_codec_enable", + &config_val) == 0) + hw->is_used_v4l = config_val; + + if (get_config_int(pdata->config, + "parm_v4l_canvas_mem_mode", + &config_val) == 0) + hw->blkmode = config_val; + } else + hw->dynamic_buf_num_margin = dynamic_buf_num_margin; + + hw->buf_num = vmpeg4_get_buf_num(hw); if (vmmpeg4_init(hw) < 0) { pr_err("%s init failed.\n", __func__); diff --git a/drivers/frame_provider/decoder/utils/vdec.c b/drivers/frame_provider/decoder/utils/vdec.c index 983869f..a8a4b74 100644 --- a/drivers/frame_provider/decoder/utils/vdec.c +++ b/drivers/frame_provider/decoder/utils/vdec.c @@ -1171,6 +1171,13 @@ int vdec_write_vframe(struct vdec_s *vdec, const char *buf, size_t count) } EXPORT_SYMBOL(vdec_write_vframe); +int vdec_write_vframe_with_dma(struct vdec_s *vdec, + ulong addr, size_t count, u32 handle) +{ + return vdec_input_add_frame_with_dma(&vdec->input, addr, count, handle); +} +EXPORT_SYMBOL(vdec_write_vframe_with_dma); + /* add a work queue thread for vdec*/ void vdec_schedule_work(struct work_struct *work) { diff --git a/drivers/frame_provider/decoder/utils/vdec.h b/drivers/frame_provider/decoder/utils/vdec.h index 8b0aaf2..9d1045a 100644 --- a/drivers/frame_provider/decoder/utils/vdec.h +++ b/drivers/frame_provider/decoder/utils/vdec.h @@ -323,6 +323,9 @@ extern int vdec_set_receive_id(struct vdec_s *vdec, int receive_id); extern int vdec_write_vframe(struct vdec_s *vdec, const char *buf, size_t count); +extern int vdec_write_vframe_with_dma(struct vdec_s *vdec, + ulong addr, size_t count, u32 handle); + /* mark the vframe_chunk as consumed */ extern void vdec_vframe_dirty(struct vdec_s *vdec, struct vframe_chunk_s *chunk); diff --git a/drivers/frame_provider/decoder/utils/vdec_input.c b/drivers/frame_provider/decoder/utils/vdec_input.c index 4965cff..da663b6 100644 --- a/drivers/frame_provider/decoder/utils/vdec_input.c +++ b/drivers/frame_provider/decoder/utils/vdec_input.c @@ -973,6 +973,16 @@ int vdec_input_add_frame(struct vdec_input_s *input, const char *buf, } EXPORT_SYMBOL(vdec_input_add_frame); +int vdec_input_add_frame_with_dma(struct vdec_input_s *input, ulong addr, + size_t count, u32 handle) +{ + struct vdec_s *vdec = input->vdec; + + return vdec_secure(vdec) ? + vdec_input_add_chunk(input, (char *)addr, count, handle) : -1; +} +EXPORT_SYMBOL(vdec_input_add_frame_with_dma); + struct vframe_chunk_s *vdec_input_next_chunk(struct vdec_input_s *input) { struct vframe_chunk_s *chunk = NULL; diff --git a/drivers/frame_provider/decoder/utils/vdec_input.h b/drivers/frame_provider/decoder/utils/vdec_input.h index 26ccb49..4e871e7 100644 --- a/drivers/frame_provider/decoder/utils/vdec_input.h +++ b/drivers/frame_provider/decoder/utils/vdec_input.h @@ -143,6 +143,9 @@ extern int vdec_input_set_buffer(struct vdec_input_s *input, u32 start, extern int vdec_input_add_frame(struct vdec_input_s *input, const char *buf, size_t count); +extern int vdec_input_add_frame_with_dma(struct vdec_input_s *input, ulong addr, + size_t count, u32 handle); + /* Peek next frame data from decoder's input */ extern struct vframe_chunk_s *vdec_input_next_chunk( struct vdec_input_s *input); diff --git a/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.c b/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.c index 88d2947..e99d59b 100644 --- a/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.c +++ b/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.c @@ -1,4 +1,11 @@ #include "vdec_v4l2_buffer_ops.h" +#include <media/v4l2-mem2mem.h> +#include <linux/printk.h> + +#ifndef CONFIG_AMLOGIC_MEDIA_V4L_DEC +static void v4l2_m2m_job_pause(struct v4l2_m2m_dev *m2m_dev, + struct v4l2_m2m_ctx *m2m_ctx) { return; } +#endif int vdec_v4l_get_buffer(struct aml_vcodec_ctx *ctx, struct vdec_v4l2_buffer **out) @@ -60,6 +67,52 @@ int vdec_v4l_set_hdr_infos(struct aml_vcodec_ctx *ctx, } EXPORT_SYMBOL(vdec_v4l_set_hdr_infos); +static void aml_wait_dpb_ready(struct aml_vcodec_ctx *ctx) +{ + ulong expires; + + expires = jiffies + msecs_to_jiffies(1000); + while (!ctx->v4l_codec_dpb_ready) { + u32 ready_num = 0; + + if (time_after(jiffies, expires)) { + pr_err("the DPB state has not ready.\n"); + break; + } + + ready_num = v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx); + if ((ready_num + ctx->buf_used_count) >= ctx->dpb_size) + ctx->v4l_codec_dpb_ready = true; + } +} + +void aml_vdec_pic_info_update(struct aml_vcodec_ctx *ctx) +{ + unsigned int dpbsize = 0; + int ret; + + if (ctx->dec_if->get_param(ctx->drv_handle, GET_PARAM_PIC_INFO, &ctx->last_decoded_picinfo)) { + pr_err("Cannot get param : GET_PARAM_PICTURE_INFO ERR\n"); + return; + } + + if (ctx->last_decoded_picinfo.visible_width == 0 || + ctx->last_decoded_picinfo.visible_height == 0 || + ctx->last_decoded_picinfo.coded_width == 0 || + ctx->last_decoded_picinfo.coded_height == 0) { + pr_err("Cannot get correct pic info\n"); + return; + } + + ret = ctx->dec_if->get_param(ctx->drv_handle, GET_PARAM_DPB_SIZE, &dpbsize); + if (dpbsize == 0) + pr_err("Incorrect dpb size, ret=%d\n", ret); + + /* update picture information */ + ctx->dpb_size = dpbsize; + ctx->picinfo = ctx->last_decoded_picinfo; +} + int vdec_v4l_post_evet(struct aml_vcodec_ctx *ctx, u32 event) { int ret = 0; @@ -75,6 +128,35 @@ int vdec_v4l_post_evet(struct aml_vcodec_ctx *ctx, u32 event) } EXPORT_SYMBOL(vdec_v4l_post_evet); +int vdec_v4l_res_ch_event(struct aml_vcodec_ctx *ctx) +{ + int ret = 0; + struct aml_vcodec_dev *dev = ctx->dev; + + if (ctx->drv_handle == 0) + return -EIO; + + /* wait the DPB state to be ready. */ + aml_wait_dpb_ready(ctx); + + aml_vdec_pic_info_update(ctx); + + mutex_lock(&ctx->state_lock); + + ctx->state = AML_STATE_FLUSHING;/*prepare flushing*/ + + pr_info("[%d]: vcodec state (AML_STATE_FLUSHING-RESCHG)\n", ctx->id); + + mutex_unlock(&ctx->state_lock); + + ctx->q_data[AML_Q_DATA_SRC].resolution_changed = true; + v4l2_m2m_job_pause(dev->m2m_dev_dec, ctx->m2m_ctx); + + return ret; +} +EXPORT_SYMBOL(vdec_v4l_res_ch_event); + + int vdec_v4l_write_frame_sync(struct aml_vcodec_ctx *ctx) { int ret = 0; diff --git a/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.h b/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.h index 6254509..8bedb88 100644 --- a/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.h +++ b/drivers/frame_provider/decoder/utils/vdec_v4l2_buffer_ops.h @@ -27,4 +27,7 @@ int vdec_v4l_post_evet( struct aml_vcodec_ctx *ctx, u32 event); +int vdec_v4l_res_ch_event( + struct aml_vcodec_ctx *ctx); + #endif diff --git a/drivers/frame_provider/decoder/vp9/vvp9.c b/drivers/frame_provider/decoder/vp9/vvp9.c index 43f1376..d27b6ef 100644 --- a/drivers/frame_provider/decoder/vp9/vvp9.c +++ b/drivers/frame_provider/decoder/vp9/vvp9.c @@ -1197,6 +1197,7 @@ struct VP9Decoder_s { u32 mem_map_mode; u32 dynamic_buf_num_margin; struct vframe_s vframe_dummy; + unsigned int res_ch_flag; }; static int vp9_print(struct VP9Decoder_s *pbi, @@ -1595,6 +1596,41 @@ static u32 get_valid_double_write_mode(struct VP9Decoder_s *pbi) (double_write_mode & 0x7fffffff); } +static int v4l_parser_get_double_write_mode(struct VP9Decoder_s *pbi) +{ + u32 valid_dw_mode = get_valid_double_write_mode(pbi); + u32 dw; + int w, h; + + /* mask for supporting double write value bigger than 0x100 */ + if (valid_dw_mode & 0xffffff00) { + w = pbi->frame_width; + h = pbi->frame_height; + + dw = 0x1; /*1:1*/ + switch (valid_dw_mode) { + case 0x100: + if (w > 1920 && h > 1088) + dw = 0x4; /*1:2*/ + break; + case 0x200: + if (w > 1920 && h > 1088) + dw = 0x2; /*1:4*/ + break; + case 0x300: + if (w > 1280 && h > 720) + dw = 0x4; /*1:2*/ + break; + default: + break; + } + return dw; + } + + return valid_dw_mode; +} + + static int get_double_write_mode(struct VP9Decoder_s *pbi) { u32 valid_dw_mode = get_valid_double_write_mode(pbi); @@ -7038,6 +7074,8 @@ static int prepare_display_buf(struct VP9Decoder_s *pbi, struct vdec_s *pvdec = hw_to_vdec(pbi); int stream_offset = pic_config->stream_offset; unsigned short slice_type = pic_config->slice_type; + struct aml_vcodec_ctx * v4l2_ctx = pbi->v4l2_ctx; + ulong nv_order = VIDTYPE_VIU_NV21; u32 pts_valid = 0, pts_us64_valid = 0; u32 pts_save; u64 pts_us64_save; @@ -7050,6 +7088,13 @@ static int prepare_display_buf(struct VP9Decoder_s *pbi, return -1; } + /* swap uv */ + if (pbi->is_used_v4l) { + if ((v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12) || + (v4l2_ctx->cap_pix_fmt == V4L2_PIX_FMT_NV12M)) + nv_order = VIDTYPE_VIU_NV12; + } + if (pic_config->double_write_mode) set_canvas(pbi, pic_config); @@ -7199,7 +7244,7 @@ static int prepare_display_buf(struct VP9Decoder_s *pbi, if (pic_config->double_write_mode) { vf->type = VIDTYPE_PROGRESSIVE | VIDTYPE_VIU_FIELD; - vf->type |= VIDTYPE_VIU_NV21; + vf->type |= nv_order; if ((pic_config->double_write_mode == 3) && (!IS_8K_SIZE(pic_config->y_crop_width, pic_config->y_crop_height))) { @@ -7515,8 +7560,11 @@ int continue_decoding(struct VP9Decoder_s *pbi) int ret; int i; struct VP9_Common_s *const cm = &pbi->common; + struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(pbi->v4l2_ctx); debug_buffer_mgr_more(pbi); + if (pbi->is_used_v4l && ctx->param_sets_from_ucode) + pbi->res_ch_flag = 0; bit_depth_luma = vp9_param.p.bit_depth; bit_depth_chroma = vp9_param.p.bit_depth; @@ -8150,6 +8198,54 @@ static void get_picture_qos_info(struct VP9Decoder_s *pbi) } } +static int vvp9_get_ps_info(struct VP9Decoder_s *pbi, struct aml_vdec_ps_infos *ps) +{ + int dw_mode = v4l_parser_get_double_write_mode(pbi); + + ps->visible_width = pbi->frame_width / get_double_write_ratio(pbi, dw_mode); + ps->visible_height = pbi->frame_height / get_double_write_ratio(pbi, dw_mode); + ps->coded_width = ALIGN(pbi->frame_width, 32) / get_double_write_ratio(pbi, dw_mode); + ps->coded_height = ALIGN(pbi->frame_height, 32) / get_double_write_ratio(pbi, dw_mode); + ps->dpb_size = pbi->used_buf_num; + + return 0; +} + + +static int v4l_res_change(struct VP9Decoder_s *pbi) +{ + struct aml_vcodec_ctx *ctx = + (struct aml_vcodec_ctx *)(pbi->v4l2_ctx); + struct VP9_Common_s *const cm = &pbi->common; + int ret = 0; + + if (ctx->param_sets_from_ucode && + pbi->res_ch_flag == 0) { + struct aml_vdec_ps_infos ps; + if ((cm->width != 0 && + cm->height != 0) && + (pbi->frame_width != cm->width || + pbi->frame_height != cm->height)) { + + vp9_print(pbi, 0, "%s (%d,%d)=>(%d,%d)\r\n", __func__, cm->width, + cm->height, pbi->frame_width, pbi->frame_height); + vvp9_get_ps_info(pbi, &ps); + vdec_v4l_set_ps_infos(ctx, &ps); + vdec_v4l_res_ch_event(ctx); + pbi->v4l_params_parsed = false; + pbi->res_ch_flag = 1; + pbi->eos = 1; + vp9_bufmgr_postproc(pbi); + //del_timer_sync(&pbi->timer); + notify_v4l_eos(hw_to_vdec(pbi)); + ret = 1; + } + } + + return ret; +} + + static irqreturn_t vvp9_isr_thread_fn(int irq, void *data) { struct VP9Decoder_s *pbi = (struct VP9Decoder_s *)data; @@ -8376,27 +8472,31 @@ static irqreturn_t vvp9_isr_thread_fn(int irq, void *data) pbi->frame_width = vp9_param.p.width; pbi->frame_height = vp9_param.p.height; - if (ctx->param_sets_from_ucode && !pbi->v4l_params_parsed) { - struct aml_vdec_ps_infos ps; - - ps.visible_width = pbi->frame_width; - ps.visible_height = pbi->frame_height; - ps.coded_width = ALIGN(pbi->frame_width, 32); - ps.coded_height = ALIGN(pbi->frame_height, 32); - ps.dpb_size = pbi->used_buf_num; - pbi->v4l_params_parsed = true; - vdec_v4l_set_ps_infos(ctx, &ps); + if (!v4l_res_change(pbi)) { + if (ctx->param_sets_from_ucode && !pbi->v4l_params_parsed) { + struct aml_vdec_ps_infos ps; + + pr_debug("set ucode parse\n"); + vvp9_get_ps_info(pbi, &ps); + /*notice the v4l2 codec.*/ + vdec_v4l_set_ps_infos(ctx, &ps); + pbi->v4l_params_parsed = true; + pbi->postproc_done = 0; + pbi->process_busy = 0; + dec_again_process(pbi); + return IRQ_HANDLED; + } + } else { + pbi->postproc_done = 0; + pbi->process_busy = 0; + dec_again_process(pbi); + return IRQ_HANDLED; } } - if (pbi->is_used_v4l) { - pbi->dec_result = DEC_V4L2_CONTINUE_DECODING; - vdec_schedule_work(&pbi->work); - } else { - continue_decoding(pbi); - pbi->postproc_done = 0; - pbi->process_busy = 0; - } + continue_decoding(pbi); + pbi->postproc_done = 0; + pbi->process_busy = 0; #ifdef MULTI_INSTANCE_SUPPORT if (pbi->m_ins_flag) @@ -8567,7 +8667,8 @@ static void vvp9_put_timer_func(struct timer_list *timer) if (pbi->m_ins_flag) { if (hw_to_vdec(pbi)->next_status - == VDEC_STATUS_DISCONNECTED) { + == VDEC_STATUS_DISCONNECTED && + !pbi->is_used_v4l) { #ifdef SUPPORT_FB_DECODING if (pbi->run2_busy) return; @@ -9558,25 +9659,6 @@ static void vp9_work(struct work_struct *work) return; } - if (pbi->dec_result == DEC_V4L2_CONTINUE_DECODING) { - struct aml_vcodec_ctx *ctx = - (struct aml_vcodec_ctx *)(pbi->v4l2_ctx); - - if (ctx->param_sets_from_ucode) { - reset_process_time(pbi); - if (wait_event_interruptible_timeout(ctx->wq, - ctx->v4l_codec_ready, - msecs_to_jiffies(500)) < 0) - return; - } - - continue_decoding(pbi); - pbi->postproc_done = 0; - pbi->process_busy = 0; - - return; - } - if (((pbi->dec_result == DEC_RESULT_GET_DATA) || (pbi->dec_result == DEC_RESULT_GET_DATA_RETRY)) && (hw_to_vdec(pbi)->next_status != @@ -9845,10 +9927,18 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) struct aml_vcodec_ctx *ctx = (struct aml_vcodec_ctx *)(pbi->v4l2_ctx); - if (ctx->param_sets_from_ucode && - !ctx->v4l_codec_ready && - pbi->v4l_params_parsed) { - ret = 0; /*the params has parsed.*/ + if (ctx->param_sets_from_ucode) { + if (pbi->v4l_params_parsed) { + if ((ctx->cap_pool.in < pbi->used_buf_num) && + v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < + run_ready_min_buf_num) + ret = 0; + } else { + if ((pbi->res_ch_flag == 1) && + ((ctx->state <= AML_STATE_INIT) || + (ctx->state >= AML_STATE_FLUSHING))) + ret = 0; + } } else if (ctx->cap_pool.in < ctx->dpb_size) { if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < run_ready_min_buf_num) |