Go语言实现屏幕截取+实时推流

本文介绍如何使用 Golang 原生库 实现一个高效的屏幕实时截图推送服务。不同于以往依赖 FFmpeg 的方案,我们通过
github.com/kbinani/screenshot 直接捕获屏幕画面,并将图像以 JPEG 格式通过 HTTP 推送给前端浏览器播放。

核心功能

  1. 屏幕截取:使用Go捕获当前屏幕内容
  2. 实时推流:将视频流通过HTTP协议推送
  3. Web播放:简单HTML页面验证流媒体

Go后端实现

1. 全局帧缓存模块 (frame_cache.go)

package main

import ( "sync" "time" ) #后端 #音视频开发

var ( frameCache []byte frameCacheTime time.Time cacheMutex sync.RWMutex )

// 更新帧缓存 func updateFrameCache(frame []byte) { cacheMutex.Lock() defer cacheMutex.Unlock() frameCache = frame frameCacheTime = time.Now() }

// 获取帧缓存 func getFrameCache() ([]byte, time.Time) { cacheMutex.RLock() defer cacheMutex.RUnlock() return frameCache, frameCacheTime }

2. 截屏服务模块 (capture_service.go)

package main

import ( "bytes" "image/jpeg" "log" "time"

"github.com/kbinani/screenshot" )

func startCaptureService() { ticker := time.NewTicker(time.Second / time.Duration(frameRate)) defer ticker.Stop()

for range ticker.C { img, err := screenshot.CaptureRect(screenBounds) if err != nil { log.Printf("截屏失败: %v", err) continue }

buf := new(bytes.Buffer) if err := jpeg.Encode(buf, img, &jpeg.Options{Quality: quality}); err != nil { log.Printf("JPEG 编码失败: %v", err) continue }

updateFrameCache(buf.Bytes()) } }

3. 流处理模块 (stream_handler.go)

package main

import ( "fmt" "net/http" "time" )

func streamHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "multipart/x-mixed-replace; boundary=frame") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive")

// 发送初始帧分隔符 if _, err := w.Write([]byte("--frame
")); err != nil { return }

lastSent := time.Now() for { frame, frameTime := getFrameCache()

// 只发送新帧 if frameTime.After(lastSent) { if _, err := fmt.Fprintf(w, "Content-Type: image/jpeg
Content-Length: %d

", len(frame)); err != nil { return }

if _, err := w.Write(frame); err != nil { return }

if _, err := w.Write([]byte("
--frame
")); err != nil { return }

if f, ok := w.(http.Flusher); ok { f.Flush() }

lastSent = frameTime }

// 防止 CPU 空转 time.Sleep(time.Second / time.Duration(frameRate*2))

select { case <-r.Context().Done(): return default: } } }

4. 主程序模块 (main.go)

package main

import ( "image" "log" "net/http"

"github.com/kbinani/screenshot" )

var ( quality = 50 // JPEG 质量(1-100) frameRate = 10 // 帧率(FPS) screenBounds = image.Rect(0, 0, 0, 0) // 屏幕尺寸 )

func main() { // 初始化截屏区域 if n := screenshot.NumActiveDisplays(); n <= 0 { log.Fatal("未检测到活动显示器") } screenBounds = screenshot.GetDisplayBounds(0)

// 启动截屏服务 go startCaptureService()

// 设置路由 http.HandleFunc("/stream", streamHandler) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "index.html") })

// 启动服务器 log.Println("服务启动: http://localhost:8080") log.Fatal(http.ListenAndServe(":8080", nil)) }

三、Web前端实现

创建一个简单的 index.html 文件,前端直接用 image 标签进行显示即可:

<!DOCTYPE html>

<html>

<head>

<title>Go 屏幕流测试</title>

<style>

body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; } #video { max-width: 90%; border: 1px solid #ccc; margin: 20px auto; } </style>

</head>

<body>

<h1>Go 屏幕流测试播放器</h1>

<img id="video" src="/stream" alt="视频流">

<div>

<button onclick="window.location.reload()">重新加载</button>

</div>

<script>

// 自动重连逻辑 const video = document.getElementById('video'); video.onerror = function() { setTimeout(function() { video.src = '/stream?t=' + new Date().getTime(); }, 1000); }; </script>

</body>

</html>

运行步骤

  1. 安装依赖库:
go get github.com/kbinani/screenshot
  1. 运行Go程序:
go run main.go
  1. 打开浏览器访问: http://localhost:8080

技术要点说明

  1. 使用 screenshot 库捕获屏幕内容
  2. 采用MJPEG(Motion-JPEG)格式推送视频流
  3. 前端通过简单的 <img> 标签即可播放视频流
  4. 自动重连机制确保网络不稳定时的观看体验
© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
岁月静好者200809的头像 - 鹿快
评论 抢沙发

请登录后发表评论

    暂无评论内容