用Golang搞定YCC365摇头机扫码连接视频,这事儿其实没那么玄乎
- 科技
- 2026-07-25 14:55:12
- 52
说实话,我第一次拿到YCC365摇头机的时候,心里是有点懵的,说明书上写着“扫码连接视频”,但真正用Go语言去实现这个功能时,你会发现——坑还挺多,不过别担心,今天咱就把这件事拆开揉碎了聊,保证你看完就能动手干。
先搞清楚YCC365摇头机到底怎么通信的
YCC365这款摄像头,本质上是一个WiFi网络摄像头,它内部跑的是RTSP流媒体协议,外加一套自己的配网逻辑,所谓“扫码连接”,其实就是手机通过扫描摄像头底部的二维码,获取设备的序列号和密钥,然后建立连接。
这个二维码里藏的信息大概是这样的:
YCC365:SN:ABCD123456:KEY:abcdef1234567890
别笑,基本上就是这么个格式。
用Go语言扫码,比你想的简单
第一步:扫码库的选择
Go生态里有个好用的库叫github.com/makiuchi-d/gozxing,支持二维码解码,安装它:
go get github.com/makiuchi-d/gozxing
写个简单的扫码函数:
func decodeQRCode(imgPath string) (string, error) {
file, _ := os.Open(imgPath)
defer file.Close()
img, _, _ := image.Decode(file)
source := gozxing.NewBitmapSourceFromImage(img)
reader := gozxing.NewQRCodeReader()
result, _ := reader.Decode(source, nil)
return result.GetText(), nil
}
第二步:解析二维码信息
拿到字符串后,用正则或者字符串分割提取SN和KEY:
func parseYCC365QR(raw string) (sn string, key string, err error) {
parts := strings.Split(raw, ":")
if len(parts) != 5 || parts[0] != "YCC365" {
return "", "", fmt.Errorf("格式不对啊老铁")
}
return parts[2], parts[4], nil
}
这里有个小细节:有些批次的YCC365二维码格式可能有微小差异,比如多了一位校验码,建议你实际拿几个摄像头扫扫看,摸清规律。
连接视频流才是重头戏
获取到SN和KEY之后,下一步是建立RTSP连接,YCC365的RTSP地址一般长这样:
rtsp://admin:密钥@IP地址:554/stream1
这里的密钥就是刚才从二维码里拿到的KEY,但问题来了:你首先要拿到摄像头的IP地址。
局域网的IP发现——靠UPnP
YCC365支持UPnP自动发现,Go语言里可以用gopnp库:
go get github.com/huin/goupnp
写个搜索函数:
func discoverCamera(sn string) (string, error) {
devices, _ := goupnp.DiscoverDevices("urn:schemas-upnp-org:device:MediaServer:1")
for _, dev := range devices {
if strings.Contains(dev.Device.FriendlyName, sn) {
return dev.Device.URLBase.Host, nil
}
}
return "", fmt.Errorf("没找到摄像头,别急再试一次")
}
实际测试发现:并不是所有YCC365都完美支持UPnP,有时候需要手动ping一下局域网IP段,这时候你可以写个并发扫描:
func fastScan(subnet string) []string {
var found []string
var wg sync.WaitGroup
for i := 1; i <= 254; i++ {
wg.Add(1)
go func(ip string) {
defer wg.Done()
conn, err := net.DialTimeout("tcp", ip+":554", 500*time.Millisecond)
if err == nil {
conn.Close()
found = append(found, ip)
}
}(fmt.Sprintf("%s.%d", subnet, i))
}
wg.Wait()
return found
}
温馨提示:别扫得太狠,小心路由器把你当攻击源。
真正的视频拉流——RTSP + Golang
拿到IP地址和密钥后,用Go拉RTSP流有很多选择,我个人比较偏爱github.com/pion/rtsp,轻量干净。
示例大概是这样:
func playRTSP(ip, key string) {
url := fmt.Sprintf("rtsp://admin:%s@%s:554/stream1", key, ip)
session, _ := rtsp.Dial(url)
defer session.Close()
// 循环读取视频帧
for {
frame, _ := session.ReadFrame()
// 这里可以转成H264或者直接显示
fmt.Println("收到一帧,长度:", len(frame))
}
}
但这里有个实际坑:YCC365的RTSP实现不是100%标准,某些固件版本握手时会要求额外的DESCRIBE参数,解决办法是抓包看一次官方App的请求格式,然后用Go模仿。
| 固件版本 | 行为差异 | 解决办法 |
|---|---|---|
| v2.1.x | 标准RTSP | 无需改 |
| v2.3.x | 要求Authentication Digest | 加Authorization头 |
| v2.5.x | 偶尔断流 | 心跳包保活 |
多嘴一句:v2.5.x的断流问题很烦人,我后来加了个自动重连的goroutine才算解决。
声音传输——差点忘了这茬
YCC365的音频用的是G.711编码,Go里没有现成的解码库,但你可以用CGo调用ffmpeg,或者用纯Go实现的github.com/igadmg/GoG711
func decodeAudio(g711Data []byte) []byte {
decoder := g711.NewDecoder()
pcm, _ := decoder.Decode(g711Data)
return pcm
}
说实话,这步我当时折腾了整整两天,因为Go的字节序和G.711的格式对不上,后来发现一字节对齐问题,加了个binary.LittleEndian转换就通了。
运行起来的样子
你的Go程序流程应该是这样的:
- 扫码 → 获取SN和KEY
- 搜索网络 → 找到摄像头IP
- 建立RTSP会话 → 拉取视频流
- 解码音视频 → 播放或保存
其实没那么复杂,就是步骤多,坑也多。
现在你手里应该有一个能工作的雏形了,别怕改代码,YCC365这东西固件版本多,一次写完美不太现实,先跑起来再说,慢慢调——搞技术的不都这样嘛,边试边改,还挺有意思的。
