rockchip-linux / mpp

Media Process Platform (MPP) module
532 stars 161 forks source link

mpp无法解码h264但可以解码h265 #88

Open Rereflyer opened 5 years ago

Rereflyer commented 5 years ago

我是仿照mpi_dec_test.c里面的方法,将h264的视频采用不分帧的方式处理的,设置如下: mpi_cmd = MPP_DEC_SET_PARSER_SPLIT_MODE; param = &need_split; ret = mpi->control(ctx, mpi_cmd, param); if (MPP_OK != ret) { mpp_err("mpi->control failed\n"); goto MPP_TEST_OUT; }

ret = mpp_init(ctx, MPP_CTX_DEC, type);
if (MPP_OK != ret) {
    mpp_err("mpp_init failed\n");
    goto MPP_TEST_OUT;
}

然后,从输入的帧中取出数据(rtspsrc->rtph264depay->h264parse,数据来自h264parse的输出),并调用decode_put_packet()函数 codec_data = gst_buffer_ref (frame->input_buffer); gst_buffer_map (codec_data, &mapinfo, GST_MAP_READ); mpp_packet_init (&mpkt, mapinfo.data, mapinfo.size);

do {
  mret = self->mpi->decode_put_packet (self->mpp_ctx, mpkt);
} while (MPP_ERR_BUFFER_FULL == mret);

再调用decode_get_frame()函数: MppFrame mframe = NULL; mret = self->mpi->decode_get_frame (self->mpp_ctx, &mframe);

很奇怪的是,每次decode_get_frame()返回的mframe非NULL(也就是说正常的),但是调用如下函数 mpp_frame_get_width (mframe); mpp_frame_get_height (mframe); mpp_frame_get_hor_stride (mframe); mpp_frame_get_ver_stride (mframe); 得到的值都为0,说明并没有解码成功。

我检查了一下,mpkt的数据依次是: frame 0: 00 00 00 01 09 F0 00 00 00 01 67 64 00 2A AD 84 01 0C 20 08 ... frame 1: 00 00 00 01 09 F0 00 00 00 01 68 EE 3C B0 00 ... ... 看起来PPS,SPS,I帧,这些都是正常的。

所以,我有两个疑问: 1、理论上来说,采用不分帧的方式,由mpp自己分帧,decode_put_packet()送入frame 0,decode_get_frame()得到的mframe为NULL,然后再decode_put_packet()送入frame 1,decode_get_frame()得到的mframe依然为NULL,多个frame之后,才能真正解出真实的一帧图像,而不是像现在,每一个mframe都非NULL;

2、如果上述的H264视频源换成H265,一切都又是正常的,对于视频源的前几帧,decode_get_frame()得到的mframe为NULL,送入足够的frame时,得到正常的mframe;

HermanChen commented 5 years ago

mpp_packet_init (&mpkt, mapinfo.data, mapinfo.size); 这个 mpkt, mapinfo.data 是什么数据?是指针么?要先看 decode_get_frame 的函数返回值是否是 MPP_OK,如果不是,说明流程出错,mframe 的返回值是无效的。 使用 mpp 内部分帧的话,解码的数据需要能分帧出一帧图像,mpp 内部才会去解码一次,get_frame 才能得到图像。

HermanChen commented 5 years ago

可能 264 和 265 的源不同,内容不一样,264 比较大,需要凑上几包数据才能出一帧,265 数据比较小,一包数据就有一帧。

Rereflyer commented 5 years ago

mpp_packet_init (&mpkt, mapinfo.data, mapinfo.size); 这个 mpkt, mapinfo.data 是什么数据?是指针么?要先看 decode_get_frame 的函数返回值是否是 MPP_OK,如果不是,说明流程出错,mframe 的返回值是无效的。 使用 mpp 内部分帧的话,解码的数据需要能分帧出一帧图像,mpp 内部才会去解码一次,get_frame 才能得到图像。

感谢回复!

mpkt定义如下:MppPacket mpkt = NULL; mapinfo.data就是前一级送过来的视频帧数据,是一个指针; mapinfo.size表示这个视频帧的大小。 我刚刚确认了,decode_get_frame()函数每次都是返回MPP_OK,而且得到的mframe也是非NULL。

我打印数据看了一下,decode_put_packet()送进去的第一帧数据是SPS(00 00 00 01 67),然后直接调用decode_get_frame(),理论上来说,返回MPP_OK,但是mframe应该为NULL,因为此时并不能解码一帧真实的图像,数据不够。 decode_put_packet()送进去的第二帧数据是PPS(00 00 00 01 68),然后直接调用decode_get_frame(),同样的,返回MPP_OK,但是mframe应该为NULL,因为此时并不能解码一帧真实的图像,数据不够。 ... 后面过了好几帧,才会有I帧数据送进去...

所以,我怀疑,是不是设置mpp内部分帧没有生效,mpp decoder将我送入的每一帧数据都当作一个完整的数据帧来解码了?

HermanChen commented 5 years ago

不用客气。 SPS 和 PPS 不是图像数据,是无法解码出图像的,需要有 I 帧码流输入之后,解码才会真正开始输出图像。 如果对分帧标志有疑问,可以跟踪下 split 标志位的传递是否有问题(正常是不会有问题的,除非有本地修改)。

Rereflyer commented 5 years ago

不用客气。 SPS 和 PPS 不是图像数据,是无法解码出图像的,需要有 I 帧码流输入之后,解码才会真正开始输出图像。 如果对分帧标志有疑问,可以跟踪下 split 标志位的传递是否有问题(正常是不会有问题的,除非有本地修改)。

跟到mpp里面看了,打印出来的flag确实是1,如下: mpp: MPP_DEC_SET_PARSER_SPLIT_MODE flag is 1

我想确认一下,如果split flag设为1之后,不管decode_put_packet()送多少次数据进去,只要不够完整的一帧图像,decode_get_frame()都得不到mframe数据的吗? 现在的现象就是虽然设了flag为1,但还是按照默认的分帧方式在处理,这点很让人疑惑。

HermanChen commented 5 years ago

是的,put_packet 的数据不足一帧的,get_frame 还是无法得到结果,这是正常的 配置分帧模式要要 init 之前进行

Rereflyer commented 5 years ago

是的,put_packet 的数据不足一帧的,get_frame 还是无法得到结果,这是正常的 配置分帧模式要要 init 之前进行

配置分帧都是在mpp_init()之前进行的。

尝试了几种方式,还是得不到想要的结果,我想请教一下,什么情况下,会出现如下我描述的情况: 1、 送入一帧数据,调用decode_put_packet (self->mpp_ctx, mpkt);

2、 获取frame,调用decode_get_frame (self->mpp_ctx, &mframe); 其中,decode_get_frame返回MPP_OK,读取mframe的信息如下: (1)format = mpp_frame_get_fmt (mframe); //返回值为MPP_FMT_YUV420SP (2)width = mpp_frame_get_width (mframe); //返回值为0 (3)height = mpp_frame_get_height (mframe); //返回值为0 (4)hor_stride = mpp_frame_get_hor_stride (mframe); //返回值为0 (5)ver_stride = mpp_frame_get_ver_stride (mframe); //返回值为0

HermanChen commented 5 years ago

mframe 内部数据全为 0 这个不太可能,看一下 info_change 或者 eos 标志位有没有置起来。 eos 是有可能出现全为 0 的空帧输出情况。可以试试 mpi_dec_mt_test 多线程测试的方式,把 put / get 分到两个线程看看。

fuqiankun commented 4 years ago

mpp在解码h265时出现这个问题,是什么原因? @HermanChen 一直解析出来的MppFrame是null....

mpp[30463]: H265D_PARSER: PPS id out of range: 0
mpp[30463]: H265D_PARSER: hls_slice_header error ret = -1004
mpp[30463]: H265D_PARSER: Error parsing NAL unit #0,error ret = 0xd.
mpp[30463]: H265D_PARSER: current stream is no right skip it (nil)