HermanChen / mpp

Rockchip MPP(Media Process Platfrom)
162 stars 73 forks source link

hevc decode and display exception #23

Closed chllcy closed 3 years ago

chllcy commented 3 years ago

I'm use mpp_linux_cpp to decode hevc and display. when I used nvidia encode and use mpp to decode and then display. the Resolution is 2560x1440,the stride calc error。I have change hevc_hor_align to MPP_ALIGN(val, 32), and now it's displayed ok. decoder require buffer w:h [2560:1440] stride [2560:1440]

hevc is used 32x32. but when I change resolution to 800x600,the stride calc error too.and I change code to fix.

         mpp_frame_set_hor_stride(frame->frame,
-                                 (MPP_ALIGN(s->h265dctx->coded_width, 64) * s->h265dctx->nBitDepth) >> 3);
+                                 (MPP_ALIGN(s->h265dctx->coded_width, 32) * s->h265dctx->nBitDepth) >> 3);

the log shows as follow: now decoder require buffer w:h [800:600] stride [800:608] I think the stride is ok now,but it's still displayed execption. the stride correspond to MppFrameImpl(hor_stride,ver_stride) how can I fix it? the log hevc.log 微信图片_20201022181936

zinsayon commented 3 years ago

hevc dec out stride is MPP_ALIGN(val, 256) | 256; so 2560 the dec out stride is 2816 and 800 out stride is 1280 , you should get stride from get frame, no set by yourself

chllcy commented 3 years ago

@zinsayon if use MPP_ALIGN(val, 256) | 256, it will display with exception. so I change the code, and now 2560x1440 display is ok.

and use AVC(h264),the display is both ok(2560x1440,800x600)


AVC log below: decode_get_frame get info changed found. decoder require buffer w:h [2560:1440] stride [2560:1440] decode_get_frame get info changed found. decoder require buffer w:h [800:600] stride [800:608] decode_get_frame get info changed found.

zinsayon commented 3 years ago

the min stride for hevc is 64 align,avc min stride is 16,so you can't set stride small then 64 in hevc decode,if stride big then need, you can used setcrop to crop exception part

chllcy commented 3 years ago

@zinsayon with 1600x900 resolution,the avc decode and display well decoder require buffer w:h [1600:900] stride [1600:912]

but change to hevc, it displayed with exception,I find the SPS info 1600x928 1600x900

use H264BSAnalyzer.exe to play,it's ok

zinsayon commented 3 years ago

if hevc_hor_align is 64 ,hevc_ver defaut 8 align, so the stride is [1600:904] you should check the stride you set to display is right, if displayed with exception,you can dump yuv, used yuview tool to check the data

chllcy commented 3 years ago

@zinsayon Nvidia NVENC: There is no B-Frame support for HEVC encoding, and the maximum CU size is 32×32. Does this matter?

zinsayon commented 3 years ago

no matter

chllcy commented 3 years ago

@zinsayon I test with ffplay,it play ok. but with mpp dump to YUV420SP, use 7yuv,it had some problem.

image image image

zinsayon commented 3 years ago

which value you set to hor_stride ? show the code how do you write 420sp

chllcy commented 3 years ago

hi @zinsayon I had not set hor_stride,I check the code ,find that it was set by libmpp,and get the stride info from SPS.

int Codec::dump_mpp_frame_to_file(MppFrame frame, FILE *fp)
{
    RK_U32 width = 0;
    RK_U32 height = 0;
    RK_U32 h_stride = 0;
    RK_U32 v_stride = 0;
    MppFrameFormat fmt = MPP_FMT_YUV420SP;
    MppBuffer buffer = NULL;
    RK_U8 *base = NULL;

    if (!fp || !frame)
        return -1;

    width = mpp_frame_get_width(frame);
    height = mpp_frame_get_height(frame);
    h_stride = mpp_frame_get_hor_stride(frame);
    v_stride = mpp_frame_get_ver_stride(frame);
    fmt = mpp_frame_get_fmt(frame);
    buffer = mpp_frame_get_buffer(frame);

    if(!buffer)
        return -2;

    base = (RK_U8 *)mpp_buffer_get_ptr(buffer);
    {
        RK_U32 i;
        RK_U8 *base_y = base;
        RK_U8 *base_u = base + h_stride * v_stride;
        RK_U8 *base_v = base_u + h_stride * v_stride / 4;

        for (i = 0; i < height; i++, base_y += h_stride)
            fwrite(base_y, 1, width, fp);
        for (i = 0; i < height / 2; i++, base_u += h_stride / 2)
            fwrite(base_u, 1, width / 2, fp);
        for (i = 0; i < height / 2; i++, base_v += h_stride / 2)
            fwrite(base_v, 1, width / 2, fp);
    }

    return 0;
}
zinsayon commented 3 years ago

due to the output is 420sp so you dump uv is no right RK_U8 base_uv = base + h_stride v_stride; for (i = 0; i < height / 2; i++, base_uv += h_stride ) fwrite(base_uv , 1, width, fp);

mo123 commented 2 years ago

@chllcy

You know how I can fix this? If I play any H265 video in Android and the height is not divisible by 16, the video doesn't play. It is something to do with stride, same as on Linux.

Video having a problem Video Resolution 1920x952p, Buffer Resolution 1920x960p, they don't match because of stride. https://mega.nz/file/Q7QVFKJA#DGRBWtU2jVnKqBUdWJ_xGq_OGcQTut3mhUppxe-En3s

Video that can play correctly 960 height, 16 aligned - Video resolution and Video dimension is 1920x960p https://mega.nz/file/A3IXwAzA#hnyYLtzXzpFBM2zxAgc-8_fUD5iDGCpzTEL9APpdeSg

What file did you modify and what changed, can you help?

HermanChen commented 2 years ago

Can you run mpi_dec_test and try input the raw steam?

mo123 commented 2 years ago

Can you run mpi_dec_test and try input the raw steam?

Is there an easy command to try mpi_dec_test on Android or Linux?

Both these videos can't play but if I re-encode them and change the height to 960 then they both play correctly. Height 808 pixels https://mega.nz/file/gyw2iSyJ#PVkglqGQYg8xGTb10aYJr52YlyZh3nQEFKWbg5SPYp4 Height 792 pixles https://mega.nz/file/s6ZWmDYQ#NfvKsU-dN3Dg5_Qdd34ac6JFjGwMiYWpP6_4ZORbhVs

If in below 2 files I change the alignment from 64 to 32 then the 2 videos start playing in Android 11 but the whole videos are green and show a double image.

h265d_refs.c mpp_frame_set_hor_stride(frame->frame, (MPP_ALIGN(s->h265dctx->coded_width, 32) * s->h265dctx->nBitDepth) >> 3);

static RK_U32 hor_align_64(RK_U32 val) { return MPP_ALIGN(val, 32);

hal_h265d_rkv.c stride_y = ((MPP_ALIGN(width, 32)