media: cedrus: h264: Support multiple slices per frame
authorJernej Skrabec <jernej.skrabec@siol.net>
Fri, 11 Oct 2019 09:32:45 +0000 (06:32 -0300)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Mon, 21 Oct 2019 10:43:04 +0000 (07:43 -0300)
With recent changes, support for decoding multi-slice frames can be
easily added now.

Signal VPU if current slice is first in frame or not and add information
about first macroblock coordinates.

When frame contains multiple slices and driver works in slice mode, it's
more efficient to hold capture buffer in queue until all slices of a
same frame are decoded.

Add support for that to Cedrus driver by exposing and implementing
V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF capability.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
[hverkuil-cisco@xs4all.nl: rewritten to use v4l2_m2m_buf_done_and_job_finish]
[hverkuil-cisco@xs4all.nl: removed unnecessary (u32) cast]
[hverkuil-cisco@xs4all.nl: use new_frame v4l2_m2m_ctx bool]
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/staging/media/sunxi/cedrus/cedrus_h264.c
drivers/staging/media/sunxi/cedrus/cedrus_hw.c
drivers/staging/media/sunxi/cedrus/cedrus_video.c

index d6a782703c9b0643ded926c6384a229f27ac91d0..cd85668f9c80c2080072bbcf2b120aa41d23ed7a 100644 (file)
@@ -301,6 +301,8 @@ static void cedrus_set_params(struct cedrus_ctx *ctx,
        dma_addr_t src_buf_addr;
        u32 offset = slice->header_bit_size;
        u32 len = (slice->size * 8) - offset;
+       unsigned int pic_width_in_mbs;
+       bool mbaff_pic;
        u32 reg;
 
        cedrus_write(dev, VE_H264_VLD_LEN, len);
@@ -370,12 +372,20 @@ static void cedrus_set_params(struct cedrus_ctx *ctx,
                reg |= VE_H264_SPS_DIRECT_8X8_INFERENCE;
        cedrus_write(dev, VE_H264_SPS, reg);
 
+       mbaff_pic = !(slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) &&
+                   (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD);
+       pic_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1;
+
        // slice parameters
        reg = 0;
+       reg |= ((slice->first_mb_in_slice % pic_width_in_mbs) & 0xff) << 24;
+       reg |= (((slice->first_mb_in_slice / pic_width_in_mbs) *
+                (mbaff_pic + 1)) & 0xff) << 16;
        reg |= decode->nal_ref_idc ? BIT(12) : 0;
        reg |= (slice->slice_type & 0xf) << 8;
        reg |= slice->cabac_init_idc & 0x3;
-       reg |= VE_H264_SHS_FIRST_SLICE_IN_PIC;
+       if (ctx->fh.m2m_ctx->new_frame)
+               reg |= VE_H264_SHS_FIRST_SLICE_IN_PIC;
        if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)
                reg |= VE_H264_SHS_FIELD_PIC;
        if (slice->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)
index a942cd9bed57e0ab5db61dd8747621dfbb55a6de..e7e18424bab1eb4386692b680265136cda140ebc 100644 (file)
@@ -103,7 +103,6 @@ static irqreturn_t cedrus_irq(int irq, void *data)
 {
        struct cedrus_dev *dev = data;
        struct cedrus_ctx *ctx;
-       struct vb2_v4l2_buffer *src_buf, *dst_buf;
        enum vb2_buffer_state state;
        enum cedrus_irq_status status;
 
@@ -121,24 +120,13 @@ static irqreturn_t cedrus_irq(int irq, void *data)
        dev->dec_ops[ctx->current_codec]->irq_disable(ctx);
        dev->dec_ops[ctx->current_codec]->irq_clear(ctx);
 
-       src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
-       dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-
-       if (!src_buf || !dst_buf) {
-               v4l2_err(&dev->v4l2_dev,
-                        "Missing source and/or destination buffers\n");
-               return IRQ_HANDLED;
-       }
-
        if (status == CEDRUS_IRQ_ERROR)
                state = VB2_BUF_STATE_ERROR;
        else
                state = VB2_BUF_STATE_DONE;
 
-       v4l2_m2m_buf_done(src_buf, state);
-       v4l2_m2m_buf_done(dst_buf, state);
-
-       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+       v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx,
+                                        state);
 
        return IRQ_HANDLED;
 }
index 3ec3a2db790c9140a20300339556b1e9fb8d94fb..f745f66c44406e6caaae8139e0b149705390d874 100644 (file)
@@ -303,6 +303,17 @@ static int cedrus_s_fmt_vid_out(struct file *file, void *priv,
 
        ctx->src_fmt = f->fmt.pix;
 
+       switch (ctx->src_fmt.pixelformat) {
+       case V4L2_PIX_FMT_H264_SLICE:
+               vq->subsystem_flags |=
+                       VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
+               break;
+       default:
+               vq->subsystem_flags &=
+                       ~VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
+               break;
+       }
+
        /* Propagate colorspace information to capture. */
        ctx->dst_fmt.colorspace = f->fmt.pix.colorspace;
        ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func;
@@ -336,6 +347,9 @@ const struct v4l2_ioctl_ops cedrus_ioctl_ops = {
        .vidioc_streamon                = v4l2_m2m_ioctl_streamon,
        .vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
 
+       .vidioc_try_decoder_cmd         = v4l2_m2m_ioctl_stateless_try_decoder_cmd,
+       .vidioc_decoder_cmd             = v4l2_m2m_ioctl_stateless_decoder_cmd,
+
        .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
 };