Toybrick

RK3399Pro入门教程(6)硬件编解码器MPP库的使用

 

swlmx

注册会员

积分
195
楼主
发表于 2019-9-10 14:33:50 | 显示全部楼层
楼主好。我在Android环境下用java的MediaCodec API读取YUV编码h.264,然后demsg显示要20毫秒编码一帧,达不到同时两路1080p@30fps呢?

下面是编码的代码

  1. public void encode(byte[] yuvFrame){
  2.         int inputBufferIndex = codec.dequeueInputBuffer(-1);

  3.         if (inputBufferIndex >= 0) {
  4.             ByteBuffer inputBuffer;
  5.             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  6.                 inputBuffer = codec.getInputBuffer(inputBufferIndex);
  7.             } else {
  8.                 inputBuffer = codec.getInputBuffers()[inputBufferIndex];
  9.             }
  10.             pts = computePresentationTime(generateIndex);
  11.             if (inputBuffer != null) {
  12.                 inputBuffer.clear();
  13.                 inputBuffer.put(yuvFrame, 0, yuvFrame.length);
  14.                 codec.queueInputBuffer(inputBufferIndex, 0, yuvFrame.length, pts, 0);
  15.             }
  16.             generateIndex += 1;
  17.         }
  18.         MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();

  19.         int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, DEFAULT_TIMEOUT_US);

  20.         while (outputBufferIndex >= 0) {
  21.             ByteBuffer outputBuffer;
  22.             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  23.                 outputBuffer = codec.getOutputBuffer(outputBufferIndex);
  24.             } else {
  25.                 outputBuffer = codec.getOutputBuffers()[outputBufferIndex];
  26.             }
  27.             if (outputBuffer != null) {
  28.                 byte[] outData = new byte[bufferInfo.size];
  29.                 outputBuffer.get(outData);
  30.                 if (bufferInfo.flags == 2) {
  31.                     configByte = outData;
  32.                 } else if (bufferInfo.flags == 1) {
  33.                     byte[] keyframe = new byte[bufferInfo.size + configByte.length];
  34.                     System.arraycopy(configByte, 0, keyframe, 0, configByte.length);
  35.                     System.arraycopy(outData, 0, keyframe, configByte.length, outData.length);

  36.                     if (null != callback) {
  37.                         callback.onFrame(this, keyframe);
  38.                     }
  39.                 } else {
  40.                     if (null != callback) {
  41.                         callback.onFrame(this, outData);
  42.                     }
  43.                 }

  44.                 codec.releaseOutputBuffer(outputBufferIndex, false);
  45.             }
  46.             outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, DEFAULT_TIMEOUT_US);
  47.         }
  48.     }

  49.     /**
  50.      * Generates the presentation time for frame N, in microseconds.
  51.      */
  52.     private long computePresentationTime(long frameIndex) {
  53.         return frameIndex * 1000000 / FPS;
  54.     }
复制代码
回复

使用道具 举报

swlmx

注册会员

积分
195
沙发
发表于 2019-9-12 15:54:24 | 显示全部楼层
jefferyzhang 发表于 2019-9-11 08:18
编码在VPU跑 300MHz情况下只能一路1080p30,
跑2路需要将频率提到400MHz或者更高 ...

那怎么提升VPU频率呢
回复

使用道具 举报

swlmx

注册会员

积分
195
板凳
发表于 2019-9-24 10:09:24 | 显示全部楼层
4. you can get demo about mpp applied to linux and android.
     Liunx : https://github.com/WainDing/mpp_linux_cpp
     Android : https://github.com/c-xh/MediaCodecDecodeMulti_h264

安卓的失效了,能重新放一个demo吗
回复

使用道具 举报

swlmx

注册会员

积分
195
地板
发表于 2019-9-24 17:12:57 | 显示全部楼层
jefferyzhang 发表于 2019-9-24 10:38
https://github.com/c-xh/mediacodec_gl_decode_multi_h264_file

好的 谢谢
回复

使用道具 举报

swlmx

注册会员

积分
195
5#
发表于 2019-10-24 13:50:36 | 显示全部楼层
jefferyzhang 发表于 2019-5-17 11:05
mpp的build目录里有安卓编译。
我们的android也是自带libmpp的,无需编译。
android的media_codec默认就 ...

楼主,我现在想解码 Mjpeg,但是 mediacodec api 好像不支持 video/mjpeg。
应用层又无法通过 System.loadLibrary() 载入 libmpp (报错 E/linker: library "/vendor/lib/libmpp.so" ("/vendor/lib/libmpp.so") needed or dlopened by "/system/lib/libnativeloader.so" is not accessible for the namespace)。看起来android N开始应用层无法载入系统私有库。
所以要怎么测试解码mjpeg?
回复

使用道具 举报

swlmx

注册会员

积分
195
6#
发表于 2019-10-30 11:20:52 | 显示全部楼层
jefferyzhang 发表于 2019-10-24 18:04
可以直接用安卓jpeg loader来读,底层我记得是对接过硬件的(大于多少像素会用VPU解),具体我也不是很清 ...

libmpp.so是armv7的?1.3固件。
我用v8a的库链接报错
回复

使用道具 举报

swlmx

注册会员

积分
195
7#
发表于 2019-11-5 10:40:22 | 显示全部楼层
jefferyzhang 发表于 2019-10-30 11:43
toybrick里带的都是64bit的

我yuv编码jpeg出现 jpege_api: jpege: hardware return error status 40 。存下来的图底部是花的,是哪里出了问题?代码如下

  1. void doCodec(){
  2.     MppCtx ctx;
  3.     MppApi *mpi;
  4.     MpiCmd cmd = MPP_SET_OUTPUT_BLOCK;
  5.     MppParam param      = NULL;
  6.     MppPollType block   = MPP_POLL_BLOCK;
  7.     MppCodingType type = MPP_VIDEO_CodingMJPEG;
  8.     int MPI_ENC_LOOP_COUNT = 1;
  9.     __android_log_print(ANDROID_LOG_DEBUG, "JNI","mpp_create");

  10.     if(MPP_OK != mpp_create(&ctx, &mpi)){
  11.         __android_log_print(ANDROID_LOG_DEBUG, "JNI","mpp_create failed");
  12.         goto MPP_TEST_FAILED;
  13.     }
  14.     __android_log_print(ANDROID_LOG_DEBUG, "JNI","mpp_init");

  15.     if(MPP_OK != mpp_init(ctx, MPP_CTX_ENC, type)){
  16.         __android_log_print(ANDROID_LOG_DEBUG, "JNI","mpp_init failed");
  17.         goto MPP_TEST_FAILED;
  18.     }

  19.     MppEncRcCfg rcCfg;


  20.     __android_log_print(ANDROID_LOG_DEBUG, "JNI","rcCfg");

  21.     rcCfg.change = MPP_ENC_RC_CFG_CHANGE_ALL;
  22.     rcCfg.rc_mode = (MppEncRcMode) MPP_ENC_RC_MODE_CBR;
  23.     rcCfg.quality = (MppEncRcQuality)MPP_ENC_RC_QUALITY_BEST;
  24.     rcCfg.bps_target = bps;
  25.     rcCfg.bps_max = bps * 17 / 16;
  26.     rcCfg.bps_min = bps * 15 / 16;
  27.     rcCfg.fps_in_flex      = 0;
  28.     rcCfg.fps_in_num       = 24;
  29.     rcCfg.fps_in_denorm    = 1;
  30.     rcCfg.fps_out_flex     = 0;
  31.     rcCfg.fps_out_num      = 24;
  32.     rcCfg.fps_out_denorm   = 1;
  33.     rcCfg.gop = 50;
  34.     if(MPP_OK != mpi->control(ctx, MPP_ENC_SET_RC_CFG, &rcCfg)){
  35.         __android_log_print(ANDROID_LOG_DEBUG, "JNI","rcCfg failed");
  36.         goto MPP_TEST_FAILED;
  37.     }

  38.     __android_log_print(ANDROID_LOG_DEBUG, "JNI","prepCfg");

  39.     MppEncPrepCfg prepCfg;
  40.     prepCfg.change = MPP_ENC_PREP_CFG_CHANGE_INPUT | MPP_ENC_PREP_CFG_CHANGE_FORMAT;
  41.     prepCfg.width = 1920;
  42.     prepCfg.height = YUV_HEIGHT;
  43.     prepCfg.hor_stride = MPP_ALIGN(1920, 8);
  44.     prepCfg.ver_stride = MPP_ALIGN(YUV_HEIGHT, 8);
  45.     prepCfg.format = MPP_FMT_YUV420P;

  46.     if(MPP_OK != mpi->control(ctx, MPP_ENC_SET_PREP_CFG, &prepCfg)){
  47.         __android_log_print(ANDROID_LOG_DEBUG, "JNI","rcCfg failed");
  48.         goto MPP_TEST_FAILED;
  49.     }
  50.    
  51.     __android_log_print(ANDROID_LOG_DEBUG, "JNI","codecCfg");
  52.     MppEncCodecCfg codecCfg;


  53.     if(MPP_OK != mpi->control(ctx, MPP_ENC_SET_CODEC_CFG, &codecCfg)){
  54.         __android_log_print(ANDROID_LOG_DEBUG, "JNI","codecCfg failed");
  55.         goto MPP_TEST_FAILED;
  56.     }
  57.    

  58.     MppPacket enc_out;
  59.     MppFrame enc_in;

  60.     param = █

  61.     MppBuffer frm_buf;
  62.     unsigned char *buf2;
  63.     mpp_buffer_get(NULL, &frm_buf, MPP_ALIGN(1920, 8) * MPP_ALIGN(YUV_HEIGHT, 8) * 3 / 2);


  64.     FILE *file;
  65.     file = fopen("/sdcard/single_frame.yuv", "rb");
  66.     buf2 = (unsigned char *)malloc(YUV_SIZE);
  67.     memset(buf2, 0, YUV_SIZE);

  68.     fread(buf2, 1, YUV_SIZE, file);



  69.     if(MPP_OK != mpi->control(ctx, MPP_SET_OUTPUT_BLOCK, param)){
  70.         __android_log_print(ANDROID_LOG_DEBUG, "JNI","control failed");
  71.         goto MPP_TEST_FAILED;
  72.     }

  73.     // interface with both input and output
  74.     for (int i = 0; i < MPI_ENC_LOOP_COUNT; i++) {
  75.         unsigned char *buf;
  76.         buf = (unsigned char *)mpp_buffer_get_ptr(frm_buf);


  77.         memcpy(buf, buf2, YUV_SIZE);


  78.         mpp_frame_init(&enc_in);


  79.         mpp_frame_set_width(enc_in, 1920);
  80.         mpp_frame_set_height(enc_in, YUV_HEIGHT);
  81.         mpp_frame_set_hor_stride(enc_in, MPP_ALIGN(1920, 8));
  82.         mpp_frame_set_ver_stride(enc_in, MPP_ALIGN(YUV_HEIGHT, 8));
  83.         mpp_frame_set_fmt(enc_in, MPP_FMT_YUV420P);
  84.         mpp_frame_set_buffer(enc_in, frm_buf);
  85.         mpp_frame_set_eos(enc_in, 0);





  86.         if (MPP_OK != mpi->encode_put_frame(ctx, enc_in)) {
  87.             __android_log_print(ANDROID_LOG_DEBUG, "JNI","encode_put_frame failed");
  88.             goto MPP_TEST_FAILED;
  89.         } else{

  90.             if (MPP_OK != mpi->encode_get_packet(ctx, &enc_out)) {
  91.                 __android_log_print(ANDROID_LOG_DEBUG, "JNI","encode_get_packet failed");
  92.                 goto MPP_TEST_FAILED;
  93.             } else{
  94.                 if(enc_out){
  95.                     __android_log_print(ANDROID_LOG_DEBUG, "JNI","enc_out!");
  96.                     void *ptr   = mpp_packet_get_pos(enc_out);
  97.                     size_t len  = mpp_packet_get_length(enc_out);
  98.                     RK_U32 eos = mpp_packet_get_eos(enc_out);
  99.                     unsigned char* out_buf = new unsigned char[len];
  100.                     memcpy(out_buf, ptr, len);

  101.                     FILE *outfile = fopen("/sdcard/output.jpeg", "wb+");
  102.                     fwrite(out_buf, 1, len, outfile);
  103.                     fclose(outfile);

  104.                     mpp_packet_deinit(&enc_out);
  105.                 }
  106.             }
  107.         }

  108.         mpp_frame_deinit(&enc_in);
  109.     }

  110.     mpi->reset(ctx);

  111.     if (enc_in){
  112.         mpp_frame_deinit(&enc_in);

  113.     }

  114.     mpp_destroy(ctx);
  115.     free(buf2);

  116.     __android_log_print(ANDROID_LOG_DEBUG, "JNI","mpi_test success");


  117.     return;

  118.     MPP_TEST_FAILED:

  119.     if (enc_in){
  120.         mpp_frame_deinit(&enc_in);
  121.     }
  122.     if (ctx){
  123.         mpp_destroy(ctx);
  124.     }
  125.     if (buf2){
  126.         free(buf2);
  127.     }


  128. }
复制代码
回复

使用道具 举报

swlmx

注册会员

积分
195
8#
发表于 2019-11-6 11:31:35 | 显示全部楼层
jefferyzhang 发表于 2019-10-30 11:43
toybrick里带的都是64bit的

你们固件里面libmpp.so确实是armv7的,我下载github上mpp的testcode编译出来armv8找不到libmpp.so,只有v7才能运行,而且输出也不正常……
回复

使用道具 举报

swlmx

注册会员

积分
195
9#
发表于 2019-11-6 13:58:38 | 显示全部楼层
jefferyzhang 发表于 2019-11-6 12:52
你说的是安卓还是linux?

安卓 字数补丁
回复

使用道具 举报

swlmx

注册会员

积分
195
10#
发表于 2019-11-8 16:44:41 | 显示全部楼层
本帖最后由 swlmx 于 2019-11-8 16:54 编辑
jefferyzhang 发表于 2019-11-6 15:15
哦,安卓是v7 32bit的,因为安卓的框架mediacodec他是32 only的,所以mpp也必须是32才能被系统调用 ...

我用mpp demo里的decode_advanced代码循环300次平均每解码1帧1080p jpg要26ms,而且dmesg显示解码耗时很离谱。我另外测用jpegturbo解码平均才17ms。
另外demo里decode_simple解不了mjpeg……是不是有bug?

mpp流程循环中的伪代码:
  1. mpp_packet_set_pos
  2. mpp_packet_set_length
  3. //input
  4. mpi->poll
  5. mpi->dequeue
  6. mpp_task_meta_set_packet
  7. mpp_task_meta_set_frame
  8. mpi->enqueue
  9. //output
  10. mpi->poll
  11. mpi->dequeue
  12. mpp_task_meta_get_frame
  13. mpi->enqueue
复制代码


dmesg里的log:
  1. [83150.339427] rk_vcodec: vpu2_dec task: 1573200164298 ms
  2. [83150.368903] rk_vcodec: vpu2_dec task: 1573200164327 ms
  3. [83150.394374] rk_vcodec: vpu2_dec task: 1573200164353 ms
  4. [83150.419830] rk_vcodec: vpu2_dec task: 1573200164378 ms
  5. [83150.445152] rk_vcodec: vpu2_dec task: 1573200164404 ms
  6. [83150.470661] rk_vcodec: vpu2_dec task: 1573200164429 ms
  7. [83150.496018] rk_vcodec: vpu2_dec task: 1573200164455 ms
  8. [83150.521544] rk_vcodec: vpu2_dec task: 1573200164480 ms
  9. [83150.550334] rk_vcodec: vpu2_dec task: 1573200164509 ms
  10. [83150.579556] rk_vcodec: vpu2_dec task: 1573200164538 ms
  11. [83150.620477] rk_vcodec: vpu2_dec task: 1573200164579 ms
  12. [83150.649453] rk_vcodec: vpu2_dec task: 1573200164608 ms
  13. [83150.678954] rk_vcodec: vpu2_dec task: 1573200164637 ms
  14. [83150.702283] rk_vcodec: vpu2_dec task: 1573200164661 ms
复制代码


感觉是把当前时间戳打出来了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

产品中心 购买渠道 开源社区 Wiki教程 资料下载 关于Toybrick


快速回复 返回顶部 返回列表