您尚未登录。

楼主 # 2022-09-11 23:24:26

unturned3
会员
注册时间: 2020-07-01
已发帖子: 236
积分: 274

V3s 主线 Linux 5.19 实现 1920x1080 @ 30fps h.264 硬编码

折腾了很久,终于实现了这个功能!!!

自从 aodzip 大佬分享了他的 cedar 仓库后,我就一直想试试 V3s 的 h264 硬编码,可惜 OpenMax 这个中间层就是个渣渣,不仅莫名其妙的占用大量内存,在 ffmpeg 中也无法调整各种编码参数。V3s 上实测,编码 dvp 摄像头采集的 640x480 的视频就已经是极限了…… 显然这和 datasheet 中提及的 1080p @ 30fps 还差的有点远

于是我直接放弃 openmax、ffmpeg,参考了网上 V4L2 和全志 Cedar API 的例程,开始手写程序。全志 video_encoder_API_guide.pdf 里的描述可以说是“惜字如金”,而且网上各个例程使用这些函数的方法也有差异,比如有些每帧调用一次 AllocInputBuffer, 有些没有使用 ReturnOneAllocInputBuffer 等等,导致这些函数的具体作用比较难理解

这些例程大都是读取某个 yuv 文件,将每帧的数据 memcpy 到 CedarVE 申请的缓冲区内,然后再编码。对于 640x480 之类的低分辨率还没太大问题,但是编码 1920x1080 的时候帧率就直接掉到10以下并且CPU使用率占满,因为程序花费了大量的时间来拷贝数据,非常低效。

要实现零拷贝的话,一般是采取 V4L2_MEMORY_DMABUF(Linux DMA-BUF 机制)或者 V4L2_MEMORY_USERPTR(V4L2 直接将数据写入 userspace 的某个 buffer)这两种方法。可惜,libcedarc 的 API 不支持前者,而 Linux 的 sun6i-video 驱动又恰巧不支持后者。现在剩下的只有 V4L2_MEMORY_MMAP。不过如果我们希望将自己申请的 buffer 交给 libcedarc 使用的话,我们需要知道 buffer 的物理地址;可是 V4L2 API 中并没有能让我们获取 MMAP buffer 物理地址的功能……

由于本人能力不足,实在看不懂 cedar 驱动的架构,于是只好另辟蹊径,放弃为 cedar 添加 dma-buf 支持的想法。在深入研究 V4L2 MMAP 机制后,发现其实 MMAP 过程中返回 buffer 中一个 private struct 里的 dma_addr 就是 MMAP 缓冲区的 dma 地址。

不过 dma_addr 怎么转换成物理地址呢?无数次实验后,发现 kernel 自带的 virt_to_phys 函数貌似可以完成这个功能…… 这个函数返回的 phys_addr,经过 busybox devmem 读写数据验证,的确是相应 V4L2 MMAP buffer 的物理地址…… 这肯定不是 virt_to_phys 的正确用法,不过能用就先用着吧…… (路过的大神请手下留情哈哈)

知道如何获取 phys_addr 后,剩下的就是解决如何将这个信息传回给 userspace 的应用。仔细阅读 sun6i-video 中 V4L2 相关代码后,发现有一个叫做 vidioc_default 的无用 ioctl,简直完美!写了个简单的 ioctl handler 便解决了这个问题。现在 userspace 的应用只需将 V4L2 MMAP 返回的 buffer 传递给这个 ioctl,就能获取该 buffer 的物理地址。

最后一个问题:cedar 在 Linux 5.5 及以上的版本就无法编译了,因为 dma-buf 中某个结构体无法对齐。恼人的是,5.10 后又添加了许多对于全志 SoC 的驱动改进,实在是想用。于是我又花了很多时间仔细阅读 Linux 5.4、5.5 附近的 commit 记录,发现 Linux 在 5.5 以后移除了 Android ION 这个内存管理器的相关代码,并且顺带移除了 dma-buf 一个结构体中的元素。而老旧的 cedar 恰好又需要这个 ION 机制…… 我只好写了个 patch 将这个删掉的元素重新添加进 dma-buf 的结构体(顺带修改了一些头文件、syscall参数错误,等等),于是 cedar 在最新主线 Linux 5.19 上就能运行了,舒服!

代码:https://github.com/Unturned3/h264enc_demo

配套的 buildroot “包”:https://github.com/Unturned3/v3s3

顺便介绍一下:v3s3 是一个 buildroot external tree (“外部树”),并不是一个独立的开发环境,需要和一个 buildroot 包配合使用。它的优点是当前项目所有的文件和 buildroot 内部文件是分开的,非常干净,便于管理;日后更换、升级 buildroot 版本简直不要太爽。v3s3 仓库除了硬编码 demo 外,还有许多其他好东西,例如一个极优化的 Linux 内核 config,0.3 秒从 Starting kernel 到 /sbin/init,硬件AES256加速驱动,等等。具体详见 repo README。(如果对你有帮助的话,不妨给个star,逃

编译方法
# 切换到某个合适的目录
cd /some/working/directory

# 下载 buildroot external tree
git clone https://github.com/Unturned3/v3s3

# 下载并解压任意一个 buildroot 版本(最近的版本应该都能用;我测试的是2022.05.1)
wget buildroot.org/downloads/buildroot-x.y.z.tar.gz
tar -xf buildroot-x.y.z.tar.gz

# 切换至 buildroot 目录,并初始化配置
cd buildroot-x.y.z
make BR2_EXTERNAL=../v3s3 licheepi_zero_defconfig

# 打开 buildroot 配置目录
make nconfig

# 勾选 h.264 硬编码 demo 选项
External options --->
	[*] CedarVE H.264 encoding demo

# 下载所需的软件包
make source

# 编译
make all

# 烧录 SD 卡 (将 /dev/sdX 替换成合适的路径)
sudo dd if=output/images/sdcard.img of=/dev/sdX bs=4M
使用方法

本人用的硬件是荔枝派Zero,OV5640 DVP (parallel) 摄像头。荔枝派Zero 第一次上电可能会出现 OV5640 i2c ID 错误的情况,目前暂不知原因,不过重启(软重启,i.e. reboot, 不是插拔电源)一次便可解决。只要 /dev/video0, /dev/media0 存在就没太大问题。media-ctl -p 这个指令也可以用于查看 OV5640 是否注册成功。

用串口、或者 ssh 登录后,/root 目录下会有一个 h264enc_demo 的二进制文件:

./h264enc_demo [width] [height] [FPS] [n_frames]

支持 640x480, 1280x720, 1920x1080。n_frames 为采集的帧数,如果不写的话默认450帧。

所有分辨率均支持 30 FPS;640x480 模式下额外支持 60FPS (这是 OV5640 驱动的限制)

h264enc_demo 会将编码流输出至 /mnt/out.h264,如果录制的 n_frames 较大,可考虑在 /mnt 上挂载一个大 SD 卡分区来存储数据。

copy_video.sh 可通过 scp 指令将 /mnt/out.h264 拷贝至某台远程电脑(需要你自己设置合适的 scp destination)

在装有 ffmpeg 的电脑上,可通过 ffmpeg -framerate 30 -i out.h264 -c copy out.mp4 指令将裸 h264 流转换为 MP4

最近编辑记录 unturned3 (2022-09-11 23:32:58)

离线

楼主 #3 2022-09-15 10:34:58

unturned3
会员
注册时间: 2020-07-01
已发帖子: 236
积分: 274

Re: V3s 主线 Linux 5.19 实现 1920x1080 @ 30fps h.264 硬编码

笔走天下 说:

楼主,
有没有实操视频看下

哪天有空我录一个好点的

荔枝派 zero 的电源好像设计的有点问题,ov5640 获取的图像噪音有点大

最近编辑记录 unturned3 (2022-09-15 10:35:08)

离线

楼主 #4 2022-09-15 10:35:52

unturned3
会员
注册时间: 2020-07-01
已发帖子: 236
积分: 274

Re: V3s 主线 Linux 5.19 实现 1920x1080 @ 30fps h.264 硬编码

cec0d5f1b6ab 说:

请问下f1c100s/f1c200s支持h264硬件编码吗?

f1c 只有 h264 硬解。没有硬件编码器

离线

楼主 #11 2022-09-16 13:05:22

unturned3
会员
注册时间: 2020-07-01
已发帖子: 236
积分: 274

Re: V3s 主线 Linux 5.19 实现 1920x1080 @ 30fps h.264 硬编码

hanzixi_angel 说:

楼主  这个可以播放h264的mp4视频吗  有没有demo可以测试?

我只弄了编码

而且播放好像还需要 DisplayEngine、DRM、LCD显示驱动啥的,我基本没了解过

离线

楼主 #12 2022-09-16 13:08:12

unturned3
会员
注册时间: 2020-07-01
已发帖子: 236
积分: 274

Re: V3s 主线 Linux 5.19 实现 1920x1080 @ 30fps h.264 硬编码

webb_2002 说:
bigbat 说:

楼主的硬解和硬编的资料从哪里来的

在代码里扣出来的。

确实,基本全靠摸索

这个仓库 有一些关于 API 的资料

https://linux-sunxi.org/Video_Engine 有关于 VE 寄存器的资料

最近编辑记录 unturned3 (2022-09-16 13:08:26)

离线

楼主 #13 2022-09-16 13:09:50

unturned3
会员
注册时间: 2020-07-01
已发帖子: 236
积分: 274

Re: V3s 主线 Linux 5.19 实现 1920x1080 @ 30fps h.264 硬编码

goanale 说:

有谁下载烧录成功了f1c200s的固件了吗?我太难了,都没成功

我这个关于 V3s 硬编码的帖子可能对你烧录固件帮助不大……

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn