mpp 解码之后出现绿屏,花屏等现象,一般是由于h265数据对齐问题,
h264视频对齐方式为16位对齐方法。
h265视频对齐方式位256奇数对齐。
h265对齐之后的宽高可通过 MPP函数中的
reallyWidth = static_cast<int>( mpp_frame_get_hor_stride(frame));
reallyHight = static_cast<int>( mpp_frame_get_ver_stride(frame));
可将hor_stride 与 ver_stride 填入RGA 中的wrapbuffer_virtualaddr() 函数
src = wrapbuffer_virtualaddr(srcdata, reallyWidth, reallyHight, SRC_FORMAT);
dst = wrapbuffer_virtualaddr(dst_buf, srcWidth, srcHight, DST_FORMAT);
注意 上述代码中的srcWidth与srcHight是真实的宽高
此时解码出的图像有存在绿边现象。
作者用的qt,可通过Qimage 的copy函数进行拷贝,去除,也可通过rga裁剪进行去除
完整c文件如下:
mpp.c
#include "mppdecode.h"
void MppDecode::slotGetSendMppSrcImg()
{
srcImgSend = true;
}
void MppDecode::setWidthHight(int width, int hight)
{
// initSrcHight = hight;
// initSrcWidth = width;
// while(hight%16 != 0)
// {
// hight++;
// }
srcHight = hight;
srcWidth = width;
}
size_t MppDecode::mpp_buffer_group_usage(MppBufferGroup group)
{
if (nullptr == group)
{
mpp_err_f("input invalid group %p\n", group);
return MPP_BUFFER_MODE_BUTT;
}
MppBufferGroupImpl *p = (MppBufferGroupImpl *)group;
return p->usage;
}
int MppDecode::decode_simple(MppDecode::MpiDecLoopData *data, AVPacket *av_packet)
{
RK_U32 pkt_done = 0;
RK_U32 pkt_eos = 0;
RK_U32 err_info = 0;
MPP_RET ret = MPP_OK;
MppCtx ctx = data->ctx;
MppApi *mpi = data->mpi;
MppPacket packet = nullptr;
MppFrame frame = nullptr;
ret = mpp_packet_init(&packet, av_packet->data, av_packet->size);
if(ret < 0)
{
return -1;
}
mpp_packet_set_pts(packet, av_packet->pts);
//qDebug()<<"av_packet->data:"<<av_packet->data;
do {
RK_S32 times = 5;
// send the packet first if packet is not done
if (!pkt_done) {
ret = mpi->decode_put_packet(ctx, packet);
if (MPP_OK == ret)
pkt_done = 1;
}
// then get all available frame and release
do {
RK_S32 get_frm = 0;
RK_U32 frm_eos = 0;
try_again:
ret = mpi->decode_get_frame(ctx, &frame);
if (MPP_ERR_TIMEOUT == ret) {
if (times > 0) {
times--;
mmsleep(2);
goto try_again;
}
mpp_err("decode_get_frame failed too much time\n");
}
//qDebug()<< "mpp_log" <<"get MPP_OK"<<MPP_OK;
if (MPP_OK != ret) {
mpp_err("decode_get_frame failed ret %d\n", ret);
break;
}
if (frame)
{
if (mpp_frame_get_info_change(frame)) {
RK_U32 width = mpp_frame_get_width(frame);
RK_U32 height = mpp_frame_get_height(frame);
RK_U32 hor_stride = mpp_frame_get_hor_stride(frame);
RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
RK_U32 buf_size = mpp_frame_get_buf_size(frame);
qDebug()<<"mpp_log :"<<"decode_get_frame get info changed found";
qDebug("mpp_log :decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d",
width, height, hor_stride, ver_stride, buf_size);
ret = mpp_buffer_group_get_internal(&data->frm_grp, MPP_BUFFER_TYPE_ION);
if (ret) {
mpp_err("get mpp buffer group failed ret %d\n", ret);
break;
}
mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp);
mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, nullptr);
} else {
err_info = mpp_frame_get_errinfo(frame) | mpp_frame_get_discard(frame);
if (err_info) {
qDebug("decoder_get_frame get err info:%d discard:%d.\n",
mpp_frame_get_errinfo(frame), mpp_frame_get_discard(frame));
}
data->frame_count++;
//qDebug("decode_get_frame get frame %d\n", data->frame_count);
if (!err_info){
//qDebug("no err_info");
//qDebug("frame:%p",frame);
MppBuffer buff = mpp_frame_get_buffer(frame);
if(dst_buf == nullptr)
{
reallyWidth = static_cast<int>( mpp_frame_get_hor_stride(frame));
reallyHight = static_cast<int>( mpp_frame_get_ver_stride(frame));
// //RK_U32 buf_size = mpp_frame_get_buf_size(frame);
qDebug() << "srcHight"<<srcWidth<<"srcHight"<<srcHight;
qDebug() << ".reallyWidth"<<reallyWidth<<".reallyHight"<<reallyHight;
//dst_buf = (char*)malloc(srcWidth * srcHight * get_bpp_from_format(DST_FORMAT));
dst_buf = (char*)malloc(reallyWidth * reallyHight * get_bpp_from_format(DST_FORMAT));
//dstResize_buf = (char*)malloc(reallyWidth*reallyHight*get_bpp_from_format(DST_FORMAT));
}
convertdata((char *)mpp_buffer_get_ptr(buff),dst_buf);
//convertdata((char *)mpp_buffer_get_ptr(buff),dst_buf,dstResize_buf);
QImage qimg((uchar *)dst_buf,srcWidth,srcHight,QImage::Format_RGB888);
if(qimg.isNull())
{
qDebug("空的");
}
// QImage ResizeImg((uchar *)dstResize_buf,416,416,QImage::Format_RGB888);
emit MySigSendMppImg(qimg.copy(0,0,2560-256,1440));
//emit MySigSendMppImg(qimg.copy());
// if(srcImgSend)
// {
// srcImgSend = false;
// QImage Img((uchar *)dst_buf,416,416,QImage::Format_RGB888);
// emit MySigSendMppImgSrc(Img.copy());
// }
}
}
frm_eos = mpp_frame_get_eos(frame);
mpp_frame_deinit(&frame);
frame = nullptr;
get_frm = 1;
}
// try get runtime frame memory usage
if (data->frm_grp) {
size_t usage = mpp_buffer_group_usage(data->frm_grp);
if (usage > data->max_usage)
data->max_usage = usage;
}
// if last packet is send but last frame is not found continue
if (pkt_eos && pkt_done && !frm_eos) {
mmsleep(10);
continue;
}
if (frm_eos) {
qDebug("mpp_log :found last frame\n");
break;
}
if (data->frame_num > 0 && data->frame_count >= data->frame_num) {
data->eos = 1;
break;
}
if (get_frm)
continue;
break;
} while (1);
if (data->frame_num > 0 && data->frame_count >= data->frame_num) {
data->eos = 1;
qDebug("mpp_log_reach max frame number %d\n", data->frame_count);
break;
}
if (pkt_done)
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.
*/
mmsleep(3);
} while (1);
mpp_packet_deinit(&packet);
return ret;
}
int MppDecode::convertdata(char *srcdata, char *dst_buf)
{
// rga
im_rect src_rect;
im_rect dst_rect;
rga_buffer_t src;
rga_buffer_t dst;
IM_STATUS STATUS;
int ret = 0;
memset(&src_rect, 0, sizeof(src_rect));
memset(&dst_rect, 0, sizeof(dst_rect));
memset(&src, 0, sizeof(src));
memset(&dst, 0, sizeof(dst));
//memset(dst_buf,0x00,srcWidth*srcHight*get_bpp_from_format(DST_FORMAT));
src = wrapbuffer_virtualaddr(srcdata, reallyWidth, reallyHight, SRC_FORMAT);
dst = wrapbuffer_virtualaddr(dst_buf, srcWidth, srcHight, DST_FORMAT);
if(src.width == 0 || dst.width == 0) {
printf("%s, %s\n", __FUNCTION__, imStrError());
return -1;
}
src.format = SRC_FORMAT;
dst.format = DST_FORMAT;
ret = imcheck(src, dst, src_rect, dst_rect);
if (IM_STATUS_NOERROR != ret) {
printf("%d, check error! %s", __LINE__, imStrError((IM_STATUS)ret));
return -1;
}
STATUS = imcvtcolor(src, dst, src.format, dst.format);
//qDebug("resizing .... %s\n", imStrError(STATUS));
return 0;
}
int MppDecode::convertdata(char *srcdata, char *dst_buf,char *dstResize_buf)
{
im_rect src_rect;
im_rect dst_rect;
rga_buffer_t src;
rga_buffer_t dst;
rga_buffer_t dstCrop;
IM_STATUS STATUS;
int ret = 0;
memset(&src_rect, 0, sizeof(src_rect));
memset(&dst_rect, 0, sizeof(dst_rect));
memset(&src, 0, sizeof(src));
memset(&dst, 0, sizeof(dst));
memset(&dstCrop, 0, sizeof(dstCrop));
//memset(dst_buf,0x00,srcWidth*srcHight*get_bpp_from_format(DST_FORMAT));
src = wrapbuffer_virtualaddr(srcdata, reallyWidth, reallyHight, SRC_FORMAT);
//qDebug() <<""
dst = wrapbuffer_virtualaddr(dst_buf, srcWidth, srcHight, DST_FORMAT);
//dstCrop = wrapbuffer_virtualaddr(dstResize_buf, srcWidth, srcHight, DST_FORMAT);
if(src.width == 0 || dst.width == 0) {
printf("%s, %s\n", __FUNCTION__, imStrError());
return -1;
}
src.format = SRC_FORMAT;
dst.format = DST_FORMAT;
//dstCrop.format = DST_FORMAT;
src_rect.x = 0;
src_rect.y = 0;
src_rect.width = srcWidth-256;
src_rect.height = srcHight;
// ret = imcheck(src, dst, src_rect, dst_rect);
// if (IM_STATUS_NOERROR != ret) {
// printf("%d, check error! %s", __LINE__, imStrError((IM_STATUS)ret));
// return -1;
// }
STATUS = imcvtcolor(src, dst, src.format, dst.format);
//qDebug("resizing .... %s\n", imStrError(STATUS));
//STATUS = imcrop(dst,dstCrop,src_rect);
//qDebug("resizing .... %s\n", imStrError(STATUS));
return 0;
}
头文件如下
#ifndef MPPDECODE_H
#define MPPDECODE_H
#define MODULE_TAG "mpi_dec_test"
#include <string.h>
#include "utils.h"
#include "rk_mpi.h"
#include "mpp_log.h"
#include "mpp_mem.h"
#include "mpp_env.h"
#include "mpp_time.h"
#include "mpp_common.h"
#include "mpp_frame.h"
#include "mpp_buffer_impl.h"
#include "mpp_frame_impl.h"
#include <im2d.hpp>
#include <rga.h>
#include <RgaUtils.h>
#include <QPixmap>
#include <QImage>
#include <QDebug>
extern "C"
{
#include <libavformat/avformat.h>
}
#define SRC_FORMAT RK_FORMAT_YCbCr_420_SP
#define DST_FORMAT RK_FORMAT_RGB_888
//#define SRC_WIDTH 2592
//#define SRC_HEIGHT 1944
//#define DST_WIDTH 2592
//#define DST_HEIGHT 1944
#define MPI_DEC_STREAM_SIZE (SZ_4K)
#define MPI_DEC_LOOP_COUNT 4
#define MAX_FILE_NAME_LENGTH 256
class MppDecode : public QObject
{
Q_OBJECT
signals:
void MySigSendMppImg(QImage img);
void MySigSendMppImgSrc(QImage img);
public slots:
void slotGetSendMppSrcImg();
public:
void setWidthHight(int width,int hight);
typedef struct
{
MppCtx ctx;
MppApi *mpi;
RK_U32 eos;
char *buf;
RK_U32 quiet;
MppBufferGroup frm_grp;
MppBufferGroup pkt_grp;
MppPacket packet;
size_t packet_size;
MppFrame frame;
FILE *fp_input;
RK_S32 frame_count;
RK_S32 frame_num;
size_t max_usage;
} MpiDecLoopData;
typedef struct
{
char file_input[MAX_FILE_NAME_LENGTH];
char file_output[MAX_FILE_NAME_LENGTH];
MppCodingType type;
MppFrameFormat format;
RK_U32 width;
RK_U32 height;
RK_U32 debug;
RK_U32 have_input;
RK_U32 have_output;
RK_U32 simple;
RK_S32 timeout;
RK_S32 frame_num;
size_t max_usage;
} MpiDecTestCmd;
size_t mpp_buffer_group_usage(MppBufferGroup group);
int decode_simple(MpiDecLoopData *data, AVPacket* av_packet);
int convertdata(char *srcdata,char * dst_buf);
int convertdata(char *srcdata,char * dstsrc_buf,char *dst_buf);
char* dst_buf = nullptr;
//char* dstResize_buf = nullptr;
//char* dstCrop = nullptr;
int cout =0;
int srcWidth;
int srcHight;
int initSrcHight;
int initSrcWidth;
bool srcImgSend;
int reallyWidth;
int reallyHight;
};
#endif // MPPDECODE_H
关于h265的在mpp解码的对齐问题,作者还有许多不明白之处,欢迎评论交流