文章目录
- 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 }
- 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()) } }
- 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(“–framern”)); err != nil { return } lastSent := time.Now() for { frame, frameTime := getFrameCache() // 只发送新帧 if frameTime.After(lastSent) { if _, err := fmt.Fprintf(w, “Content-Type: image/jpegrnContent-Length: %drnrn”, len(frame)); err != nil { return } if _, err := w.Write(frame); err != nil { return } if _, err := w.Write([]byte(“rn–framern”)); 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: } } }
- 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)) }
目录
- 核心功能
- Go后端实现
- 1. 全局帧缓存模块 (frame_cache.go)
- 2. 截屏服务模块 (capture_service.go)
- 3. 流处理模块 (stream_handler.go)
- 4. 主程序模块 (main.go)
- 三、Web前端实现
- 四、运行步骤
- 五、技术要点说明
本文介绍如何使用 Golang 原生库 实现一个高效的屏幕实时截图推送服务。不同于以往依赖 FFmpeg 的方案,我们通过 github.com/kbinani/screenshot 直接捕获屏幕画面,并将图像以 JPEG 格式通过 HTTP 推送给前端浏览器播放。

- 屏幕截取:使用Go捕获当前屏幕内容
- 实时推流:将视频流通过HTTP协议推送
- Web播放:简单HTML页面验证流媒体
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
}
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())
}
}
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("--framern")); err != nil {
return
}
lastSent := time.Now()
for {
frame, frameTime := getFrameCache()
// 只发送新帧
if frameTime.After(lastSent) {
if _, err := fmt.Fprintf(w,
"Content-Type: image/jpegrnContent-Length: %drnrn",
len(frame)); err != nil {
return
}
if _, err := w.Write(frame); err != nil {
return
}
if _, err := w.Write([]byte("rn--framern")); 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:
}
}
}
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))
}
创建一个简单的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
2.运行Go程序:
go run main.go
3.打开浏览器访问: http://localhost:8080
使用screenshot库捕获屏幕内容
采用MJPEG(Motion-JPEG)格式推送视频流
前端通过简单的<img>标签即可播放视频流
自动重连机制确保网络不稳定时的观看体验
到此这篇关于Go语言利用原生库实现屏幕截取和实时推流功能的文章就介绍到这了,更多相关Go屏幕截取内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!
您可能感兴趣的文章:
- golang快速实现网页截图的方法
- go语言实现屏幕截图的示例代码
- 通过Golang实现无头浏览器截图