• RKMPP库快速上手--(一)RKMPP功能及使用详解


    1、MPP简介

            MPP(Media Process Platform )是Rockchip提供的一款硬件编解码媒体处理软件平台,适用于Rockchip芯片系列。它屏蔽了有关芯片的复杂底层处理,屏蔽了不同芯片的差异,为使用者提供了一组MPI统一接口。如果想达到最好的效果,必须要通过librockchip_mpp来直接编码实现编解码。

            我们可以通过gstreamer和ffmpeg的mpp插件来使用mpp硬件加速,但是这两种应用程序都会因为兼容api的原因,徒增几次无用的帧拷贝动作,并且使用的都是虚拟地址。我们知道纯物理连续地址的硬件操作是非常快的,转到虚拟地址后效率就会降低。如果想榨干芯片的性能,开发最完美的代码,纯连续的物理buffer和mpp+rga是离不开的。

            Mpp的API思路其实跟目前绝大多数的编解码库是一致的,都是queue/dequeue的队列操作方式,先设置好编解码状态,然后不停的queue/dequeue input/output buffer就可以实现编解码控制了。如果大家熟悉FFmpeg,那学习MPP会非常容易,MPP和FFmpeg的api非常相像。

            Mpp库自带了编解码的sample,但是相关文档和注释较少,本文在原有sample的基础上添加了注释,并将部分功能封装成型。

    2、MPP提供的功能

    MPP提供有以下常用功能:

    • 视频解码
    • H.265 / H.264 / H.263 / VP9 / VP8 / MPEG-4 / MPEG-2 / MPEG-1 / VC1 / MJPEG
    • 视频编码
    • H.264 / VP8 / MJPEG
    • 视频处理
    • 视频拷贝,缩放,色彩空间转换,场视频解交织(Deinterlace)

    3、MPP系统架构

    4、MPP库的MPI接口介绍

    5、MPI数据结构说明

    MppMem: 为 C 库 malloc 内存的封装。

    MppBuffer: 为硬件用的 dmabuf 内存的封装。

    MppPacket: 为一维缓存封装,可以从 MppMem 和 MppBuffer 生成,表示码流数据。

    MppFrame: 为二维帧数据封装,可以从 MppMem 和 MppBuffer 生成,表示图像数据。

    MppMeta、MppTask:输入输出用任务的高级组合接口,可以指定输入输出方式;

    使用 MppPacket 和 MppFrame 就可以简单有效的完成一般的视频编解码工作。

    以视频解码为例,码流输入端把地址和大小赋值给 MppPacket,通过 put_packet 接口输入,在输出端通过 get_frame 接口得到输入图像 MppFrame,即可完成最简单的视频解码过程。

    6、解码流程示例

    7、RK-MPP库工具介绍与使用

            MPP 提供了一些单元测试用的工具程序,这种程序可以对软硬件平台以及 MPP 库本身进行测试

    mpp_info_test

    用于读取和打印 MPP 库的版本信息,在反馈问题时,可以把打印出来信息附上。

    mpp_buffer_test

    用于测试内核的内存分配器是否正常。

    mpp_mem_test

    用于测试 C 库的内存分配器是否正常。

    mpp_runtime_test

    用于测试一些软硬件运行时环境是否正常。

    mpp_platform_test

    用于读取和测试芯片平台信息是否正常

    8、交叉编译MPP库

    unzip mpp-develop.zip && cd mpp-develop

    cd build/linux/aarch64(根据平台选择) && vim arm.linux.cross.cmake(看下是否是对应平台的交叉编译工具)

    ./arm.linux.cross.cmake && make,编译之后,动态库在mpp目录下,测试工具在test目录下

    将工具和动态库push到rk的平台上(一般rk的平台都已经自带MPP动态库了),以解码为例执行./mpi_dec_test -t 7 -i /sdcard/input.h264 -n 10

    9、mpp测试程序说明及代码示例

    mpi_enc_test:使用同步界面(轮询,出队和入队),对raw data进行编码以压缩视频。

    mpi_dec_test:使用同步接口和异步接口(decode_put_packet和decode_get_frame),将视频压缩解码为yuv格式的raw data。

    mpi_rc_test:编码使用详细的比特率控制配置。

    mpi_rc2_test:使用详细的比特率控制配置进行编码,而cfg参数则来自mpi_rc.cfg。

    mpi_test:mpi调用方法的简单描述,仅供参考

    mpp_event_trigger:事件触发测试。

    mpp_parse_cfg:mpp解析器cfg测试。

    vpu_api_test:编码或解码使用旧版接口,以便与以前的vpu接口兼容

    (1)、参考mpi_dec_test.c 写一个最简单的解码demo

    1. #include
    2. #include "rk_mpi.h"
    3. #include "mpp_mem.h"
    4. #include "mpp_env.h"
    5. #include "mpp_time.h"
    6. #include "mpp_common.h"
    7. #include "mpi_dec_utils.h"
    8. #include "utils.h"
    9. typedef struct
    10. {
    11. MppCtx ctx;
    12. MppApi *mpi;
    13. RK_U32 eos;
    14. char *buf;
    15. MppBufferGroup frm_grp;
    16. MppPacket packet;
    17. size_t packet_size;
    18. MppFrame frame;
    19. FILE *fp_input;
    20. FILE *fp_output;
    21. RK_S32 frame_count;
    22. RK_S32 frame_num;
    23. size_t max_usage;
    24. } MpiDecLoopData;
    25. static int decode_simple(MpiDecLoopData *data)
    26. {
    27. RK_U32 pkt_done = 0;
    28. RK_U32 err_info = 0;
    29. MPP_RET ret = MPP_OK;
    30. MppCtx ctx = data->ctx;
    31. MppApi *mpi = data->mpi;
    32. char *buf = data->buf;
    33. MppPacket packet = data->packet;
    34. MppFrame frame = NULL;
    35. size_t read_size = fread(buf, 1, data->packet_size, data->fp_input);
    36. if (read_size != data->packet_size || feof(data->fp_input)) {
    37. printf("found last packet\n");
    38. data->eos = 1;
    39. }
    40. mpp_packet_write(packet, 0, buf, read_size);
    41. mpp_packet_set_pos(packet, buf);
    42. mpp_packet_set_length(packet, read_size);
    43. if (data->eos){
    44. mpp_packet_set_eos(packet);
    45. }
    46. do {
    47. if (!pkt_done) {
    48. ret = mpi->decode_put_packet(ctx, packet);
    49. if (MPP_OK == ret){
    50. pkt_done = 1;
    51. }
    52. }
    53. do {
    54. RK_S32 get_frm = 0;
    55. RK_U32 frm_eos = 0;
    56. ret = mpi->decode_get_frame(ctx, &frame);
    57. if (frame) {
    58. if (mpp_frame_get_info_change(frame)){
    59. RK_U32 width = mpp_frame_get_width(frame);
    60. RK_U32 height = mpp_frame_get_height(frame);
    61. RK_U32 hor_stride = mpp_frame_get_hor_stride(frame);
    62. RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
    63. RK_U32 buf_size = mpp_frame_get_buf_size(frame);
    64. printf("decode_get_frame get info changed found\n");
    65. printf("decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d", width, height, hor_stride, ver_stride, buf_size);
    66. if (NULL == data->frm_grp) {
    67. ret = mpp_buffer_group_get_internal(&data->frm_grp, MPP_BUFFER_TYPE_ION);
    68. if (ret) {
    69. printf("get mpp buffer group failed ret %d\n", ret);
    70. break;
    71. }
    72. ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, data->frm_grp);
    73. if (ret) {
    74. printf("set buffer group failed ret %d\n", ret);
    75. break;
    76. }
    77. } else {
    78. ret = mpp_buffer_group_clear(data->frm_grp);
    79. if (ret){
    80. printf("clear buffer group failed ret %d\n", ret);
    81. break;
    82. }
    83. }
    84. ret = mpp_buffer_group_limit_config(data->frm_grp, buf_size, 24);
    85. if (ret) {
    86. printf("limit buffer group failed ret %d\n", ret);
    87. break;
    88. }
    89. ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
    90. if (ret) {
    91. printf("info change ready failed ret %d\n", ret);
    92. break;
    93. }
    94. }else{
    95. err_info = mpp_frame_get_errinfo(frame) | mpp_frame_get_discard(frame);
    96. if (err_info) {
    97. printf("decoder_get_frame get err info:%d discard:%d.\n", mpp_frame_get_errinfo(frame), mpp_frame_get_discard(frame));
    98. }
    99. data->frame_count++;
    100. printf("decode_get_frame get frame %d\n", data->frame_count);
    101. if ( (!err_info) && (data->frame_count==data->frame_num)){
    102. dump_mpp_frame_to_file(frame, data->fp_output);
    103. }
    104. }
    105. frm_eos = mpp_frame_get_eos(frame);
    106. mpp_frame_deinit(&frame);
    107. frame = NULL;
    108. get_frm = 1;
    109. }
    110. if (data->frm_grp) {
    111. size_t usage = mpp_buffer_group_usage(data->frm_grp);
    112. if (usage > data->max_usage){
    113. data->max_usage = usage;
    114. }
    115. }
    116. if (data->eos && pkt_done && !frm_eos) {
    117. msleep(10);
    118. continue;
    119. }
    120. if (frm_eos) {
    121. printf("found last frame\n");
    122. break;
    123. }
    124. if (data->frame_num && data->frame_count >= data->frame_num) {
    125. data->eos = 1;
    126. break;
    127. }
    128. if (get_frm){
    129. continue;
    130. }
    131. break;
    132. } while (1);
    133. if (data->frame_num && data->frame_count >= data->frame_num){
    134. data->eos = 1;
    135. printf("reach max frame number %d\n", data->frame_count);
    136. break;
    137. }
    138. if (pkt_done){
    139. break;
    140. }
    141. } while (1);
    142. return ret;
    143. }
    144. int mpi_dec_test_decode(char **argv)
    145. {
    146. MPP_RET ret = MPP_OK;
    147. size_t file_size = 0;
    148. MppParam param = NULL;
    149. RK_U32 need_split = 1;
    150. MpiDecLoopData data;
    151. memset(&data, 0, sizeof(data));
    152. data.eos = 0;
    153. data.packet_size = MPI_DEC_STREAM_SIZE;
    154. data.frame_count = 0;
    155. data.frame_num = 1;
    156. data.fp_input = fopen(argv[1], "rb");
    157. data.fp_output = fopen(argv[2], "w+");
    158. if ( (NULL == data.fp_input) || (NULL == data.fp_output) ) {
    159. printf("failed to open input/output file \n");
    160. goto MPP_TEST_OUT;
    161. }
    162. data.buf = mpp_malloc(char, data.packet_size);
    163. ret = mpp_packet_init(&data.packet, data.buf, data.packet_size);
    164. if(MPP_OK != ret){
    165. printf("mpp_packet_init error\n");
    166. goto MPP_TEST_OUT;
    167. }
    168. ret = mpp_create(&data.ctx, &data.mpi);
    169. if(MPP_OK != ret){
    170. printf("mpp_create error\n");
    171. goto MPP_TEST_OUT;
    172. }
    173. ret = mpp_init(data.ctx, MPP_CTX_DEC, MPP_VIDEO_CodingAVC);
    174. if (MPP_OK != ret)
    175. {
    176. printf("mpp_init failed\n");
    177. goto MPP_TEST_OUT;
    178. }
    179. param = &need_split;
    180. ret = data.mpi->control(data.ctx, MPP_DEC_SET_PARSER_SPLIT_MODE, param);
    181. if (MPP_OK != ret) {
    182. printf("mpi->control failed\n");
    183. goto MPP_TEST_OUT;
    184. }
    185. fseek(data.fp_input, 0L, SEEK_END);
    186. file_size = ftell(data.fp_input);
    187. rewind(data.fp_input);
    188. printf("input file size %ld\n", file_size);
    189. while (!data.eos)
    190. {
    191. decode_simple(&data);
    192. }
    193. ret = data.mpi->reset(data.ctx);
    194. if (MPP_OK != ret)
    195. {
    196. printf("mpi->reset failed\n");
    197. goto MPP_TEST_OUT;
    198. }
    199. MPP_TEST_OUT:
    200. if (data.packet) {
    201. mpp_packet_deinit(&data.packet);
    202. data.packet = NULL;
    203. }
    204. if (data.ctx) {
    205. mpp_destroy(data.ctx);
    206. data.ctx = NULL;
    207. }
    208. if (data.buf) {
    209. mpp_free(data.buf);
    210. data.buf = NULL;
    211. }
    212. if (data.frm_grp) {
    213. mpp_buffer_group_put(data.frm_grp);
    214. data.frm_grp = NULL;
    215. }
    216. if (data.fp_output){
    217. fclose(data.fp_output);
    218. data.fp_output = NULL;
    219. }
    220. if (data.fp_input) {
    221. fclose(data.fp_input);
    222. data.fp_input = NULL;
    223. }
    224. return ret;
    225. }
    226. int main(int argc, char **argv)
    227. {
    228. RK_S32 ret = 0;
    229. if(argc != 3 ){
    230. printf("please input options\n");
    231. return -1;
    232. }
    233. ret = mpi_dec_test_decode(argv);
    234. return ret;
    235. }

    10、测试MPP解码H264,解码输出格式为YUV420SP

    ./mpi_dec_test input.h264 out.yuv

  • 相关阅读:
    Matlab信号处理3:fft(快速傅里叶变换)标准使用方式
    信息安全软考 第二章 网络攻击原理与常用方法笔记总结
    武汉新时标文化传媒有限公司短视频中需要的平台和软件都是这样的
    【优化调度】粒子群算法求解水火电调度优化问题【含Matlab源码 1181期】
    分治算法求解:逆序对,Max Sum,棋盘覆盖,a-Good String——中山大学软件工程学院算法第四次实验课 必做+选做题
    echarts实现3d饼图
    了解 HTTPS 中间人攻击:保护你的网络安全
    AI短视频制作一本通:文本生成视频、图片生成视频、视频生成视频
    echarts点击按钮排序
    如果我在初用tomcat时,是看到这篇tomcat架构解析,是不是就不会被说菜鸡了!
  • 原文地址:https://blog.csdn.net/fanyun_01/article/details/126089171