当前位置:首页 > 科技 > 正文

用Golang搞定YCC365摇头机扫码连接视频,这事儿其实没那么玄乎

  • 科技
  • 2026-07-25 14:55:12
  • 19
摘要: 说实话,我第一次拿到YCC365摇头机的时候,心里是有点懵的,说明书上写着“扫码连接视频”,但真正用Go语言去实现这个功能时,你...

说实话,我第一次拿到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程序流程应该是这样的:

  1. 扫码 → 获取SN和KEY
  2. 搜索网络 → 找到摄像头IP
  3. 建立RTSP会话 → 拉取视频流
  4. 解码音视频 → 播放或保存

其实没那么复杂,就是步骤多,坑也多

现在你手里应该有一个能工作的雏形了,别怕改代码,YCC365这东西固件版本多,一次写完美不太现实,先跑起来再说,慢慢调——搞技术的不都这样嘛,边试边改,还挺有意思的。

用Golang搞定YCC365摇头机扫码连接视频,这事儿其实没那么玄乎