MPP 无法解码
程序在解码时到ret = mpi->decode_get_frame(ctx, &frame)在这里返回0,但是去不了frame,一读取frame,系统崩溃,frame返回为NULL,明明返回时0,成功,为何不能读取,
返回 0 代表流程正常,没有错误出现,具体有没有取到数据,还是要读 frame 做判断
为什么同样的H264文件,在软解码可以解,MPP不能解,是不是MPP解码不兼容
Hi3516C 视频流无法解码
void VideoDecoder::Decoder()
{
RK_U32 pkt_done = 0;
RK_U32 pkt_eos = 0;
RK_U32 err_info = 0;
MPP_RET ret = MPP_OK;
int size;
MppFrame frame = NULL;
RK_U32 width;
RK_U32 height;
RK_U32 hor_stride;
RK_U32 ver_stride;
RK_U32 buf_size;
while(1)
{
//printf("start Decoder\n");
if(IsStop==1)
break;
//printf("IsStop = %d\n",IsStop);
//printf("readpos = %d, writepos = %d\n",readpos, writepos);
if(readpos!=writepos)
{
printf("readpos = %d, writepos = %d\n",readpos, writepos);
size=m_pDecode[readpos].size;
memcpy(buf, m_pDecode[readpos].pbuff, size);
// write data to packet
mpp_packet_write(packet, 0, buf, size); //把文件读到的数据写入packet
// reset pos and set valid length
mpp_packet_set_pos(packet, buf); //设置有效数据的起始地址
mpp_packet_set_length(packet, size); //设置有效数据的长度
do
{
RK_S32 times = 5;
if (!pkt_done)
{
ret = mpi->decode_put_packet(ctx, packet); //视频解码输入接口
if (MPP_OK == ret)
{
pkt_done = 1;
}
}
do
{
RK_S32 get_frm = 0;
RK_U32 frm_eos = 0;
try_again:
ret = mpi->decode_get_frame(ctx, &frame); //frame 解码出来的帧
if (MPP_ERR_TIMEOUT == ret)
{
if (times > 0)
{
times--;
msleep(2);
goto try_again;
}
mpp_err("decode_get_frame failed too much time\n");
}
if (MPP_OK != ret)
{
mpp_err("decode_get_frame failed ret %d\n", ret);
break;
}
if (frame)
{
if (mpp_frame_get_info_change(frame))
{
width = mpp_frame_get_width(frame); //获取图像宽度
height = mpp_frame_get_height(frame); //获取图像高度
hor_stride = mpp_frame_get_hor_stride(frame); //获取buffer缓存宽度
ver_stride = mpp_frame_get_ver_stride(frame); //获取buffer缓存高度
buf_size = mpp_frame_get_buf_size(frame); //获取图像需要分配的缓存大小
printf("buf_size = %d\n",buf_size);
mpp_log("decode_get_frame get info changed found\n");
mpp_log("decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d",
width, height, hor_stride, ver_stride, buf_size);
if (NULL == frm_grp)
{
/* If buffer group is not set create one and limit it */
ret = mpp_buffer_group_get_internal(&frm_grp, MPP_BUFFER_TYPE_ION); //解码器内存分配
if (ret)
{
mpp_err("get mpp buffer group failed ret %d\n", ret);
break;
}
/* Set buffer to mpp decoder */
ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, frm_grp); //半内部分配模式
if (ret)
{
mpp_err("set buffer group failed ret %d\n", ret);
break;
}
}
else
{
/* If old buffer group exist clear it */
ret = mpp_buffer_group_clear(frm_grp); //释放内存
if (ret)
{
mpp_err("clear buffer group failed ret %d\n", ret);
break;
}
}
/* Use limit config to limit buffer count to 24 with buf_size */
ret = mpp_buffer_group_limit_config(frm_grp, buf_size, 24); //限制最多24个buf
if (ret)
{
mpp_err("limit buffer group failed ret %d\n", ret);
break;
}
/*
* All buffer group config done. Set info change ready to let
* decoder continue decoding
*/
ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL); //分配设置确认
if (ret)
{
mpp_err("info change ready failed ret %d\n", ret);
break;
}
}
else
{
err_info = mpp_frame_get_errinfo(frame) | mpp_frame_get_discard(frame); //检查获得的帧数据是否正常
if (err_info)
{
mpp_log("decoder_get_frame get err info:%d discard:%d.\n",
mpp_frame_get_errinfo(frame), mpp_frame_get_discard(frame));
}
mpp_log("decode_get_frame get frame 1111\n");
if (!err_info)
{
//解码后数据的使用方法
m_videoback((char*)frame,hor_stride,ver_stride);
printf("m_videoback OK, Width = %d, Height = %d\n",hor_stride,ver_stride);
}
}
frm_eos = mpp_frame_get_eos(frame);
mpp_frame_deinit(&frame);
frame = NULL;
get_frm = 1;
}
if (pkt_done && !frm_eos)
{
msleep(1);
continue;
}
if (frm_eos)
{
// mpp_log("found last frame\n");
break;
}
if (get_frm)
continue;
break;
}while(1);
if (pkt_done)
{
pkt_done = 0;
break;
}
/*
* why sleep here:
* mpi->decode_put_packet will failed when packet in internal queue is
* full,waiting the package is consumed .Usually hardware decode one
* frame which resolution is 1080p needs 2 ms,so here we sleep 3ms
* * is enough.
*/
msleep(1);
}while(1);
if(readpos<(MAX_NUMD-1))
readpos++;
else
readpos=0;
usleep(20000);
}
}
pthread_exit(&dwTheadId);
}
这是我的解码流程
void VideoDecoder::InitVideoDecoder(VideoDecoderBack pvideoback)
{
m_videoback=pvideoback;
ret = MPP_OK;
mpi_cmd = MPP_CMD_BASE;
need_split = 1;
output_block = MPP_POLL_BLOCK;
// paramter for resource malloc
width = 1920;
height = 1080;
type = MPP_VIDEO_CodingAVC;
packet_size = PACKETSIZE;
buf = mpp_malloc(char, packet_size); //分配了256K char类型的buf, packet_size = 256K
if (NULL == buf) {
mpp_err("mpi_dec_test malloc input stream buffer failed\n");
Mpp_test_out();
}
ret = mpp_packet_init(&packet, buf, packet_size); //一个新的packet, 数据buf, 大小packet_size
if (ret) {
mpp_err("mpp_packet_init failed\n");
Mpp_test_out();
}
mpp_log("mpi_dec_test decoder test start w %d h %d type %d\n", width, height, type);
// decoder demo
ret = mpp_create(&ctx, &mpi); //获取 MppCtx 实例以及 MppApi 结构体
if (MPP_OK != ret) {
mpp_err("mpp_create failed\n");
Mpp_test_out();
}
// NOTE: decoder split mode need to be set before init
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");
Mpp_test_out();
}
ret = mpp_init(ctx, MPP_CTX_DEC, type); //初始化 MppCtx 实例, 解码模式,H264格式
if (MPP_OK != ret) {
mpp_err("mpp_init failed\n");
Mpp_test_out();
}
}
这是初始化MPP,你看看有何问题
能否帮我解惑
有没有结果
先把码流给 ffmpeg 解码看一下能否正常。 mpp 只能处理没有封装的裸码流,你看下码流能不能用 elecard 打开,是否码流本身非标。
和楼主遇到了完全一模一样的问题。解出来的frame是NULL。 同样的文件,我用ffmpeg软解码,都没问题。用mpp解不出来。不知道是什么原因 但有些文件,用mpp又可以正常
解码取数据的方式要看是阻塞还是非阻塞的。
解码取数据的方式要看是阻塞还是非阻塞的。
HI Chen: 我用ffmpeg -i video.mp4 -codec copy -f h264 video.h264提取出H264的裸流以后,就可以播放了 可能是我ffmpeg解完封装后的喂给mpp的packet不是H264纯码流
我想再请教一下,mpp解码后的像素格式只能是YUV420sp吗?因为我用SDL2进行显示,SDL2对YUV数据的接口只支持YUV420p和YV12。我这里需要对YUV420sp数据进行一次转换,这个转换非常耗时,有没有可能,mpp直接解码出YUV420p的数据?
谢谢~
硬件只支持 420sp 的输出,420p 的格式对硬件的数据访问不太友好,可以试试用 rga 来做 sp -> p 的这个转换
解码取数据的方式要看是阻塞还是非阻塞的。
请问怎么设置MMP解码方式。
能否帮我解惑
楼主是否解决了问题,遇到趴您同样的问题。受教了。