The RK3588S is equipped with powerful codecs that support up to 7680x4320@30fps decoding and 7680x4320@30fps encoding, and the RK platforms uniformly use the MPP library as the development tool for their codecs. Therefore, it is possible to realize one time development and mutual porting between multiple platforms.
Since there are open source sdk, it is recommended to build the SDK on PC, so as to ensure the same build environment, the cross-compile environment inside the SDK is the same as the environment on the board.
There are two ways to get the MPP library source code.
If you want to keep the same dynamic libraries on board, you need to pull the whole SDK. mpp source code is under external/mpp in the root directory of SDK, it is recommended to copy this source code to a separate working directory for use.
If you don't want to download the whole SDK, you can download the mpp package from the link below, which is extracted from the full version of the sdk.
If you want to experience the latest version of mpp, you can pull it directly from rk's git, create a new working directory, and then run
git clone https://github.com/rockchip-linux/mpp.git
First, configure the cross-compilation environment. In the SDK root directory , execute the following lines
DIR=$(pwd)
export PATH=$PATH:${DIR}/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin
export CROSS_COMPILE=aarch64-none-linux-gnu-
export ARCH=aarch64
In the working directory of mpp, open the build/linux/aarch64 directory.
Then modify the compiler in the arm.linux.cross.cmake file as follows
SET(CMAKE_C_COMPILER "aarch64-none-linux-gnu-gcc")
SET(CMAKE_CXX_COMPILER "aarch64-none-linux-gnu-g++")
Then in the build/linux/aarch64 directory run
./make-Makefiles.bash
make -j8
You can compile it, and the finished message is as follows
After compiling, you can see the following files in this directory
Then you have to verify that the compiled mpp environment runs on the board.
The compiled program is available in the mpp working directory under build/linux/aarch64/test
. This mpp_info_test can be used to verify that the current mpp environment on the board is working. Place this file on the board and run
./mpp_info_test
To view the output: This program changes the print interface to system log
, you need to enter the following command to view the mpp output
tail -10f /var/log/messages
If you can see normal output, the environment in which mpp is running is fine
MPP project comes with cmake, as long as the configuration of cmake can compile its own demo, but in practice, many times to integrate the mpp function into their own project, this time you need to have the function of linking mpp library. Below by introducing how to compile a separate mpp demo, to illustrate how to link the mpp library.
First of all, copy the mpp demo source code, for example, copy it to the mytest directory of the mpp project (this directory needs to be created by yourself, or you can change it to another directory
). The most commonly used functions here are the codecs, and their demo source codes are
test/mpi_dec_test.c
test/mpi_enc_test.c
Then cd to the project directory of mpp, respectively execute the
aarch64-none-linux-gnu-gcc mytest/mpi_enc_test.c build/linux/aarch64/utils/libutils.a build/linux/aarch64/osal/libosal.a -Lbuild/linux/aarch64/mpp -lrockchip_mpp -I./osal/inc -I./osal/linux -I./inc -I./utils -o mytest/mpi_enc_test -lpthread -lstdc++
aarch64-none-linux-gnu-gcc mytest/mpi_dec_test.c build/linux/aarch64/utils/libutils.a build/linux/aarch64/osal/libosal.a -Lbuild/linux/aarch64/mpp -lrockchip_mpp -I./osal/inc -I./osal/linux -I./inc -I./utils -o mytest/mpi_dec_test -lpthread -lstdc++
You can compile mpi_enc_test and mpi_dec_test, that is, encoding and decoding demos.
libutils are some auxiliary functions, such as crc calculation, etc., which will be used in the demo, and can not be referenced by the user's own program.
libosal is some operating system api, such as memory allocation, etc., the same user's own program can not be used to use can not be referenced
The following demo uses mpi_enc_test, which is used for encoding. The so-called encoding, is the original RAW image data, such as YUV422 YUV420 NV12 NV16 data format, compression, compression usually H264 H265, etc., after compression, the volume is reduced, easy to store, transmission.
First of all, we need to capture a section of the original camera video, the method of capturing the original video can refer to the previous section.
Here 10 frames are grabbed at 1632x1224 resolution and saved to /tmp/isp.out. After grabbing, use the command ls -ll to see its size. You can see that images in this data format take up a lot of space.
Then encode it using the following command
./mpi_enc_test -w 1632 -h 1224 -t 7 -i /tmp/isp.out -o /tmp/isp.h264 -n 10 -f 0
Where -w is the width -h is the height -t specifies the output format, 7 for H264, -i -o are the input and output file names, -n is the number of frames, -f specifies the input format, 0 for YUV420SP, NV12. The specific parameters of this encoding command have to be matched with the format of the original image, or else it will report an error.
After encoding, the output file is /tmp/isp.h264, and you can see that its space consumption has decreased dramatically.
The relevant output from mpp can be seen in the syslog message
tail -20f /var/log/messages
! 46.jpg
Copy the /tmp/isp.h264 and /tmp/isp.out files to the virtual machine ubuntu on the PC and use the command
W=1632; H=1224; mplayer isp.out -loop 0 -demuxer rawvideo -fps 30 -rawvideo w=${W}:h=${H}:size=$((${W}*${H}*3/2)):format=NV12
Can play isp.out
mplayer isp.h264 -loop 0
can play isp.h264
As you can see, although the footprint is drastically reduced, its picture quality is about the same. And that's the point of using a board-side encoder.
Decoding, on the other hand, reduces the h264-compressed image to RAW format with the command
./mpi_dec_test -w 1632 -h 1224 -t 7 -i /tmp/isp.h264 -o /tmp/isp.h264.out -n 10 -f 0
Theoretically, the content after decoding should be the same size as before encoding. Because of the compression, some details are lost and the content is not exactly the same, but the difference in the content displayed during playback is not significant
The following is an example of the mpi_enc_test source code in the demo to introduce the use of the mpp dynamic library.
This source file is located in the test directory of the mpp project
First look at the main function, it first uses mpi_enc_test_cmd_update_by_args to parse out all the parameters, and then executes the encoding through the enc_test_multi function
int main(int argc, char **argv)
{
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, argv);
if (ret)
goto DONE;
mpi_enc_test_cmd_show_opt(cmd);
ret = enc_test_multi(cmd, argv[0]);
DONE:
mpi_enc_test_cmd_put(cmd);
return ret;
}
The mpi_enc_test_cmd_update_by_args function is to parse the arguments one by one and check the arguments, and then fill in the incomplete ones.
where MPP_RET mpp_opt_parse(MppOpt opt, int argc, char **argv); is to parse out the arguments when executing the mpi_enc_test command and put them inside MppOpt opt.
MPP_RET mpi_enc_test_cmd_update_by_args(MpiEncTestArgs* cmd, int argc, char **argv)
{
MppOpt opts = NULL;
RK_S32 ret = -1;
RK_U32 i;
...
/* should change node count when option increases */
mpp_opt_setup(opts, cmd, 67, enc_opt_cnt);
for (i = 0; i < enc_opt_cnt; i++)
mpp_opt_add(opts, &enc_opts[i]);
/* mark option end */
mpp_opt_add(opts, NULL);
ret = mpp_opt_parse(opts, argc, argv);
...
if (!cmd->hor_stride)
cmd->hor_stride = mpi_enc_width_default_stride(cmd->width, cmd->format);
if (!cmd->ver_stride)
cmd->ver_stride = cmd->height;
...
if (cmd->rc_mode == MPP_ENC_RC_MODE_FIXQP) {
if (!cmd->qp_init) {
if (cmd->type == MPP_VIDEO_CodingAVC ||
cmd->type == MPP_VIDEO_CodingHEVC)
cmd->qp_init = 26;
}
}
if (cmd->trace_fps) {
fps_calc_init(&cmd->fps);
mpp_assert(cmd->fps);
fps_calc_set_cb(cmd->fps, show_enc_fps);
}
...
return ret;
}
The main function calls
int enc_test_multi(MiEncTestArgs* cmd, const char *name).
This function creates a thread and executes
void *enc_test(void *arg).
function, this function is to loop through the encoding operations
void *enc_test(void *arg)
{
...
mpp_log_q(quiet, "%s start\n", info->name);
...
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);
...
// encoder demo
ret = mpp_create(&p->ctx, &p->mpi);
...
mpp_log_q(quiet, "%p encoder test start w %d h %d type %d\n",
p->ctx, p->width, p->height, p->type);
ret = p->mpi->control(p->ctx, MPP_SET_OUTPUT_TIMEOUT, &timeout);
...
ret = mpp_init(p->ctx, MPP_CTX_ENC, p->type);
...
ret = mpp_enc_cfg_init(&p->cfg);
...
ret = test_mpp_enc_cfg_setup(info);
...
t_s = mpp_time();
ret = test_mpp_run(info);
t_e = mpp_time();
ret = p->mpi->reset(p->ctx);
...
return NULL;
}
This function first initializes a buffer, then puts the info, data, etc. of the input file into this buffer, and then calls
mpp_create
to instantiate a MppCtx
and then use
mpp_init
initialize it, and then use
mpp_enc_cfg_init
to set it up, and finally set it up in the
test_mpp_run
call
mpi->encode_put_frame(ctx, frame).
mpi->encode_get_packet(ctx, &packet).
Send the raw data of a frame to mpp, and get the encoded data of a packet from mpp
Loop through multiple packets to get the final encoded file
The specific MPP API can be found in the MPP documentation at docs/Linux/Multimedia/Rockchip_Developer_Guide_MPP_CN.pdf