编辑
2025-03-03
记录知识
0

CAN(Controller Area Network)是一种有效支持分布式控制或实时控制的串行通信网络。CAN总线是一种在汽车上广泛采用的总线协议,被设计作为汽车环境中的微控制器通讯,公司项目逐渐朝车载领域发展,而车载领域使用can的场景越来越多,这里分析一下can的调试技巧,有助于排查can总线的问题

一:can的驱动

drivers/net/can/rockchip/rockchip_can.c drivers/net/can/rockchip/rockchip_canfd.c

rk3588有两个can驱动,均可通过设备树自由选择,默认可选canfd通讯,则设备树如下配置

can0: can@fea50000 { compatible = "rockchip,can-2.0"; reg = <0x0 0xfea50000 0x0 0x1000>; interrupts = <0 341 4>; clocks = <&cru 112>, <&cru 111>; clock-names = "baudclk", "apb_pclk"; resets = <&cru 185>, <&cru 184>; reset-names = "can", "can-apb"; pinctrl-names = "default"; pinctrl-0 = <&can0m0_pins>; tx-fifo-depth = <1>; rx-fifo-depth = <6>; status = "disabled"; }; &can0 { assigned-clocks = <&cru 112>; assigned-clock-rates = <200000000>; status = "okay"; };

真的can总线,默认可以调整其时钟的频率,默认是200M。如遇到分频不精确,可以调整时钟源为其他值,从而提高can总线的采样点

二:命令

2.1 查看can的状态

ip -details -statistics link show can0 2: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10 link/can promiscuity 0 minmtu 0 maxmtu 0 can state ERROR-ACTIVE (berr-counter tx 0 rx 0) restart-ms 1 bitrate 250000 sample-point 0.868 tq 40 prop-seg 42 phase-seg1 43 phase-seg2 13 sjw 1 rockchip_canfd: tseg1 1..128 tseg2 1..128 sjw 1..128 brp 1..256 brp-inc 2 clock 99000000 re-started bus-errors arbit-lost error-warn error-pass bus-off 12020 0 0 12132 3438 12450 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 RX: bytes packets errors dropped overrun mcast 320320 40040 0 0 0 0 TX: bytes packets errors dropped carrier collsns 0 0 0 12020 0 0

这里有如下信息可以着重看到

a.state can总线的状态 b.bitrate 比特率 c.sample-point 采样点 d.TX,RX 数据包状态

2.2 设置can的采样点

ip link set can0 type can tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1

通过设置如上参数,可以修改can的采样,也可以直接设置比特率来自动计算采样点

ip link set can0 type can bitrate 250000

2.3 开启can测试

ip link set can0 down ip link set can0 up type can bitrate 250000 ip link set can0 up while true do cansend can0 00000000#0000000000000000 done

上述命令可以直接打开can0设备,并发送默认数据

2.3 开启can回环测试

ip link set can0 down ip link set can0 up type can bitrate 250000 loopback on ip link set can0 up while true do cansend can0 00000000#0000000000000000 done

上述可以直接测试can的回环

2.4 接收和发送信息

# 接收can信息 candump can0 > can_recv.log & # 发送can信息 cansend can0 123#1122334455 cansend can0 5A1#11.2233.44556677.88 cansend can0 1F334455#1122334455667788

2.5 调试can数据

因为can的数据通过net skb上报,所以解析skb数据即可确定接收和发送的can数据信息。如下函数

static void skb_dump(struct sk_buff *skb, struct net_device *dev){ int i = 0; if(!skb || !dev){ pr_err("%s: bad param\n",__FUNCTION__); goto out; } printk(KERN_CONT "Kylin:Can packets(len=%d): ",skb->len); for (i = 0; i < skb->len; i++){ printk(KERN_CONT "%02x", *(skb->data + i)); } printk(KERN_CONT "\n"); out: return; }

然后只需要将skb_dump函数加入接收可发送的处理中即可。

2.6 确定can的错误帧

对于接收到的can中断,主要有如下中断

#define RX_FINISH_INT BIT(0) #define TX_FINISH_INT BIT(1) #define ERR_WARN_INT BIT(2) #define RX_BUF_OV_INT BIT(3) #define PASSIVE_ERR_INT BIT(4) #define TX_LOSTARB_INT BIT(5) #define BUS_ERR_INT BIT(6) #define RX_FIFO_FULL_INT BIT(7) #define RX_FIFO_OV_INT BIT(8) #define BUS_OFF_INT BIT(9) #define BUS_OFF_RECOVERY_INT BIT(10) #define TSC_OV_INT BIT(11) #define TXE_FIFO_OV_INT BIT(12) #define TXE_FIFO_FULL_INT BIT(13) #define WAKEUP_INT BIT(14)

而关于BUS_ERR的错误,有如下情况

#define BIT_ERR 0 #define STUFF_ERR 1 #define FORM_ERR 2 #define ACK_ERR 3 #define CRC_ERR 4

对应情况可以进去调试即可。

2.7 日志

关于netdev_dbg的日志,可以通过如下步骤

a. #define DEBUG 在驱动内部定义 b. 设置日志等级为8

而其他的netdev_*日志,可直接设置日志等级为8即可查看,如

dmesg -n8

2.8 中断上下文

针对can的问题,可以先确定中断

cat /proc/interrupts | grep can

查看硬件中断是否正常

然后再确定软中断

cat /proc/softirqs CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 HI: 2834 1 1 3 0 0 0 0 TIMER: 7791 33602 36340 57451 22095 6063 31674 5003 NET_TX: 2596 9 7 2 1 3870 2639 3561 NET_RX: 33128 100 36 307 141 3876 2662 21700 BLOCK: 7154 17766 14324 14861 13713 2332 2492 1812 IRQ_POLL: 0 0 0 0 0 0 0 0 TASKLET: 160 2 1 2 1 1 75 3 SCHED: 85621 59461 52573 172213 82530 16771 32225 13479 HRTIMER: 0 0 0 0 0 0 0 0 RCU: 77962 44178 37468 71517 57343 36644 33600 27705

确定NET_RX是否正常,如不正常,则can驱动内的netif_rx调用太频繁

2.9 提高can中断的实时响应

1)dts中去掉所有:cpu-idle-states = <&CPU_SLEEP>; 2)设置成性能模式:echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 3)绑定can的中断到一个特定的cpu上: irq_set_affinity_hint(ndev->irq, get_cpu_mask(num_online_cpus() - 1));
编辑
2025-03-03
记录知识
0

一:adb

1.1 windows系统需要安装adb工具,默认能够使用adb功能

  1. 按键windows+r打开运行
  2. 输入sysdm.cpl,回车
  3. 高级
  4. 环境变量
  5. 系统变量
  6. PATH 将adb.exe添加到系统环境变量

打开命令提示符,输入adb --version 如果正常出现 adb版本信息,则添加成功

1.2 linux系统安装adb工具

  1. 安装
    apt-get install android-tools-adb
  2. lsusb
2207:0006
  1. 创建adb_usb.ini文件,写入android设备的VID
cd ~/.android touch adb_usb.ini

在adb_usb.ini文件中写入以下内容:

0x2207

添加权限: 创建权限文件:touch /etc/udev/rules.d/70-android.rules70-android.rules文件中写入一下内容:

UBSYSTEM=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="d002", MODE="0666"

重启USB服务:

chmod 666 /etc/udev/rules.d/70-android.rules service udev restart

重启adb服务:

adb kill-server adb start-server

查看adb版本:

adb --version

1.3 使用adb工具

  1. 列出adb设备
adb devices List of devices attached 0123456789ABCDEF device
  1. 连接adb
adb shell #
  1. 运行命令“ls”
adb shell ls bin dev home lost+found mnt opt root sbin sys usr boot etc lib media '(null)' proc run srv tmp var
  1. 从设备拉取文件
adb shell touch testfile adb pull testfile testfile: 1 file pulled.
  1. 将文件传到设备中
adb push testfile /tmp/ testfile: 1 file pushed. adb shell ls /tmp/testfile /tmp/testfile

二:lrzsz(通过串口传输文件)

  1. 安装lrzsz
apt install lrzsz
  1. 将文件通过串口发送到设备
输入rz ---> 选择文件发送
  1. 将文件通过串口接收到主机
输入 sz /tmp/testfile ----> 选择需要存放文件的地址

三:samba(共享设备所有文件给主机)

  1. 安装samba
apt-get install samba
  1. 配置samba
[work] comment=this is Linux share directory path=/ public=yes create mode=0777 directory mode=0777 guest ok = yes browseable = yes writeable = yes
  1. 重启samba服务
systemctl restart smbd
  1. 通过IP访问samba文件

在文件管理器下输入IP 即可跳转,账号和密码为系统的账号密码

四:SFTP传输文件

  1. Linux
sftp -p root@172.25.80.124
  1. FileZilla
主机: 172.25.80.124 用户 kylin 密码 qwe123 端口 22

五:CIFS共享文档

  1. Windows打开文件共享

win主机右击要共享的目录,选择属性,在共享页面选择共享模式

  1. Linux

通过mount -t cifs //192.168.1.105/User /home/kylin/temp -o username=***,password=*,vers=2.0命令挂载目录。

其中192.168.1.105/User为win主机IP及共享目录,/home/kylin/temp为挂载目标目录。username后为win主机用户名,password为对应密码。

  1. 内核配置
CONFIG_CIFS=y CONFIG_CIFS_STATS=y CONFIG_CIFS_STATS2=y # CONFIG_CIFS_WEAK_PW_HASH is not set # CONFIG_CIFS_UPCALL is not set CONFIG_CIFS_XATTR=y CONFIG_CIFS_POSIX=y CONFIG_CIFS_ACL=y CONFIG_CIFS_DEBUG=y # CONFIG_CIFS_DEBUG2 is not set # CONFIG_CIFS_DFS_UPCALL is not set CONFIG_CIFS_SMB2=y CONFIG_CIFS_SMB311=y CONFIG_CIFS_FSCACHE=y CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y CONFIG_NFS_V2=y CONFIG_NFS_V3=y CONFIG_NFS_V3_ACL=y CONFIG_NFS_V4=y CONFIG_NFS_SWAP=y # CONFIG_NFS_V4_1 is not set CONFIG_NFS_FSCACHE=y # CONFIG_NFS_USE_LEGACY_DNS is not set CONFIG_NFS_USE_KERNEL_DNS=y # CONFIG_NFSD is not set
编辑
2025-03-03
记录知识
0

外网源能够让客户使用apt或yum命令一键安装我们制作的软件包,不需要手动解决繁琐的依赖问题。本文将介绍如何简单快速的搭建一个apt外网源。

一、准备外网源环境

1.1 搭建外网访问网页服务

因为需要通过外网访问,所以我们需要一个能联通到外网的服务器。目前市面上比较常见的有腾讯云、阿里云等,我们这里使用公司购买的阿里云服务器(公网ip为47.92.75.45)。

通过ssh登录上去之后,发现我们之前的同事已经通过apache服务搭建了一个后端代理服务器,所以我们本文就不多介绍代理服务器如何搭建,可以自行百度tomcat(或其他后端软件)服务器搭建教程。

这时我们通过在网页输入外网ip,就可以看到如下的网页

image.png

这时我们是通过ip去访问的网页,通过域名访问还需要我们去购买域名并绑定ip,这个步骤就不多做解释。公司已经购买了域名,所以我们也可以通过域名访问这个网页

image.png

1.2 创建软件源仓库文件夹

随后我们进入服务器默认的一个文件夹可以看到

image.png

因此可以在网页上看到对应的文件信息

image.png

所以我们需要先在外网服务器上创建一个文件夹来存放我们的软件镜像仓库

image.png

创建之后网页上也会出现对应的文件夹(由于后端软件不同,可能部分软件需要重启一下服务才能看到所做的改动)

image.png

此时,外网源服务器上的工作就告一段落,我们在外网源服务器上面创建了一个用于外网用户访问的路径,后面将会把软件源镜像放入这个路径中。

二、准备内网环境

2.1 制作要上传的软件包镜像

我们可以通过apt-mirror工具制作我们需要的软件源镜像。首先下载apt-mirror软件

image.png

然后配置/etc/apt/mirror.list文件

image.png

随后使用apt-mirror命令即可拉去镜像到默认文件夹中

image.png

我们可以在默认路径中看到已经下载好的软件镜像文件

image.png

到此,我们就制作好了需要的软件源镜像

2.1 定时同步软件镜像源

由于我们不停地在更新软件包,所以可以通过定时任务去同步软件源上的更新到镜像中,这里我们可以使用crontab工具,下面简单介绍crontab软件的用法

编辑/etc/crontab 将你想要执行的脚本按照提示给的格式匹配即可

image.png

这里我们添加了最后一行,意思是在每天的凌晨1点,执行apt-mirror命令,更新软件源镜像

三、把软件源从本地同步到外网仓库

3.1 同步

我们使用rsync命令同步软件源镜像,将我们的镜像文件夹同步到外网服务器上我们创建的文件夹中

image.png

这时,我们刷新网页就可以看到两个软件源的文件夹

image.png

此时,我们只需要将 deb [trusted=yes] http://download.cs2c.com.cn/kylin/rk3399/3399-base-components/kylin-desktop/ 10.1 main 加入到/etc/apt/sources.list,update后即可下载软件源中的软件包。

注意必须要加入[trusted=yes]选项,如果不加则会出现gpg密钥验证错误的问题。这是由于我们的服务器密钥没有被添加到我们本地需要安装软件包机器的密钥列表中,长沙外网源是通过kylin-keyring软件包将密钥添加到系统当中的,我们目前通过添加信任即可。

更新:可以通过 gpg -o public-file.key --export keyId 命令将外网源服务器的gpg密钥导出到public-file.key文件,然后将这个文件拷贝到你要装软件包的机器上 /etc/apt/trusted.gpg.d/ 路径下即可,这样就不需要添加 [trusted=yes] 选项了。

keyId是通过 gpg --gen-key 命令生成,已经生成的可以通过 gpg --list-keys 命令查看当前环境的gpg key。

同时还需要在外网源服务器生成InRelease文件去验证gpg密钥,命令是 gpg --clearsign --no-tty --batch --personal-digest-preferences SHA256 -o InRelease Release 密码是gpg --gen-key生成的密码。

3.2 实时同步

我们也可以把rsync加入到crontab中,每天或每周定时同步外网的软件源镜像。这里由于需要同时连接内网和外网不安全,所以就不使用定时同步。

编辑
2025-03-03
记录知识
0

本文档主要用于配合sysapp包实现V10嵌入式多模终端模块定制功能,主要说明如何将需要安装的deb包下载到一个特定系统,然后制作成该系统的本地apt源,最终实现在无需联网的情况下可自由安装、卸载本地源中的包,并自动解决依赖关系。

指定本地仓库地址

新建"/etc/apt/sources.list.d/sysapp-local.list" APT源配置文件,指定"/opt/sysapp/repo"为本地仓库地址 内容如下(注意最内层目录需要空格分开):

deb [trusted=yes] file:/opt/sysapp repo/

将需要安装的deb包和依赖下载到本地目录

可以先在一个带有外网源的系统上一次下载完所有包,然后再拷贝到本地

模拟安装所需包(获取实际需要下载的包)

apt-get -s install xdotool x11-utils evtest

image.png

根据2.1的输出结果下载所需包到本地仓库

apt-get download evtest libxdo3 x11-utils xdotool

image.png

扫描本地仓库,生成仓库索引信息

dpkg-scanpackages repo /dev/null | gzip > repo/Packages.gz

image.png

更新系统仓库缓存

apt-get update

指定本地仓库优先级

新建"/etc/apt/preferences.d/sysapp-local.pref" APT源优先级配置文件,指定本地仓库地址优先级为2000 内容如下:

Package: * Pin: origin "" Pin-Priority: 2000

验证

查看特定deb的缓存版本

如下可以看到qtcreator共3个版本,其中最新的版本为4.11.0-3kylin5, 优先级为500, 本地源版本为4.11.0-3-kylin4, 优先级为2000

image.png

安装

可以看到,即使本地源中的版本不是最新的但由于优先级更高还是安装了本地源中的版本

image.png

补充说明

链接

https://www.jianshu.com/p/3abea53e4d66
编辑
2025-03-03
记录知识
0

RK平台有一个2D加速器,名字叫做RGA,其主要用来做图片处理的加速,在适配RK3588平台的过程中,有发现一些主板上播放适配卡顿或者不播放。从而定位到是RGA的MMU无法访问4G以上的内存地址空间导致。经排查,通过在ffmpeg中申请4G以内的dma buffer来绕过RGA的硬件缺陷,本文章分享此问题的解题过程

一:问题现象

在使用ffplay播放视频的时候,会出现如下问题

[ 719.046159] rga2 fdb80000.rga: swiotlb buffer is full (sz: 278528 bytes), total 32768 (slots), used 591 (slots) [ 719.047045] rga_dma_buf: Failed to map src attachment [ 719.047491] rga_mm: rga_mm_map_dma_buffer core[4] map dma buffer error! [ 719.048090] rga_mm: rga_mm_map_buffer map dma_buf error! [ 719.048556] rga_mm: job buffer map failed! [ 719.048914] rga_mm: src channel map job buffer failed! [ 719.048915] rga_job: rga_job_run: failed to map buffer [ 719.049996] rga_job: some error on rga_job_run before hw start, rga_job_next(343) [ 719.050652] rga_job: some error on job, rga_job_commit(668) [ 719.051140] rga_job: failed to commit job! [ 719.051509] rga: rga_request_commit failed

将内核升级后,得到如下错误

Nov 24 14:14:35 Kylin kernel: [85438.014740] rga_mm: RGA_MMU unsupported Memory larger than 4G! Nov 24 14:14:35 Kylin kernel: [85438.014772] rga_mm: scheduler core[4] unsupported mm_flag[0x0]! Nov 24 14:14:35 Kylin kernel: [85438.014848] rga_mm: rga_mm_map_buffer iommu_map virtual address error! Nov 24 14:14:35 Kylin kernel: [85438.014859] rga_mm: job buffer map failed! Nov 24 14:14:35 Kylin kernel: [85438.014869] rga_mm: dst channel map job buffer failed! Nov 24 14:14:35 Kylin kernel: [85438.014878] rga_mm: failed to map buffer Nov 24 14:14:35 Kylin kernel: [85438.014894] rga_job: rga_job_commit: failed to map job info Nov 24 14:14:35 Kylin kernel: [85438.014969] rga_job: request[1] task[0] job_commit failed. Nov 24 14:14:35 Kylin kernel: [85438.014981] rga_job: rga request commit failed! Nov 24 14:14:35 Kylin kernel: [85438.014992] rga: request[1] submit failed!

从而导致3588上播放视频性能低下

二:分析

2.1 根据日志简单解析

从日志 Failed to map src attachment 可以看定位代码地址

drivers/video/rockchip/rga3/rga_dma_buf.c
sgt = dma_buf_map_attachment(attach, dir); if (IS_ERR(sgt)) { pr_err("Failed to map src attachment\n"); ret = -EINVAL; goto err_get_sgt; }

并且通过日志 RGA_MMU unsupported Memory larger than 4G 可以发现RGA MMU确实存在此硬件问题

2.2 跟踪ffplay代码

ffplay为ffmpeg的播放测试程序,视频经过ffplay播放,会通过libavcodec做真正的硬解码动作,其代码位置为 libavcodec/rkmppdec.c

经过定位

if (avctx->pix_fmt != AV_PIX_FMT_DRM_PRIME) { ret = rkmpp_convert_frame(avctx, frame, mppframe, buffer); goto out; }

这里判断了pix fmt类型,如果不是DRM_PRIME类型,则主动通过mpp进行帧的转换

avctx->pix_fmt = ff_get_format(avctx, avctx->codec->pix_fmts);

帧格式通过ffmpeg的api获取

这里默认会拿到YCbCr_420_SP的视频格式,但是AV_PIX_FMT_DRM_PRIME默认格式为RK_FORMAT_YCbCr_420_P。所以视频过来的每一帧都需要进行 420sp-→420p的格式转换

这个转换通过两种方式,如果rga不支持,则通过软件转换,如下

for (i = 0; i < frame->height / 2; i++) { for (j = 0; j < frame->width; j++) { dst_u[j] = src[2 * j + 0]; dst_v[j] = src[2 * j + 1]; } dst_u += u_pitch; dst_v += v_pitch; src += hstride; }

如果rga支持,则通过rga的api 加速转换

c_RkRgaBlit(&src_info, &dst_info, NULL)

2.3 基本推断

从上面的信息可以判断,rgaBlit的失败,会导致内核出错,并且每一帧的视频输出格式都通过cpu来计算,从而导致播放卡顿

根据c_RkRgaBlit 的两个参数,结合/usr/include/rga/drmrga.h 的struct rga_info 定义,可以看到 void *virAddr 是rga内部使用的内存地址

根据分析rga源码,从而得到如下为rga内部使用的内存地址

src_info.fd = mpp_buffer_get_fd(buffer); dst_info.virAddr = dst_y;

2.4 跟踪代码

跟踪mpp的代码可以知道,mpp的buffer通过如下申请

ret = mpp_buffer_group_get_internal(&decoder->frame_group, MPP_BUFFER_TYPE_DRM);

获取mpp源码 mpp_1.5.0-1.tar.gz 分析代码,可以发现

osal/linux/os_allocator.cMPP_RET os_allocator_get(os_allocator *api, MppBufferType type) 作为所有的mpp的buffer的申请器

其支持的申请方式如下:

MPP_BUFFER_TYPE_NORMAL malloc申请 MPP_BUFFER_TYPE_ION android的ion申请 MPP_BUFFER_TYPE_DRM 通过drm设备"/dev/dri/card0"申请

这里可以发现,当前版本的mpp内存申请方式,都没有对内存的实际地址进行判断,也就是有可能在rga的mmu访问的时候,实际内存可能大于4G内存

而在内核内,有申请dma32的堆的驱动drivers/dma-buf/heaps/

打开 DMABUF_HEAPS_SYSTEM 重编译内核,替换内核后重启,可以看到dma的申请设备

/dev/dma_heap/system /dev/dma_heap/system-uncached /dev/dma_heap/system-dma32 /dev/dma_heap/system-uncached-dma32

对应的,要使用dma32,可以借鉴rk的使用例子。代码在linux-rga源码

samples/im2d_slt/sources/dma_alloc.cpp

通过合入patch的方式,可以为mpp增加一个dma heap的内存申请方式。可以参考commit 如下

https://gitlab2.kylin.com/shanghai-team/mpp/-/commit/3ed4d85d6ba174575e7bd0fe0cc6b29f4d54c9ee

2.5 运行测试

将支持dma heap申请的mpp编译后,安装在系统上,进入调试状态,

export mpp_rt_debug=1 && ffplay /data/bbb_sunflower_2160p_60fps_normal.mp4

在另一个窗口监听syslog 如下

tail -f /var/log/syslog | grep mpp_rt

通过日志可以发现,在播放视频时,mpp这边的buffer已经正常的通过heap的方式申请

Nov 24 16:52:38 Kylin mpp[999038]: mpp_rt: use dma heap allocator

通过sysfs也可以看到dma buffer已经申请成功

cat /sys/kernel/debug/dma_buf/bufinfo 04177920 00000002 00080007 00000002 system-uncached-dma32 03377282 1002674-ffplay Attached Devices: fdc38100.rkvdec-core Total 1 devices attached

但是MMU 4G的问题还是存在

2.6 rga的dest buffer

至此mpp buffer这边已经正常的通过dma去申请了。而rga这边的buffer还是有问题的,继续翻阅ffmpeg的代码,可以找到

rkmppdec.c if (avctx->pix_fmt != AV_PIX_FMT_DRM_PRIME) { ret = ff_get_buffer(avctx, frame, 0); if (ret < 0) goto out; }

可以发现,rga的dest buffer通过ffmpeg的标准接口申请,跟踪代码可知,内存的申请通过av_malloc

故,为了解决rga这边的内存问题,需要也通过dma去申请

申请如下:

ret = ioctl(buf->fd, DMA_HEAP_IOCTL_ALLOC, buf->alloc_info); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to alloc rga dst dma buffer\n"); goto out; } if (fcntl(buf->alloc_info->fd, F_GETFL) & O_RDWR) prot |= PROT_WRITE; buf->buf_ptr = mmap(NULL, MAX_FRAMESIZE, prot, MAP_SHARED, buf->alloc_info->fd, 0); if (buf->buf_ptr == MAP_FAILED) { av_log(avctx, AV_LOG_ERROR, "Failed to mmap dma buffer.size=%d: %s\n", MAX_FRAMESIZE, strerror(errno)); goto out; }

由此,可以得到一个buf→buf_ptr 的 MAX_FRAMESIZE (819281924) 的内存地址

然后将此地址提供给每个帧buffer上,如下

frame->data[0] = decoder->dma_buf->buf_ptr; frame->data[1] = frame->data[0] + frame->linesize[0]*mpp_frame_get_ver_stride(mppframe); frame->data[2] = frame->data[1] + frame->linesize[1]*mpp_frame_get_ver_stride(mppframe)/2;

此计算是为了满足如下公式

u_pitch == y_pitch / 2 v_pitch == y_pitch / 2 dst_u == dst_y + y_pitch * dst_height dst_v == dst_u + u_pitch * dst_height / 2

frame->data[0]dst_info.virAddr = dst_y;

由此,rga这边的buffer也是dma申请的。

root@kylin:/sys/kernel/debug/dma_buf# cat bufinfo | grep 268435456 -A 3 268435456 00000002 00080007 00000002 system-uncached-dma32 03444815 1029285-ffplay Attached Devices: Total 0 devices attached

这里可以看到 268435456 = MAX_FRAMESIZE 已经正常申请

patch地址为

https://gitlab2.kylin.com/shanghai-team/FFmpeg/-/commit/9fbfadb6f185e73b2140b5ff063ef2445897b301

2.7 权限

ffplay因为要通过dma去申请,这里需要满足权限

需要复制给dma heap 一个777 的最大权限,确保应用正常使用堆

chmod -R 777 /dev/dma_heap/

三:自测结果

通过播放视频,查看rga的使用率,确定rga正常使用,视频播放不卡顿。如下

watch -n 1 cat /sys/kernel/debug/rkrga/load Every 1.0s: cat /sys/kernel/debug/rkrga/load kylin: Thu Nov 24 17:20:31 2022 num of scheduler = 3 ================= load ================== scheduler[0]: rga3_core0 load = 0% ----------------------------------- scheduler[1]: rga3_core1 load = 0% ----------------------------------- scheduler[2]: rga2 load = 22% ----------------------------------- process 1: pid = 1033010, name: ffplay /data/bbb_sunflower_2160p_60fps_normal.mp4

这里可以确定,当前视频通过ffplay播放,走的rga2加速。4K的视频源,rga使用率在20-30%。