概述
瑞芯微提供的媒体处理软件平台(Media Process Platform,简称 MPP)是适用于瑞芯微芯片系列的
通用媒体处理软件平台。该平台对应用软件屏蔽了芯片相关的复杂底层处理,其目的是为了屏蔽不
同芯片的差异,为使用者提供统一的视频媒体处理接口(Media Process Interface,缩写 MPI)。MPP
提供的功能包括:
视频解码:
H.265 / H.264 / H.263 / VP9 / VP8 / MPEG-4 / MPEG-2 / MPEG-1 / VC1 / MJPEG
视频编码:
H.264 / VP8 / MJPEG
视频处理:
视频拷贝,缩放,色彩空间转换,场视频解交织(Deinterlace)
MPP源码下载
git clone https://github.com/rockchip-linux/mpp.git
编码demo测试
mpi_enc_test -w 720 -h 480 -t 7 -i /sdcard/soccer_720x480_30fps.yuv -o /sdcard/out.h264 -n 1000
mpi_enc_test 的命令参数中,图像宽度(w)图像高度(h),码流类型(t)为强制要求参数,其他参
数如输入文件(i),输出文件(o),编码帧数(n)等为可选参数。
执行完测试程序在/sdcard目录下会生成out.h264文件。
将out.h264在VLC media player播放器播放:
MPI接口使用流程
创建 MPP context 和 MPP api 接口
ret = mpp_create(&p->ctx, &p->mpi);
初始化 MPP
ret = mpp_init(p->ctx, MPP_CTX_ENC, p->type); // 初始化MPP
设置一些MPP的模式
ret = mpi->control(ctx, MPP_ENC_SET_SEI_CFG, &p->sei_mode);
编码就是喂MppFrame,输出MppPacket;
输入frame
ret = mpi->encode_put_frame(ctx, frame);
输出packet
ret = mpi->encode_get_packet(ctx, &packet);
RK官方编码demo mpi_enc_test.c简化
#if defined(_WIN32)
#include "vld.h"
#endif
#define MODULE_TAG "mpi_enc_test"
#include <string.h>
#include "rk_mpi.h"
#include "mpp_mem.h"
#include "mpp_common.h"
#include "utils.h"
#include "mpi_enc_utils.h"
#include <stdio.h>
typedef struct {
// base flow context
MppCtx ctx;
MppApi *mpi;
// global flow control flag
RK_U32 frm_eos;
RK_U32 pkt_eos;
RK_S32 frame_count;
// src and dst
FILE *fp_output;
/* encoder config set */
MppEncCfg cfg;
// input / output
MppBufferGroup buf_grp;
MppBuffer frm_buf;
MppBuffer pkt_buf;
MppBuffer md_info;
MppEncSeiMode sei_mode;
MppEncHeaderMode header_mode;
// paramter for resource malloc
RK_U32 width;
RK_U32 height;
RK_U32 hor_stride;
RK_U32 ver_stride;
MppFrameFormat fmt;
MppCodingType type;
// resources
size_t header_size;
size_t frame_size;
size_t mdinfo_size;
} MpiEncTestData;
/* For each instance thread return value */
typedef struct {
RK_S32 frame_count;
} MpiEncMultiCtxRet;
typedef struct {
MpiEncTestArgs *cmd; // pointer to global command line info
const char *name;
pthread_t thd; // thread for for each instance
MpiEncTestData ctx; // context of encoder
MpiEncMultiCtxRet ret; // return of encoder
} MpiEncMultiCtxInfo;
MPP_RET test_ctx_init(MpiEncMultiCtxInfo *info)
{
MpiEncTestArgs *cmd = info->cmd;
MpiEncTestData *p = &info->ctx;
MPP_RET ret = MPP_OK;
// 设置编码宽高、对齐后宽高参数
p->width = cmd->width;
p->height = cmd->height;
p->hor_stride = (cmd->hor_stride) ? (cmd->hor_stride) :
(MPP_ALIGN(cmd->width, 16));
p->ver_stride = (cmd->ver_stride) ? (cmd->ver_stride) :
(MPP_ALIGN(cmd->height, 16));
p->fmt = cmd->format;
p->type = cmd->type;
p->mdinfo_size = (MPP_VIDEO_CodingHEVC == cmd->type) ?
(MPP_ALIGN(p->hor_stride, 64) >> 6) *
(MPP_ALIGN(p->ver_stride, 64) >> 6) * 32 :
(MPP_ALIGN(p->hor_stride, 64) >> 6) *
(MPP_ALIGN(p->ver_stride, 16) >> 4) * 8;
p->frame_size = MPP_ALIGN(p->hor_stride, 64) * MPP_ALIGN(p->ver_stride, 64) * 4;
return ret;
}
MPP_RET test_ctx_deinit(MpiEncTestData *p)
{
if (p) {
if (p->fp_output) {
fclose(p->fp_output);
p->fp_output = NULL;
}
}
return MPP_OK;
}
MPP_RET test_mpp_enc_cfg_setup(MpiEncMultiCtxInfo *info)
{
MpiEncTestData *p = &info->ctx;
MppApi *mpi = p->mpi;
MppCtx ctx = p->ctx;
MppEncCfg cfg = p->cfg;
MPP_RET ret;
mpp_enc_cfg_set_s32(cfg, "prep:width", p->width);
mpp_enc_cfg_set_s32(cfg, "prep:height", p->height);
mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", p->hor_stride);
mpp_enc_cfg_set_s32(cfg, "prep:ver_stride", p->ver_stride);
mpp_enc_cfg_set_s32(cfg, "prep:format", p->fmt);
ret = mpi->control(ctx, MPP_ENC_SET_CFG, cfg); //创建 MPP
p->sei_mode = MPP_ENC_SEI_MODE_ONE_FRAME;
ret = mpi->control(ctx, MPP_ENC_SET_SEI_CFG, &p->sei_mode); //设置一些MPP的模式
if (p->type == MPP_VIDEO_CodingAVC || p->type == MPP_VIDEO_CodingHEVC) {
p->header_mode = MPP_ENC_HEADER_MODE_EACH_IDR;
ret = mpi->control(ctx, MPP_ENC_SET_HEADER_MODE, &p->header_mode);
}
return ret;
}
MPP_RET test_mpp_run(MpiEncMultiCtxInfo *info) //图像编码函数
{
MpiEncTestData *p = &info->ctx;
MppApi *mpi = p->mpi;
MppCtx ctx = p->ctx;
MPP_RET ret = MPP_OK;
MppMeta meta = NULL;
MppFrame frame = NULL;
MppPacket packet = NULL; // 存放编码数据
void *buf = mpp_buffer_get_ptr(p->frm_buf);
ret = fill_image(buf, p->width, p->height, p->hor_stride,
p->ver_stride, p->fmt, p->frame_count);
ret = mpp_frame_init(&frame);
mpp_frame_set_width(frame, p->width);
mpp_frame_set_height(frame, p->height);
mpp_frame_set_hor_stride(frame, p->hor_stride);
mpp_frame_set_ver_stride(frame, p->ver_stride);
mpp_frame_set_fmt(frame, p->fmt);
mpp_frame_set_eos(frame, p->frm_eos);
mpp_frame_set_buffer(frame, p->frm_buf);
meta = mpp_frame_get_meta(frame);
mpp_packet_init_with_buffer(&packet, p->pkt_buf);
mpp_packet_set_length(packet, 0);
mpp_meta_set_packet(meta, KEY_OUTPUT_PACKET, packet);
mpp_meta_set_buffer(meta, KEY_MOTION_INFO, p->md_info);
ret = mpi->encode_put_frame(ctx, frame); //输入frame
if (ret) {
mpp_frame_deinit(&frame);
}
mpp_frame_deinit(&frame);
ret = mpi->encode_get_packet(ctx, &packet); //输出packet
mpp_assert(packet);
void *ptr = mpp_packet_get_pos(packet);
size_t len = mpp_packet_get_length(packet);
p->pkt_eos = mpp_packet_get_eos(packet);
fwrite(ptr, 1, len, p->fp_output);
mpp_packet_deinit(&packet);
return ret;
}
void *enc_test(void *arg) //编码器初始化函数
{
MpiEncMultiCtxInfo *info = (MpiEncMultiCtxInfo *)arg;
MpiEncTestData *p = &info->ctx;
MppPollType timeout = MPP_POLL_BLOCK;
MPP_RET ret = MPP_OK;
ret = test_ctx_init(info);
ret = mpp_buffer_group_get_internal(&p->buf_grp, MPP_BUFFER_TYPE_DRM);
ret = mpp_buffer_get(p->buf_grp, &p->frm_buf, p->frame_size + p->header_size);
ret = mpp_buffer_get(p->buf_grp, &p->pkt_buf, p->frame_size);
ret = mpp_buffer_get(p->buf_grp, &p->md_info, p->mdinfo_size);
ret = mpp_create(&p->ctx, &p->mpi); //创建 MPP context 和 MPP api 接口
ret = p->mpi->control(p->ctx, MPP_SET_OUTPUT_TIMEOUT, &timeout);
ret = mpp_init(p->ctx, MPP_CTX_ENC, p->type); // 初始化MPP
ret = mpp_enc_cfg_init(&p->cfg);
ret = test_mpp_enc_cfg_setup(info);
ret = test_mpp_run(info);
ret = p->mpi->reset(p->ctx);
test_ctx_deinit(p);
return NULL;
}
int enc_test_multi(MpiEncTestArgs* cmd, const char *name)
{
MpiEncMultiCtxInfo *ctxs = NULL;
RK_S32 ret = MPP_NOK;
RK_S32 i = 0;
ctxs = mpp_calloc(MpiEncMultiCtxInfo, cmd->nthreads);
ctxs[i].cmd = cmd;
ctxs[i].name = name;
ret = pthread_create(&ctxs[i].thd, NULL, enc_test, &ctxs[i]);
pthread_join(ctxs[i].thd, NULL);
MPP_FREE(ctxs);
return ret;
}
int main(int argc,char **argv)
{
argc = 13;
char* argvv[] = {"mpi_enc_test","-w","720","-h","480","-t","7","-i","/sdcard/soccer_720x480_30fps.yuv","-o","/sdcard/out.h264","-n","10"};
RK_S32 ret = MPP_NOK;
MpiEncTestArgs* cmd = mpi_enc_test_cmd_get();
// parse the cmd option
ret = mpi_enc_test_cmd_update_by_args(cmd, argc, argvv);
mpi_enc_test_cmd_show_opt(cmd);
ret = enc_test_multi(cmd, argvv[0]);
return ret;
}