Toybrick

标题: RK3399Pro入门教程(8)6路1080P30帧解码显示范例 [打印本页]

作者: jefferyzhang    时间: 2019-8-26 10:53
标题: RK3399Pro入门教程(8)6路1080P30帧解码显示范例
本帖最后由 jefferyzhang 于 2019-9-4 10:58 编辑

[attach]509[/attach]



前言:

RK3399Pro拥有六路1080P30帧解码能力,很多开发者不知道如何快速搭建这么一个Demo,这里我们社区开发者团队编写了一套Toybrick简单上手的python库,可以让大家快速上手编写各种demo。
该库目前还在非常早期的测试版本阶段,还未正式发布。并且需要注意以下几点:

1. 该python模块仅用于快速开发调试,方便同学们将注意力放在神经网络上,但是不建议用于正式项目。
2. 该python模块仅授权Toybrick开发版使用,包含Toybrick 3399Pro和Toybrick 1808计算棒,其他产品我们无法提供支持。
3. 该python模块不开源。所有代码在各个模块的demo中都有,正式做项目还请参看RK的各个模块的demo来改。
4. 该python模块是为了让开发者专注于神经网络应用的调试,抽象的比较高层,不会提供太多底层控制接口。
5. 有Bug和需求反馈,直接回在帖子里,但是可能修改更新不会很及时,请见谅。


思路分析:

RK3399Pro的VPU支持多路编解码,主控想完成多路编解码并显示,需要有一些开发技巧:

1. 使用多线程处理不同的通路,避免时间被卡在相互等待上。
2. 显示建议用GPU OpenGL来做,速度快,也避免GPU在整个项目中被闲置。
3. Demo主要利用Rtsp获取数据,每个线程做的事基本就是 : Rtsp获取数据 - 解码 - 显示


逻辑代码:

  1. #!/usr/bin/env python3.6
  2. import os
  3. import toybrick as toy
  4. import time
  5. import threading


  6. def func_rtspdisplay(gl, index, url, usr, pwd):
  7.     rtsp = toy.input.createRtspClient(url, usr, pwd)
  8.     rtsp.connect()

  9.     last = time.time()
  10.     while rtsp.is_opened():
  11.         frame = rtsp.read_rgb(640, 360)
  12.         now = time.time()
  13.         gl.show(index, frame)
  14.         print("> [%d] got frame. use = %f s" % (index, now - last))
  15.         last = now

  16.     print('# End of Thread %d' % (index))


  17. if __name__ == '__main__':
  18.     os.system('iptables -F')  # Disable Firewall

  19.     gl = toy.output.createGLDrmDisplay(toy.DisplayPort.HDMI_A)
  20.     idx0 = gl.add_view(0, 180, 640, 360)
  21.     idx1 = gl.add_view(640, 180, 640, 360)
  22.     idx2 = gl.add_view(1280, 180, 640, 360)
  23.     idx3 = gl.add_view(0, 540, 640, 360)
  24.     idx4 = gl.add_view(640, 540, 640, 360)
  25.     idx5 = gl.add_view(1280, 540, 640, 360)

  26.     t0 = threading.Thread(target=func_rtspdisplay, args = (gl, idx0, "rtsp://192.168.169.13/cam/realmonitor?channel=1&subtype=0", "admin", "admin123"))
  27.     t1 = threading.Thread(target=func_rtspdisplay, args = (gl, idx1, "rtsp://192.168.169.16/cam/realmonitor?channel=1&subtype=0", "admin", "admin123"))
  28.     t2 = threading.Thread(target=func_rtspdisplay, args = (gl, idx2, "rtsp://192.168.169.13/cam/realmonitor?channel=1&subtype=0", "admin", "admin123"))
  29.     t3 = threading.Thread(target=func_rtspdisplay, args = (gl, idx3, "rtsp://192.168.169.16/cam/realmonitor?channel=1&subtype=0", "admin", "admin123"))
  30.     t4 = threading.Thread(target=func_rtspdisplay, args = (gl, idx4, "rtsp://192.168.169.13/cam/realmonitor?channel=1&subtype=0", "admin", "admin123"))
  31.     t5 = threading.Thread(target=func_rtspdisplay, args = (gl, idx5, "rtsp://192.168.169.16/cam/realmonitor?channel=1&subtype=0", "admin", "admin123"))

  32.     t0.start()
  33.     t1.start()
  34.     t2.start()
  35.     t3.start()
  36.     t4.start()
  37.     t5.start()

  38.     t0.join()
  39.     t1.join()
  40.     t2.join()
  41.     t3.join()
  42.     t4.join()
  43.     t5.join()
复制代码

[attach]506[/attach]


代码解析:
1. main函数首先创建了一个OpenGL via DRM的显示接口,输出目的地是HDMI-A
2. 然后该接口允许我们在屏幕上新建6个不同位置的显示窗口
3. 完成后新建了6个线程,每个线程都执行同样的一个函数 func_rtspdisplay
4. func_rtspdisplay函数都通过传入参数获取rtsp码流,然后直接显示在第二步建立的gl窗口上。


该套库的特点:

1. 自动使用VPU硬件进行解码
2. 解码到缩放到显示全部是硬件连续地址,没有mmap虚拟地址,完全0拷贝,速度很快。
3. 使用GPU绘制6路显示接口,不占用CPU资源。


效果图:

[attach]512[/attach][attach]513[/attach]

---------------- 二楼提供快速开发工具包说明 --------------->






作者: jefferyzhang    时间: 2019-8-26 10:53
本帖最后由 jefferyzhang 于 2019-9-17 09:06 编辑



快速开发包简介:

1. 收集和提供常用input/output接口抽象(目前版本input仅有rtsp client,output仅有显示)
2. 对接numpy array和3399硬件buffer分配和操作接口
3. 对接硬件RGA实现缩放、旋转
4. 对接硬件GPU实现OpenGL显示
5. 目前还处于非常早期的开发阶段,仅能保证多路Rtsp解码显示Sample能正常运行。


版权说明:

1. 该快速开发库由Toybrick社区开发团队编写,并未授权开放源码,使用上有问题也请直接在社区提出。
2. 仅授权Toybrick开发版使用(包含Toybrick 3399Pro和Toybrick 1808计算棒,并不包含任何EVB开发版,也不包含Rockchip其他芯片方案),不建议在Toybrick正式项目使用。


API接口列表:

  1. # Main API Lists V0.2.X

  2. ## Graphic Buffer

  3. gbuf = toybrick.createGraphicBuffer(width, height, GraphicFormat.<format>)      # 新建buffer
  4. gbuf.array()                                                                    # 获取np数组
  5. gbuf.resize(width, height)                                                      # 缩放
  6. gbuf.rotate(degree)                                                             # 旋转
  7. gbuf.memcpy_from(byte_list)                                                     # 从np数组拷贝


  8. ## toybrick.in                                                                  # 输入

  9. rtspc = toybrick.in.createRtspClient(url, user, password, usetcp, verbose)      # 新建Rtsp客户端
  10. rtspc.set_url(url, user, password)                                              # 设置rtsp地址(如果构造时候没设置的话)
  11. rtspc.connect()                                                                 # 开始连接
  12. rtspc.disconnect()                                                              # 断开连接
  13. rtspc.read_rgb(width, height) -> GraphicBuffer                                  # 获取RGB帧(自带缩放)


  14. ## toybrick.out                                                                 # 输出

  15. drmdisp = toybrick.out.createDrmDisplay(DisplayPort.<port>, DisplayMode.<mode>) # DRM显示输出(建议用GL来显示)
  16. drmdisp.printConnects()                                                         # 打印出所有可显示设备
  17. drmdisp.show(index, frame)                                                      # 在mode的index位置显示一帧 (只支持GraphicBuffer)

  18. gldisp = toybrick.output.createGLDrmDisplay(DisplayPort.<port>)                 # OpenGL via DRM 显示
  19. gldisp.add_view(x, y, w, h) -> index                                            # 新增矩形显示区域 (屏幕左下角为坐标原点,右上角为(1920, 1080))
  20. gldisp.show(index, frame)                                                       # 在index的view区域显示一帧(只支持GraphicBuffer)


  21. ## toybrick.rockx                                                               # rockx

  22. rockx = toybrick.createRockx(RockxType.<type>)                                  # 创建 rockx
  23. rockx.inference(img) -> Dict                                                    # AI推理(可支持GraphicBuffer或者nparray输入)
复制代码



下载地址:

链接: https://pan.baidu.com/s/1RxHPu5ogBD0WNtHpQ3RXTg 提取码: snwf


安装方式:

  1. dnf install python3-toybrick-0.2-8.aarch64.rpm
复制代码


卸载方式:

  1. dnf remove python3-toybrick
复制代码

如果卸载报错(测试版本很可能会陷入卸载报错永远卸载不掉的情况), 可以增加卸载参数 --setopt=tsflags=noscripts来解决:
  1. dnf remove --setopt=tsflags=noscripts  python3-toybrick
复制代码





作者: bingqingsuimeng    时间: 2019-9-3 10:25
有OpenGL via DRM的C++示例吗?
作者: jefferyzhang    时间: 2019-9-4 08:19
bingqingsuimeng 发表于 2019-9-3 10:25
有OpenGL via DRM的C++示例吗?

这个mali库就是libmali_gbm.so的,通过这个库渲染的就是通过DRM显示的。
然后mali还有libmali_x11.so和libmali_wayland.so对应不同的显示管理平台。

基础示例我曾经给客户写过一个,可以参考:https://github.com/Jerzha/samples-rklinux-opengl
然后可以参考glmark2的源码,那里头有各种画图平台的GL用法。
作者: shopping    时间: 2019-9-5 09:01
你好,我是 rk3399 pro 开发板,debian9 系统。以上技术方案有没有我们这个对应版本的,我计划用 2个 USB-摄像头 ,这样的话,1080p 30帧能达到吗?
作者: jefferyzhang    时间: 2019-9-5 12:06
shopping 发表于 2019-9-5 09:01
你好,我是 rk3399 pro 开发板,debian9 系统。以上技术方案有没有我们这个对应版本的,我计划用 2个 USB- ...

usb cam的这个要评估usb带宽够不够。我们板子上处理是没有问题的。这个我跟我们老大说下,看看能不能做个demo
作者: geekioe    时间: 2019-9-6 12:00
1、使用上述的方式做6路摄像头硬解码;
2、然后再对6路视频流做人脸检测,做人脸计数;
这样理论上是否可行?
作者: shopping    时间: 2019-9-6 14:42
jefferyzhang 发表于 2019-9-5 12:06
usb cam的这个要评估usb带宽够不够。我们板子上处理是没有问题的。这个我跟我们老大说下,看看能不能做个 ...

好的,谢谢,最起码 720p 。
作者: jefferyzhang    时间: 2019-9-6 14:59
geekioe 发表于 2019-9-6 12:00
1、使用上述的方式做6路摄像头硬解码;
2、然后再对6路视频流做人脸检测,做人脸计数;
这样理论上是否可行 ...

当然可行,看你模型运行速度是多少,你需要的帧率是多少,一个NPU够不够算,不够就多加几个。
带宽上是没有问题的。
作者: geekioe    时间: 2019-9-9 09:28
jefferyzhang 发表于 2019-9-6 14:59
当然可行,看你模型运行速度是多少,你需要的帧率是多少,一个NPU够不够算,不够就多加几个。
带宽上是没 ...

get~
我自己测试看看,不够的话,挂在计算棒的形式是可行的对吧?
作者: jefferyzhang    时间: 2019-9-9 09:57
geekioe 发表于 2019-9-9 09:28
get~
我自己测试看看,不够的话,挂在计算棒的形式是可行的对吧?

如果你自己做板子,是可以挂在1808上的,我们1808是有usb总线的
作者: shopping    时间: 2019-9-9 14:26
jefferyzhang 发表于 2019-9-6 14:59
当然可行,看你模型运行速度是多少,你需要的帧率是多少,一个NPU够不够算,不够就多加几个。
带宽上是没 ...

你好,以后公司是计划一个板子同时处理两路视频的输入,看你说的,NPU可以自己加,还是联系厂家帮忙?
作者: jefferyzhang    时间: 2019-9-9 15:05
shopping 发表于 2019-9-9 14:26
你好,以后公司是计划一个板子同时处理两路视频的输入,看你说的,NPU可以自己加,还是联系厂家帮忙? ...

1808计算棒,随便加。。。
3399Pro带一个NPU,1808计算棒也带NPU,你想插几个都可以
作者: Sean    时间: 2019-9-10 11:12
下载地址失效了,请问是怎么回事啊???
作者: shopping    时间: 2019-9-10 16:45
本帖最后由 shopping 于 2019-9-10 16:46 编辑
jefferyzhang 发表于 2019-9-9 15:05
1808计算棒,随便加。。。
3399Pro带一个NPU,1808计算棒也带NPU,你想插几个都可以 ...

贵公司的NPU可以同时跑两个目标检测算法模型吗(mobilenet-ssd这种)?如果可以,帧率最大会是多少? 还有你那个1080的棒子多少钱一个?
作者: jefferyzhang    时间: 2019-9-11 08:16
shopping 发表于 2019-9-10 16:45
贵公司的NPU可以同时跑两个目标检测算法模型吗(mobilenet-ssd这种)?如果可以,帧率最大会是多少? 还有 ...

请看本社区顶部商城链接和wiki链接
作者: kyeteo    时间: 2019-9-16 11:04
    dnf install python3-toybrick-0.2-8.aarch64.rpm
这个指令无法安装,显示找不到包是啥原因呀
作者: 18958105257    时间: 2019-9-16 13:41
@jefferyzhang  你好j链接: https://pan.baidu.com/s/1B1tt0YptruPuNLekCuh5gQ 提取码: d91q; 这个地址过期了,能不能再发一份;谢谢;

作者: jefferyzhang    时间: 2019-9-17 09:05
18958105257 发表于 2019-9-16 13:41
@jefferyzhang  你好j链接: https://pan.baidu.com/s/1B1tt0YptruPuNLekCuh5gQ 提取码: d91q; 这个地址过 ...

链接: https://pan.baidu.com/s/1RxHPu5ogBD0WNtHpQ3RXTg 提取码: snwf 复制这段内容后打开百度网盘手机App,操作更方便哦
作者: jefferyzhang    时间: 2019-9-17 09:05
kyeteo 发表于 2019-9-16 11:04
dnf install python3-toybrick-0.2-8.aarch64.rpm
这个指令无法安装,显示找不到包是啥原因呀 ...

下载到本地安装
作者: duanyanbiao    时间: 2019-9-18 18:18
ImportError: librknn_api.so: cannot open shared object file: No such file or directory
我遇到这个问题,是因为系统版本太老吗?
作者: jefferyzhang    时间: 2019-9-19 10:18
duanyanbiao 发表于 2019-9-18 18:18
ImportError: librknn_api.so: cannot open shared object file: No such file or directory
我遇到这个问 ...

No such file or directory

是toybrick板子么?我们所有固件都有这个so
作者: 18958105257    时间: 2019-9-19 14:14




  File "1demo_multi_gldisplay.py", line 3, in <module>
    import toybrick as toy
  File "/usr/local/lib/python3.6/site-packages/toybrick/__init__.py", line 18, in <module>
    from toybrick.rockx import createRockx, RockxType, Rockx
  File "/usr/local/lib/python3.6/site-packages/toybrick/rockx.py", line 1, in <module>
    from . import rkrockx
ImportError: librockx.so: cannot open shared object file: No such file or directory
请教一下,报librockx.so  板子是你们的 , 系统fedaro 28, V1.5
作者: 18958105257    时间: 2019-9-19 16:10
已经找到了,谢谢
作者: jefferyzhang    时间: 2019-9-19 17:27
18958105257 发表于 2019-9-19 14:14
File "1demo_multi_gldisplay.py", line 3, in
    import toybrick as toy
  File "/usr/local/lib ...

嗯,rockx是要单独安装的。
作者: yuys    时间: 2019-9-24 14:20
jefferyzhang 发表于 2019-9-19 17:27
嗯,rockx是要单独安装的。

版主怎么安装呢?有教程?
作者: jefferyzhang    时间: 2019-9-24 14:52
yuys 发表于 2019-9-24 14:20
版主怎么安装呢?有教程?

查看论坛置顶rockx发布贴
作者: sliver    时间: 2019-10-11 17:22
jefferyzhang 发表于 2019-8-26 10:53
快速开发包简介:

1. 收集和提供常用input/output接口抽象(目前版本input仅有rtsp client,output仅有 ...

GPU显示的时候,是把RGB图片生成纹理贴上去的吗
作者: jefferyzhang    时间: 2019-10-12 08:47
sliver 发表于 2019-10-11 17:22
GPU显示的时候,是把RGB图片生成纹理贴上去的吗

是的,而且纹理不一定是RGB格式,openGL的纹理支持很多种格式。具体可以查看下gl的文档。

作者: heyunteng251314    时间: 2019-10-28 14:05
版主,你好!目前我基于opengl es上实时播放MP4视频数据,发现处理速率很慢。处理流是将MP4中H264码流中的YUV420数据用GPU模块转化成RGB,将RGB数据生成纹理贴图通过DRM来显示,2560*1440的数据流处理速率在20ms/Fs的情况,感觉有点慢。请问你显示6路,YUV数据流是怎么转化的呢?
作者: jefferyzhang    时间: 2019-10-28 14:17
heyunteng251314 发表于 2019-10-28 14:05
版主,你好!目前我基于opengl es上实时播放MP4视频数据,发现处理速率很慢。处理流是将MP4中H264码流中的Y ...

shader转换。sample可以参看下gles的例子。

作者: heyunteng251314    时间: 2019-10-28 17:16
本帖最后由 heyunteng251314 于 2019-10-28 17:18 编辑
jefferyzhang 发表于 2019-10-28 14:17
shader转换。sample可以参看下gles的例子。

很感激版主的回复!我用的就是shader的转化模式D:\CodeFile\shader.bmp,我想请教一下你,你那DEMON是直接用YUV做贴图,没有转化成RGB的过程嘛?
作者: jefferyzhang    时间: 2019-10-28 17:20
heyunteng251314 发表于 2019-10-28 17:16
很感激版主的回复!我用的就是shader的转化模式,我想请教一下你,你那DEMON是直接用YUV做贴图,没有转化成 ...

你百度下就有了吧,这个很多的。我现在凭空也找不出代码给你啊。。。
我那个是直接YUV贴的,主要是看前面出来的的格式,264解出来就是nv12了,就不用再转一次了,浪费时间。

作者: jefferyzhang    时间: 2019-10-28 17:23
还有要看opengl最终画布大小,最终画布1080p的话,就画这么6个矩形不需要多少时间的。
这颗gpu在安卓玩3d游戏都没啥问题,就这么6个矩形也不是什么问题。
作者: iamher0    时间: 2019-11-4 17:01
本帖最后由 iamher0 于 2019-11-4 17:07 编辑

debian上的安装包有吗?另外 mpp出来的视频帧,输入到NPU,可以实现零COPY吗?

作者: jefferyzhang    时间: 2019-11-4 19:00
iamher0 发表于 2019-11-4 17:01
debian上的安装包有吗?另外 mpp出来的视频帧,输入到NPU,可以实现零COPY吗?
...

没有。
NPU都不可能0拷贝,就像PC上GPU也不可能0拷贝,两个ddr不是通的
作者: iamher0    时间: 2019-11-5 09:03
jefferyzhang 发表于 2019-11-4 19:00
没有。
NPU都不可能0拷贝,就像PC上GPU也不可能0拷贝,两个ddr不是通的

通过DMA呢,不通过CPU可行吗?
作者: jefferyzhang    时间: 2019-11-5 09:31
iamher0 发表于 2019-11-5 09:03
通过DMA呢,不通过CPU可行吗?

不可行,主控DDR和NPU的DDR之间没有DMA
作者: shopping    时间: 2019-11-6 14:10
bingqingsuimeng 发表于 2019-9-3 10:25
有OpenGL via DRM的C++示例吗?

老哥,请问你 DRM 显示搞好没有?
作者: cr7jj    时间: 7 天前
你好,我试过用你这个代码不能播放VLC流,怎么解决?
作者: huangzk    时间: 5 天前
您好,请问这边有 android 平台 6路 播放的 apk demo吗?




欢迎光临 Toybrick (http://t.rock-chips.com/) Powered by Discuz! X3.3