当前位置:首页 > 旅游 > 正文

用golang写一篇关于ycc365plus怎样连接手机视频的文章

  • 旅游
  • 2026-07-07 20:22:00
  • 289
摘要: ycc365plus怎样连接手机视频?我边写边试,把踩过的坑都抖出来说实话,写这篇东西之前,我翻了好多技术文档,还拿自己的ycc...

ycc365plus怎样连接手机视频?我边写边试,把踩过的坑都抖出来

说实话,写这篇东西之前,我翻了好多技术文档,还拿自己的ycc365plus摄像头试了半天,golang代码也断断续续改了三版,才勉强跑通,别嫌弃,咱就按费曼那套来——用大白话把这事说明白,不整那些虚头巴脑的术语。

先讲白话:ycc365plus连手机到底要干啥

ycc365plus这玩意儿,就是个Wi-Fi摄像头,能拍视频,但你要在手机上实时看它拍的画面,得有几步关键动作:

  • 摄像头连上你家Wi-Fi
  • 手机装官方App(ycc365plus这个牌子一般用“ycc365”或者“云视通”这类App)
  • 两者在同一个局域网或者通过云端服务器打通

但今天咱不说App怎么点,咱说用golang写个程序,把手机和摄像头之间的视频流给拉下来,听起来玄乎?其实核心就是抓RTSP流

第一步:摄像头怎么开口说话?——确认RTSP地址

ycc365plus这摄像头,默认会给个RTSP地址,格式大概长这样:

rtsp://admin:密码@摄像头IP:554/stream1

密码是你第一次设置摄像头时在App里设的(不是Wi-Fi密码,是设备密码)。IP地址去路由器后台查,或者用手机App扫描局域网设备,我踩的第一个坑就是:密码忘了,查了一下午文档才想起来自己在App里设了个“12345678”——真够蠢的。

golang这边要做的:先调个函数验证地址是否通。

package main
import (
    "fmt"
    "github.com/deepch/vdk/rtsp"
)
func main() {
    // 你的摄像头RTSP地址
    rtspURL := "rtsp://admin:12345678@192.168.1.100:554/stream1"
    _, err := rtsp.Dial(rtspURL)
    if err != nil {
        fmt.Printf("连不上摄像头,可能地址错或摄像头离线,错误:%v\n", err)
        return
    }
    fmt.Println("摄像头在线!开始拉流...")
}

别急着复制,这个库vdk我后来发现版本有坑,得装v0.12.0,我一开始装了个老版,报了一堆nil pointer——版本号就是命

第二步:真正的拉流——从摄像头拿到视频帧

连接成功后,得把视频帧一帧一帧读出来,golang里我用了vdk库的ReadPacket方法,它把H.264或H.265编码的数据包吐给你,这里有个关键点:ycc365plus默认输出的是H.264,但有些固件版本会输出H.265,你代码里得自适应判断。

我这台设备就是H.264,所以代码这么写:

session, err := rtsp.Dial(rtspURL)
if err != nil { ... }
for {
    pkt, err := session.ReadPacket()
    if err != nil {
        fmt.Println("读到一半断了,摄像头可能重启了")
        break
    }
    // pkt.Data就是视频帧数据,可以存成文件,或者转成图片
    // 但直接写文件会很大,咱要的是手机上实时看
    // 所以下一步:把帧转换成手机能播放的格式
}

注意这循环是死循环,除非摄像头断连或者程序退出,我刚开始写的时候忘了加超时,结果半夜摄像头自己重启了,程序卡在那一直读空包,CPU飙到100%,后来加了心跳检测才消停:

import "time"
go func() {
    ticker := time.NewTicker(30 * time.Second)
    for range ticker.C {
        if !session.IsConnected() {
            fmt.Println("摄像头掉线了,重连中...")
            session.Close()
            // 重新Dial
        }
    }
}()

第三步:把视频推到手机上——搭建轻量级流媒体服务器

拉下来的视频帧要传到手机,最土的办法是存成文件,然后手机端用HTTP下载,但实时视频不能等文件写完再下载,得边写边推,我用了golang的net/http包,再结合m3u8切片(HLS协议)。

步骤拆解

  1. 每收到一帧H.264数据,写进一个临时文件(比如segment.ts
  2. 每个几秒生成一个索引文件(playlist.m3u8
  3. 手机端(比如用VLC或者浏览器)访问http://手机IP:8080/playlist.m3u8就能看到实时画面

代码大体结构:

http.HandleFunc("/playlist.m3u8", func(w http.ResponseWriter, r *http.Request) {
    // 返回当前最新的索引内容
    w.Write([]byte("#EXTM3U\n#EXT-X-TARGETDURATION:3\n#EXTINF:3.0,\nsegment.ts\n"))
})
http.HandleFunc("/segment.ts", func(w http.ResponseWriter, r *http.Request) {
    // 返回最新的视频切片
    http.ServeFile(w, r, "segment.ts")
})
http.ListenAndServe(":8080", nil)

这里有个大坑:帧对齐,H.264切片必须从关键帧(I帧)开始切,否则手机端播放会花屏,我最初在切片点随意切,结果手机端的VLC一直黑屏,折腾了两天才发现关键帧之间插入P帧、B帧,切不对就崩,解决办法:记录nalu类型,遇到0x67(SPS)就说明新关键帧开始,此时才切割。

func onNALU(nalu []byte) {
    if nalu[0] == 0x67 { // SPS,关键帧开始
        flushCurrentSegment()   // 结束旧切片
        startNewSegment()       // 开始新切片
    }
}

第四步:手机端怎么连?——App还是浏览器?

手机浏览器是最省事的:打开浏览器,地址栏输http://你手机IP:8080/playlist.m3u8,如果用的iPhone,Safari原生支持HLS;安卓的话,用Chrome也行,但有些老版本得装VLC App。

官方App?ycc365plus的App是走私有协议的,跟golang写的这个服务器不兼容,所以咱这方案是绕开App,直接用标准协议,优势是不怕App更新封杀,劣势是……你得自己维护这个golang服务。

踩坑清单(血的教训)

坑名 原因 解决办法
密码忘了 默认密码在App里设置,不是Wi-Fi密码 重置摄像头(长按复位键)
版本依赖 vdk库老版本有nil pointer bug 升到v0.12.0+,或者换github.com/pion/mediadevices
切片花屏 没有在关键帧处切割 检查nalu类型,只切在I帧
手机延迟大 HLS默认切5秒切片 把切片时长降到2~3秒
局域网外访问 摄像头在内网,手机在外网 搞个公网IP或者内网穿透(但本文不展开)

最后说点实在的

写了这么长,其实ycc365plus连接手机视频的核心就三点:找到正确的RTSP地址、用golang循环读帧、用HLS切片推给浏览器,代码不完美,我也没删掉那些跳坑的经历——什么密码记错、版本不对、花屏三连……但这些就是真实的调试过程。

如果照着上面那几段代码跑不通,先检查摄像头IP对不对,然后打开终端输ffprobe rtsp://admin:密码@IP:554/stream1,看能不能分析出视频流,如果能,golang代码肯定也能,如果不行,那是摄像头设置问题。

好了,我去给窗台上的ycc365plus换个位置,它老对着猫窝拍,我怕隐私泄露——虽然猫也没什么隐私可言。

用golang写一篇关于ycc365plus怎样连接手机视频的文章