Toybrick

RK3399Pro入门教程(8)6路1080P30帧解码显示范例

jefferyzhang

超级版主

积分
2213
发表于 2019-8-26 10:53:32    查看: 3322|回复: 40 | [复制链接]    打印 | 显示全部楼层
本帖最后由 jefferyzhang 于 2019-9-4 10:58 编辑




前言:

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()
复制代码




代码解析:
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资源。


效果图:



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





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

jefferyzhang

超级版主

积分
2213
 楼主| 发表于 2019-8-26 10:53:52 | 显示全部楼层
本帖最后由 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

新手上路

积分
12
发表于 2019-9-3 10:25:21 | 显示全部楼层
有OpenGL via DRM的C++示例吗?
回复

使用道具 举报

jefferyzhang

超级版主

积分
2213
 楼主| 发表于 2019-9-4 08:19:58 | 显示全部楼层
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

中级会员

积分
268
发表于 2019-9-5 09:01:48 | 显示全部楼层
你好,我是 rk3399 pro 开发板,debian9 系统。以上技术方案有没有我们这个对应版本的,我计划用 2个 USB-摄像头 ,这样的话,1080p 30帧能达到吗?
回复

使用道具 举报

jefferyzhang

超级版主

积分
2213
 楼主| 发表于 2019-9-5 12:06:04 | 显示全部楼层
shopping 发表于 2019-9-5 09:01
你好,我是 rk3399 pro 开发板,debian9 系统。以上技术方案有没有我们这个对应版本的,我计划用 2个 USB- ...

usb cam的这个要评估usb带宽够不够。我们板子上处理是没有问题的。这个我跟我们老大说下,看看能不能做个demo
回复

使用道具 举报

geekioe

新手上路

积分
16
发表于 2019-9-6 12:00:53 | 显示全部楼层
1、使用上述的方式做6路摄像头硬解码;
2、然后再对6路视频流做人脸检测,做人脸计数;
这样理论上是否可行?
回复

使用道具 举报

shopping

中级会员

积分
268
发表于 2019-9-6 14:42:47 | 显示全部楼层
jefferyzhang 发表于 2019-9-5 12:06
usb cam的这个要评估usb带宽够不够。我们板子上处理是没有问题的。这个我跟我们老大说下,看看能不能做个 ...

好的,谢谢,最起码 720p 。
回复

使用道具 举报

jefferyzhang

超级版主

积分
2213
 楼主| 发表于 2019-9-6 14:59:38 | 显示全部楼层
geekioe 发表于 2019-9-6 12:00
1、使用上述的方式做6路摄像头硬解码;
2、然后再对6路视频流做人脸检测,做人脸计数;
这样理论上是否可行 ...

当然可行,看你模型运行速度是多少,你需要的帧率是多少,一个NPU够不够算,不够就多加几个。
带宽上是没有问题的。
回复

使用道具 举报

geekioe

新手上路

积分
16
发表于 2019-9-9 09:28:17 | 显示全部楼层
jefferyzhang 发表于 2019-9-6 14:59
当然可行,看你模型运行速度是多少,你需要的帧率是多少,一个NPU够不够算,不够就多加几个。
带宽上是没 ...

get~
我自己测试看看,不够的话,挂在计算棒的形式是可行的对吧?
回复

使用道具 举报

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

本版积分规则

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


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