说实话,我第一次接触DM365这个芯片的时候,心里是有点打鼓的,毕竟这玩意儿是TI家的老将,主打视频处理,但真要跑WiFi音视频传输,总觉得有点“小马拉大车”的意思,不过后来仔细想了想,正是这种“老当益壮”的芯片,配上Go语言这种“新时代利器”,反而能擦出点有意思的火花。
为什么是DM365 + Go + WiFi?
先说说DM365,这家伙内置了ARM926EJ-S核心,主频最高能到300MHz,硬件视频编码解码是它的看家本领,H.264、MPEG-4这些格式,它都能硬解,这就意味着,音视频数据的原始处理,可以交给硬件,CPU只负责调度和传输,用Go语言来写调度层,简直是天造地设的一对。
Go语言的goroutine和channel,在处理并发音视频流的时候,比C语言的pthread要舒服太多,你想啊,一路视频流、一路音频流、再加上WiFi的控制流,三个goroutine各管一摊,channel一对接,代码干净利落,不像以前用C,动不动就死锁,调试起来头大。
WiFi方面,我用的是ESP8266模块,通过UART和DM365通信,当然你也可以用更高级的模块,但ESP8266便宜啊,而且Go的串口库go.bug.st/serial用起来顺手得很。
硬件连线:其实没那么玄乎
别被那些硬件原理图吓到,DM365和ESP8266的连线就四根线:VCC、GND、TX、RX,电压注意一下,DM365是3.3V逻辑,ESP8266也是3.3V,直接连就行。
| DM365引脚 | ESP8266引脚 |
| UART0_TX | RX |
| UART0_RX | TX |
| GND | GND |
| 3V | VCC |
我当时第一次接的时候,还特意用杜邦线多绕了两圈,结果发现其实不用,直接插紧就行,对了,别忘了给ESP8266刷AT固件,不然没法用TCP/IP协议栈。
Go语言控制WiFi模块
先写个简单的串口读写函数,别搞太复杂,能用就行。
package main
import (
"fmt"
"go.bug.st/serial"
"time"
)
func main() {
mode := &serial.Mode{
BaudRate: 115200,
}
port, err := serial.Open("/dev/ttyS0", mode)
if err != nil {
fmt.Println("串口打开失败:", err)
return
}
defer port.Close()
// 发送AT指令连接WiFi
port.Write([]byte("AT+CWJAP=\"你的WiFi名\",\"密码\"\r\n"))
time.Sleep(3 * time.Second)
// 建立TCP连接
port.Write([]byte("AT+CIPSTART=\"TCP\",\"192.168.1.100\",8080\r\n"))
time.Sleep(2 * time.Second)
}
别笑,就是这么简单,AT指令控制WiFi模块,Go通过串口发指令,ESP8266负责联网,你要做的就是把音视频数据通过TCP发出去。
从DM365采集视频数据
DM365的V4L2驱动是标准的,用Go调V4L2,得用syscall包,不过别怕,封装一下就好。
我写了个videoCapture.go,专门管这个。
func startCapture() {
fd, _ := syscall.Open("/dev/video0", syscall.O_RDWR, 0)
// 设置格式、请求缓冲区、mmap...
for {
// 读取一帧
buf := make([]byte, frameSize)
// 这一帧数据,通过channel发给传输模块
videoChan <- buf
}
}
注意一点:DM365硬件编码出来的H.264数据,是NAL单元流,你得自己分包,我习惯用0x00000001作为起始码,然后按帧切割。
音频采集:别忽略小细节
音视频传输,光有视频不行,DM365的音频是通过I2S接口接的codec芯片,比如TLV320AIC31,Go语言没有直接的I2S库,但可以通过ALSA的混音设备来读。
用/dev/dsp或者/dev/snd/pcmC0D0c都行,不过要注意,音频采样率要跟视频同步,我一般用8kHz、16位、单声道,这样数据量小,WiFi传输压力也小。
func audioCapture() {
// 打开音频设备
adc, _ := os.OpenFile("/dev/snd/pcmC0D0c", os.O_RDONLY, 0)
buf := make([]byte, 320) // 8kHz, 16位, 20ms 数据
for {
adc.Read(buf)
audioChan <- buf
}
}
这里有个坑:音频设备打开后,如果没读到数据,会一直阻塞,所以最好用非阻塞模式,或者加个超时。
音视频同步:最难的部分
说实话,音视频同步这玩意儿,我折腾了三天,网上说的PTS(显示时间戳)和DTS(解码时间戳),在DM365上都有硬件支持,但你要会用。
我的办法很土:用时间戳对齐,每个视频帧和音频包,都打上当前的时间戳(微秒级),接收端收到后,根据时间戳来播放。
type AVFrame struct {
Timestamp int64
Data []byte
FrameType string // "video" 或 "audio"
}
然后在发送goroutine里,把视频帧和音频包都包装成AVFrame,通过同一个channel发给WiFi传输模块,接收端拿到后,按时间戳排序,再分别喂给解码器。
WiFi传输的坑与填坑
WiFi传输音视频,最大问题是丢包和延迟,DM365这边,我用的是TCP协议,虽然可靠,但重传会导致延迟,后来我改用UDP + 自定义ACK。
具体做法是:每个包加上序号,接收端收到后发ACK,发送端如果超时没收到ACK,就只重传关键帧(I帧),非关键帧(P帧)丢了就丢了,这样延迟从500ms降到了150ms左右。
Go实现起来也很直接:
type Packet struct {
SeqNum uint32
Data []byte
}
func sendPacket(conn net.Conn, pkt Packet) {
// 序列化
data, _ := json.Marshal(pkt)
// 发送
conn.Write(data)
// 等待ACK
// 超时则重传
}
不过注意,用json序列化有点浪费带宽,实际项目里,我用了protobuf,压缩比高,但protobuf需要编译,有点麻烦,如果你只是想快速验证,json也行。
接收端:PC端用VLC播放
接收端其实不用太复杂,我用Go写了个简单的中转程序,把收到的音视频数据通过本地UDP广播出去,然后开VLC播放。
VLC支持H.264和AAC的RTP流,命令如下:
vlc udp://@:5000
你也可以用ffmpeg来解码:
ffmpeg -i udp://:5000 -f sdl "视频窗口"
这样调试起来方便,不用专门写播放器。
Go程序在DM365上交叉编译
DM365是ARM架构,得交叉编译,我的环境是Ubuntu,装了arm-linux-gnueabi-gcc,Go交叉编译很简单:
GOOS=linux GOARCH=arm GOARM=5 go build -o av_transfer
注意GOARM=5,这是ARMv5指令集,兼容DM365的ARM926EJ-S核心,别设错了,不然跑不了。
编译完,把生成的可执行文件scp到DM365上,记得给执行权限,然后运行:
chmod +x av_transfer ./av_transfer
如果一切顺利,PC端的VLC就能看到画面、听到声音了。
性能调优:把DM365榨干
DM365的CPU只有300MHz,跑Go程序,资源得省着用,我做了几个优化:
- 减少内存分配:视频帧用
sync.Pool复用,避免GC频繁触发。 - 使用
io.Copy:数据搬运尽量用标准库,减少中间拷贝。 - 设置GOMAXPROCS=2:DM365双核,设成2就行,多了反而上下文切换浪费。
还有个关键点:DM365的DMA控制器可以接管内存搬运,Go没法直接操作DMA,但可以通过CGO调用用户空间的DMA驱动,不过CGO有性能开销,非必要别用。
实际效果:够用就行
整体做下来,720p 30fps的视频流,WiFi传输延迟在200ms以内,音频基本同步,如果你降低分辨率,比如640x480,延迟能到100ms,对于安防监控、无线图传这些场景,完全够用了。
你要是想搞4K视频,DM365就别想了,换DM8168吧。
一点题外话
其实用Go做嵌入式音视频传输,最大的好处是开发效率,同样的功能,用C写,至少多花一倍时间,而且Go的部署也简单,一个二进制文件丢上去就跑了,不用操心依赖库。
有人可能会说,Go的运行时内存占用大,但DM365有128MB DDR2,跑个轻量级的Go程序,绰绰有余,剩下的内存,给视频缓冲用。
我后来还加了运动检测功能,DM365的硬件协处理器能直接输出运动矢量,从寄存器读出来,通过Go处理一下,就能实现,不过那是另一个故事了。

WiFi音视频传输,说到底就是采集、编码、传输、解码、显示这几个环节,DM365负责采集编码,Go负责调度传输,WiFi负责桥接,各司其职,不乱折腾,事情就成了。
到现在,这套东西我还在用,偶尔改改参数,适配不同场景,有时候想想,芯片虽然老了,但配上合适的语言和方案,一样能干活,就像那句话说的:没有过时的硬件,只有过时的思路。
本文来自作者[kyadmin]投稿,不代表be365立场,如若转载,请注明出处:http://www.uss1.cn/nba/996.html
评论列表(4条)
我是be365的签约作者“kyadmin”!
希望本篇文章《用Go语言搞定DM365 WiFi音视频传输,从零开始的硬核实践》能对你有所帮助!
本站[be365]内容主要涵盖:be365,be365网站,be365网址,ball365体育,Be365排名
本文概览:说实话,我第一次接触DM365这个芯片的时候,心里是有点打鼓的,毕竟这玩意儿是TI家的老将,主打视频处理,但真要跑WiFi音视频传输,总...