This is an automatic generated email to let you know that the following patch 
were queued:

Subject: media: cedrus: Fix decoding for some H264 videos
Author:  Jernej Skrabec <jernej.skra...@siol.net>
Date:    Sat Oct 26 09:27:51 2019 +0200

It seems that for some H264 videos at least one bitstream parsing
trigger must be called in order to be decoded correctly. There is no
explanation why this helps, but it was observed that two sample videos
with this fix are now decoded correctly and there is no regression with
others.

Acked-by: Paul Kocialkowski <paul.kocialkow...@bootlin.com>
Signed-off-by: Jernej Skrabec <jernej.skra...@siol.net>
Signed-off-by: Hans Verkuil <hverkuil-ci...@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+sams...@kernel.org>

 drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 30 +++++++++++++++++++++---
 drivers/staging/media/sunxi/cedrus/cedrus_regs.h |  3 +++
 2 files changed, 30 insertions(+), 3 deletions(-)

---

diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c 
b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index cd85668f9c80..db336449c4f2 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -6,6 +6,7 @@
  * Copyright (c) 2018 Bootlin
  */
 
+#include <linux/delay.h>
 #include <linux/types.h>
 
 #include <media/videobuf2-dma-contig.h>
@@ -289,6 +290,28 @@ static void cedrus_write_pred_weight_table(struct 
cedrus_ctx *ctx,
        }
 }
 
+/*
+ * It turns out that using VE_H264_VLD_OFFSET to skip bits is not reliable. In
+ * rare cases frame is not decoded correctly. However, setting offset to 0 and
+ * skipping appropriate amount of bits with flush bits trigger always works.
+ */
+static void cedrus_skip_bits(struct cedrus_dev *dev, int num)
+{
+       int count = 0;
+
+       while (count < num) {
+               int tmp = min(num - count, 32);
+
+               cedrus_write(dev, VE_H264_TRIGGER_TYPE,
+                            VE_H264_TRIGGER_TYPE_FLUSH_BITS |
+                            VE_H264_TRIGGER_TYPE_N_BITS(tmp));
+               while (cedrus_read(dev, VE_H264_STATUS) & 
VE_H264_STATUS_VLD_BUSY)
+                       udelay(1);
+
+               count += tmp;
+       }
+}
+
 static void cedrus_set_params(struct cedrus_ctx *ctx,
                              struct cedrus_run *run)
 {
@@ -299,14 +322,13 @@ static void cedrus_set_params(struct cedrus_ctx *ctx,
        struct vb2_buffer *src_buf = &run->src->vb2_buf;
        struct cedrus_dev *dev = ctx->dev;
        dma_addr_t src_buf_addr;
-       u32 offset = slice->header_bit_size;
-       u32 len = (slice->size * 8) - offset;
+       u32 len = slice->size * 8;
        unsigned int pic_width_in_mbs;
        bool mbaff_pic;
        u32 reg;
 
        cedrus_write(dev, VE_H264_VLD_LEN, len);
-       cedrus_write(dev, VE_H264_VLD_OFFSET, offset);
+       cedrus_write(dev, VE_H264_VLD_OFFSET, 0);
 
        src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
        cedrus_write(dev, VE_H264_VLD_END,
@@ -325,6 +347,8 @@ static void cedrus_set_params(struct cedrus_ctx *ctx,
        cedrus_write(dev, VE_H264_TRIGGER_TYPE,
                     VE_H264_TRIGGER_TYPE_INIT_SWDEC);
 
+       cedrus_skip_bits(dev, slice->header_bit_size);
+
        if (((pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) &&
             (slice->slice_type == V4L2_H264_SLICE_TYPE_P ||
              slice->slice_type == V4L2_H264_SLICE_TYPE_SP)) ||
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h 
b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
index 6fc28d21a6c7..4275a307d282 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
@@ -541,13 +541,16 @@
                                         VE_H264_CTRL_SLICE_DECODE_INT)
 
 #define VE_H264_TRIGGER_TYPE           0x224
+#define VE_H264_TRIGGER_TYPE_N_BITS(x)         (((x) & 0x3f) << 8)
 #define VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE  (8 << 0)
 #define VE_H264_TRIGGER_TYPE_INIT_SWDEC                (7 << 0)
+#define VE_H264_TRIGGER_TYPE_FLUSH_BITS                (3 << 0)
 
 #define VE_H264_STATUS                 0x228
 #define VE_H264_STATUS_VLD_DATA_REQ_INT                
VE_H264_CTRL_VLD_DATA_REQ_INT
 #define VE_H264_STATUS_DECODE_ERR_INT          VE_H264_CTRL_DECODE_ERR_INT
 #define VE_H264_STATUS_SLICE_DECODE_INT                
VE_H264_CTRL_SLICE_DECODE_INT
+#define VE_H264_STATUS_VLD_BUSY                        BIT(8)
 
 #define VE_H264_STATUS_INT_MASK                        VE_H264_CTRL_INT_MASK
 

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
https://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

Reply via email to