一、下载RK-MPP硬件编解码库
下载链接:https://github.com/rockchip-linux/mpp
二、RK-MPP库介绍
MPP(Media Process Platform )是rk通过用户空间的复杂底层操作,提供了硬件编解码库MPP提供了一组MPI接口,用户通过MPI接口实现媒体处理
MPP提供的功能包括:
? 视频解码
? H.265 / H.264 / H.263 / VP9 / VP8 / MPEG-4 / MPEG-2 / MPEG-1 / VC1 / MJPEG
? 视频编码
? H.264 / VP8 / MJPEG
? 视频处理
? 视频复制、缩放、色彩空间转换、视频解交织(Deinterlace)

MppMem 为 C 库 malloc 内存包装。
MppBuffer 为硬件用的 dmabuf 内存包装。
MppPacket 从一维缓存包装开始 MppMem 和 MppBuffer 代表码流数据的生成。
MppFrame 从二维帧数据包装开始 MppMem 和 MppBuffer 生成,表示图像数据。
使用 MppPacket 和 MppFrame 一般视频编解码工作可以简单有效地完成。
以视频解码为例,码流输入端赋予地址和大小 MppPacket,通过 put_packet 在输出端通过接口输入 get_frame 接口得到输入图像 MppFrame,可以完成最简单的视频解码过程。
三、RK-MPP介绍和使用库工具
MPP 单元测试提供了一些工具程序,可用于软硬件平台和 MPP 测试库本身
mpp_info_test
用于读取和打印 MPP 在反馈问题时,可以附上打印出来的信息。
mpp_buffer_test
内存分配器用于测试内核是否正常。
mpp_mem_test
用于测试 C 库的内存分配器是否正常。
mpp_runtime_test
测试一些软硬件运行时的环境是否正常。
mpp_platform_test
用于读取和测试芯片平台信息是否正常
unzip mpp-develop.zip && cd mpp-develop
cd build/linux/aarch64(根据平台选择) && vim arm.linux.cross.cmake(查看是否是相应平台的交叉编译工具)
4.工具和动态库push到rk平台(一般rk所有的平台都自带MPP以解码为例执行动态库)./mpi_dec_test -t 7 -i /sdcard/tennis200.h264 -n 10
-t 7 表示是 H.264 码流, -i 表示输入文件, -n 10 表示解码 10 帧,如果一切正常,将得到以下结果:
四、仿照mpi_dec_test.c 写下最简单的解码demo
#include <string.h> #include "rk_mpi.h" #include "mpp_mem.h" #include "mpp_env.h" #include "mpp_time.h" #include "mpp_common.h" #include "mpi_dec_utils.h" #include "utils.h" typedef struct { MppCtx ctx; MppApi *mpi; RK_U32 eos; char *buf; MppBufferGroup frm_grp; MppPacket packet; size_t packet_size; MppFrame frame; FILE *fp_input; FILE *fp_output; RK_S32 frame_count; RK_S32 frame_num; size_t max_usage; } MpiDecLoopData; static it decode_simple(MpiDecLoopData *data)
{
RK_U32 pkt_done = 0;
RK_U32 err_info = 0;
MPP_RET ret = MPP_OK;
MppCtx ctx = data->ctx;
MppApi *mpi = data->mpi;
char *buf = data->buf;
MppPacket packet = data->packet;
MppFrame frame = NULL;
size_t read_size = fread(buf, 1, data->packet_size, data->fp_input);
if (read_size != data->packet_size || feof(data->fp_input)) {
printf("found last packet\n");
data->eos = 1;
}
mpp_packet_write(packet, 0, buf, read_size);
mpp_packet_set_pos(packet, buf);
mpp_packet_set_length(packet, read_size);
if (data->eos){
mpp_packet_set_eos(packet);
}
do {
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;
ret = mpi->decode_get_frame(ctx, &frame);
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);
printf("decode_get_frame get info changed found\n");
printf("decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d", width, height, hor_stride, ver_stride, buf_size);
if (NULL == data->frm_grp) {
ret = mpp_buffer_group_get_internal(&data->frm_grp, MPP_BUFFER_TYPE_ION);
if (ret) {
printf("get mpp buffer group failed ret %d\n", ret);
break;
}
ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp);
if (ret) {
printf("set buffer group failed ret %d\n", ret);
break;
}
} else {
ret = mpp_buffer_group_clear(data->frm_grp);
if (ret){
printf("clear buffer group failed ret %d\n", ret);
break;
}
}
ret = mpp_buffer_group_limit_config(data->frm_grp, buf_size, 24);
if (ret) {
printf("limit buffer group failed ret %d\n", ret);
break;
}
ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
if (ret) {
printf("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) {
printf("decoder_get_frame get err info:%d discard:%d.\n", mpp_frame_get_errinfo(frame), mpp_frame_get_discard(frame));
}
data->frame_count++;
printf("decode_get_frame get frame %d\n", data->frame_count);
if ( (!err_info) && (data->frame_count==data->frame_num)){
dump_mpp_frame_to_file(frame, data->fp_output);
}
}
frm_eos = mpp_frame_get_eos(frame);
mpp_frame_deinit(&frame);
frame = NULL;
get_frm = 1;
}
if (data->frm_grp) {
size_t usage = mpp_buffer_group_usage(data->frm_grp);
if (usage > data->max_usage){
data->max_usage = usage;
}
}
if (data->eos && pkt_done && !frm_eos) {
msleep(10);
continue;
}
if (frm_eos) {
printf("found last frame\n");
break;
}
if (data->frame_num && data->frame_count >= data->frame_num) {
data->eos = 1;
break;
}
if (get_frm){
continue;
}
break;
} while (1);
if (data->frame_num && data->frame_count >= data->frame_num){
data->eos = 1;
printf("reach max frame number %d\n", data->frame_count);
break;
}
if (pkt_done){
break;
}
} while (1);
return ret;
}
int mpi_dec_test_decode(char **argv)
{
MPP_RET ret = MPP_OK;
size_t file_size = 0;
MppParam param = NULL;
RK_U32 need_split = 1;
MpiDecLoopData data;
memset(&data, 0, sizeof(data));
data.eos = 0;
data.packet_size = MPI_DEC_STREAM_SIZE;
data.frame_count = 0;
data.frame_num = 1;
data.fp_input = fopen(argv[1], "rb");
data.fp_output = fopen(argv[2], "w+");
if ( (NULL == data.fp_input) || (NULL == data.fp_output) ) {
printf("failed to open input/output file \n");
goto MPP_TEST_OUT;
}
data.buf = mpp_malloc(char, data.packet_size);
ret = mpp_packet_init(&data.packet, data.buf, data.packet_size);
if(MPP_OK != ret){
printf("mpp_packet_init error\n");
goto MPP_TEST_OUT;
}
ret = mpp_create(&data.ctx, &data.mpi);
if(MPP_OK != ret){
printf("mpp_create error\n");
goto MPP_TEST_OUT;
}
ret = mpp_init(data.ctx, MPP_CTX_DEC, MPP_VIDEO_CodingAVC);
if (MPP_OK != ret)
{
printf("mpp_init failed\n");
goto MPP_TEST_OUT;
}
param = &need_split;
ret = data.mpi->control(data.ctx, MPP_DEC_SET_PARSER_SPLIT_MODE, param);
if (MPP_OK != ret) {
printf("mpi->control failed\n");
goto MPP_TEST_OUT;
}
fseek(data.fp_input, 0L, SEEK_END);
file_size = ftell(data.fp_input);
rewind(data.fp_input);
printf("input file size %ld\n", file_size);
while (!data.eos)
{
decode_simple(&data);
}
ret = data.mpi->reset(data.ctx);
if (MPP_OK != ret)
{
printf("mpi->reset failed\n");
goto MPP_TEST_OUT;
}
MPP_TEST_OUT:
if (data.packet) {
mpp_packet_deinit(&data.packet);
data.packet = NULL;
}
if (data.ctx) {
mpp_destroy(data.ctx);
data.ctx = NULL;
}
if (data.buf) {
mpp_free(data.buf);
data.buf = NULL;
}
if (data.frm_grp) {
mpp_buffer_group_put(data.frm_grp);
data.frm_grp = NULL;
}
if (data.fp_output){
fclose(data.fp_output);
data.fp_output = NULL;
}
if (data.fp_input) {
fclose(data.fp_input);
data.fp_input = NULL;
}
return ret;
}
int main(int argc, char **argv)
{
RK_S32 ret = 0;
if(argc != 3 ){
printf("please input options\n");
return -1;
}
ret = mpi_dec_test_decode(argv);
return ret;
}