Skip to content

Commit

Permalink
media: cedrus: Fix decoding for some HEVC videos
Browse files Browse the repository at this point in the history
It seems that for some HEVC 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 several videos
with this fix are now decoded correctly and there is no regression with
others.

Without this fix, those same videos totally crash HEVC decoder (other
decoder engines are unaffected). After decoding those problematic
videos, HEVC decoder always returns only green image (all zeros).
Only complete HW reset helps.

This fix is similar to that for H264.

Signed-off-by: Jernej Skrabec <[email protected]>
Acked-by: Paul Kocialkowski <[email protected]>
Signed-off-by: Hans Verkuil <[email protected]>
Signed-off-by: Mauro Carvalho Chehab <[email protected]>
  • Loading branch information
jernejsk authored and mchehab committed Jan 9, 2020
1 parent e611164 commit 7678c54
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 3 deletions.
25 changes: 22 additions & 3 deletions drivers/staging/media/sunxi/cedrus/cedrus_h265.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Copyright (C) 2018 Bootlin
*/

#include <linux/delay.h>
#include <linux/types.h>

#include <media/videobuf2-dma-contig.h>
Expand Down Expand Up @@ -220,6 +221,23 @@ static void cedrus_h265_pred_weight_write(struct cedrus_dev *dev,
}
}

static void cedrus_h265_skip_bits(struct cedrus_dev *dev, int num)
{
int count = 0;

while (count < num) {
int tmp = min(num - count, 32);

cedrus_write(dev, VE_DEC_H265_TRIGGER,
VE_DEC_H265_TRIGGER_FLUSH_BITS |
VE_DEC_H265_TRIGGER_TYPE_N_BITS(tmp));
while (cedrus_read(dev, VE_DEC_H265_STATUS) & VE_DEC_H265_STATUS_VLD_BUSY)
udelay(1);

count += tmp;
}
}

static void cedrus_h265_setup(struct cedrus_ctx *ctx,
struct cedrus_run *run)
{
Expand Down Expand Up @@ -280,10 +298,9 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,

/* Source offset and length in bits. */

reg = slice_params->data_bit_offset;
cedrus_write(dev, VE_DEC_H265_BITS_OFFSET, reg);
cedrus_write(dev, VE_DEC_H265_BITS_OFFSET, 0);

reg = slice_params->bit_size - slice_params->data_bit_offset;
reg = slice_params->bit_size;
cedrus_write(dev, VE_DEC_H265_BITS_LEN, reg);

/* Source beginning and end addresses. */
Expand Down Expand Up @@ -316,6 +333,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
/* Initialize bitstream access. */
cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_INIT_SWDEC);

cedrus_h265_skip_bits(dev, slice_params->data_bit_offset);

/* Bitstream parameters. */

reg = VE_DEC_H265_DEC_NAL_HDR_NAL_UNIT_TYPE(slice_params->nal_unit_type) |
Expand Down
1 change: 1 addition & 0 deletions drivers/staging/media/sunxi/cedrus/cedrus_regs.h
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@

#define VE_DEC_H265_TRIGGER (VE_ENGINE_DEC_H265 + 0x34)

#define VE_DEC_H265_TRIGGER_TYPE_N_BITS(x) (((x) & 0x3f) << 8)
#define VE_DEC_H265_TRIGGER_STCD_VC1 (0x02 << 4)
#define VE_DEC_H265_TRIGGER_STCD_AVS (0x01 << 4)
#define VE_DEC_H265_TRIGGER_STCD_HEVC (0x00 << 4)
Expand Down

0 comments on commit 7678c54

Please sign in to comment.