当前位置:首页 > 其它 > 正文

用Golang写了个肥东vs长丰夜景视频直播对比工具,结果我半夜看饿了

  • 其它
  • 2026-08-01 14:02:25
  • 62
摘要: 先别急着看代码,说说我为啥要整这玩意儿上周五晚上十一点,我正窝在沙发上刷手机,刷到一条短视频——肥东的夜景,霓虹灯把整条长江东路...

先别急着看代码,说说我为啥要整这玩意儿

上周五晚上十一点,我正窝在沙发上刷手机,刷到一条短视频——肥东的夜景,霓虹灯把整条长江东路照得跟白昼似的,接着又刷到下一条,长丰的北城,高楼群像打翻了的星河,我老婆凑过来瞄了一眼,来了句:“这俩地方离得这么近,夜景差距咋这么大呢?”

我随口回了句:“要不我写个程序对比下?”

…我就真写了。

作为一个整天跟Golang打交道的码农,我第一时间想到的不是拿手机录屏对比,而是写个自动抓取两地夜景直播流的工具。这事儿得从需求说起:肥东和长丰虽然都属于合肥,但夜景风格完全不同——肥东主打老城烟火气,长江东路两边的大排档灯光暖得能滴出油来;长丰北城则是新区范儿,高楼LED幕墙蓝得发冷。

当时我手头就一台笔记本电脑,装了Golang 1.21,没有GPU,没有高性能服务器,纯靠标准库加两个开源库就把这事儿干成了。

第一步:摸清视频直播流的底细

要对比两地夜景,首先得有视频源,我翻了翻几个公开的慢直播平台,发现肥东撮街长丰北城都有人做24小时夜景直播,但问题是,这些直播流地址经常变,而且有的还带防盗链。

我写了个小工具,用 net/http 库去请求直播平台的接口,解析出真实的流地址(一般是HLS格式的.m3u8文件),核心逻辑大概是这样的:

func getLiveStream(platform string, region string) (string, error) {
    // 构造API请求,获取播放列表
    resp, err := http.Get(fmt.Sprintf("https://api.example.com/live/%s/%s", platform, region))
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()
    // 解析JSON响应,提取流地址
    var data map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&data)
    streamURL := data["data"].(map[string]interface{})["url"].(string)
    return streamURL, nil
}

这是简化版,实际跑起来的时候踩了不少坑——有的平台需要带Referer头,有的需要带token,有的还会做UA校验。这块我花了整整一个晚上调试,最后封装了一个统一的请求函数,用 go-redis 缓存了token,避免频繁重新认证。

第二步:同时拉流,别让卡顿坏了对比

拿到两个直播流地址后,最大的技术难点是同时拉取两路视频,并且保证画面时间戳基本同步,我用的是 ffmpeg 命令行工具,通过Golang的 os/exec 包来调用。

这里有三个关键参数:

参数 作用 我踩的坑
-rtsp_transport tcp 用TCP传输避免丢包 默认UDP会导致画面花屏
-fflags nobuffer 降低缓冲延迟 不加这个延迟能到5秒以上
-analyzeduration 1000 缩短解析时间 默认值会导致启动慢好几秒

拉起两个ffmpeg进程后,我把输出分别重定向到两个文件,然后每10秒截取一帧缩略图,用 image 库拼成一张对比图,这活儿干着干着,我突然意识到——这不就是视频直播对比的粗糙原型嘛

第三步:数据分析,亮度对比居然有门道

光是截图对比还不够,我决定用Golang做点量化分析,用了 gocv (Go版本的OpenCV)来提取两帧画面的平均亮度、色温偏蓝程度和画面复杂度。

结果挺有意思:

  • 肥东的平均亮度在黄昏后1小时下降得比较慢,因为大排档和小商铺的招牌多,都是暖光。
  • 长丰北城的亮度曲线在晚上9点后出现一个陡升,原来是写字楼的LED幕墙在做动态切换。

我顺手把分析结果写进了一个HTML报告里,用html/template库渲染,还加了个柱状图(纯CSS画的),这里放一段关键代码:

type NightCompare struct {
    Region       string
    Brightness   float64
    BlueShift    float64
    WarmPopularity int
}
func generateReport(data []NightCompare) string {
    // 用template渲染统计结果
    tmpl := `<h2>{{.Region}}夜景分析</h2>
    <p>平均亮度: <strong>{{.Brightness}}</strong></p>
    <p>蓝色偏移: <em>{{.BlueShift}}</em></p>`
    ...
}

第四步:实时对比的UI——一个人也能搞定的“直播间”

既然做了工具,光自己看多没意思,我临时起意,用 net/http 写了个简单的Web页面,每隔5秒刷新一下对比截图组合,没有用WebSocket,因为就我一个人看,轮询够了。

页面布局很简单:

  • 左半边显示肥东的实时画面(引用本地生成的JPEG)
  • 右半边显示长丰的画面
  • 底部一行小字显示当前亮度差帧延迟

我用 html/template 直接内联在Go代码里,没单独写HTML文件,因为就一个页面没必要。

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    images := map[string]string{
        "feidong": "/tmp/shot_feidong.jpg",
        "changfeng": "/tmp/shot_changfeng.jpg",
    }
    tmpl.Execute(w, images)
})

跑起来后发现的事儿

工具跑通的那天晚上,我盯着屏幕看了半小时,你说奇怪不奇怪,肥东的绿灯多,长丰的蓝灯多,搁在同一个屏幕上,视觉冲击力特别强,我老婆路过瞅了一眼,说了一句:“这俩地方是不是约好了,一个走市井风,一个走科技风?”

还真让她说中了。

我顺手查了查资料,肥东县2023年的夜景照明规划里重点提到“保留老城区烟火气息”,而长丰北城的规划则是“打造现代化灯光艺术长廊”。两者的灯光色温有明显差异——肥东普遍在2700K左右(暖黄),长丰普遍在5000K以上(冷白)。

这还引出一个技术上的隐藏指标:把两帧画面的像素做差分,能看出动态灯光占比,长丰的动态灯光明显多,因为LED屏在滚动播放广告;肥东则是静态招牌多,偶尔有几家烧烤店的霓虹灯管闪两下。

关于代码的反思——不够完美,但够用

这套工具代码量不大,总共三百来行,纯Golang加少量Shell脚本,但它有几个毛病:

  1. ffmpeg进程如果崩了,没有自动重启逻辑,我半夜起来看,发现长丰的画面停在了凌晨两点。
  2. 截图间隔是固定的5秒,遇到直播间卡顿会攒下很多重复帧,分析出来的亮度值会偏真实值。
  3. 没有做多平台支持,换一个直播平台就得改代码,硬编码了URL模板。

这本来就是我临时起意的个人玩具。能在一个屏幕上同时看到肥东和长丰的夜景,哪怕粗糙点,也够有意思了,你看,这跟我平时写业务代码不一样——业务代码要求完美,但个人小工具嘛,能用就行。

如果你也想玩,给你点小建议

如果你对这个话题感兴趣,不妨自己动手试试,工具虽糙,但思路可以复用:

  • 视频流获取:用HTTP客户端模拟浏览器请求,解析m3u8文件里的片段地址
  • 帧对比:用ffmpeg每秒抽取一帧,存的盘用完了记得清
  • 数据可视化:Golang标准库自带的image包就够画热力图

你要是赶巧也在合肥,可以晚上八点半到九点半之间打开这个对比工具,那是两地夜景差异最明显的时候。

写到最后,我看了眼窗外——我家住在包河区,既没有肥东的热闹,也没有长丰的科技感,但打开工具,把画面切成左右两半,好像自己就站在撮街的油炸摊边上,又好像站在北城的写字楼底下抬着头,也甭管代码够不够优雅了,反正这个周末,我用Golang给自己搭了个“云逛街”的窗口。

用Golang写了个肥东vs长丰夜景视频直播对比工具,结果我半夜看饿了