go - 如何将视频捕获流式传输到网络
问题描述
我有下面的代码读取 cam 并将其显示在 GUI 窗口中,我想将相同的东西推送到我的服务器 url localhost:8080/cam
,我该怎么做?
package main
import (
"gocv.io/x/gocv"
)
func main() {
webcam, _ := gocv.VideoCaptureDevice(0)
defer webcam.Close() // Close the cam once execution completed
window := gocv.NewWindow("Hello")
defer window.Close() // Close the GUI once execution completed, though it is done automatically
img := gocv.NewMat()
defer img.Close() // Close the img once execution completed
for {
webcam.Read(&img)
window.IMShow(img)
// Want to do streaming here to localhost:8080/cam
if window.WaitKey(1) == 27 { // 27 => Esc
break
}
}
}
解决方案
package mjpeg
import (
"fmt"
"log"
"net/http"
"sync"
"time"
)
// Stream represents a single video feed.
type Stream struct {
m map[chan []byte]bool
frame []byte
lock sync.Mutex
FrameInterval time.Duration
}
const boundaryWord = "MJPEGBOUNDARY"
const headerf = "\r\n" +
"--" + boundaryWord + "\r\n" +
"Content-Type: image/jpeg\r\n" +
"Content-Length: %d\r\n" +
"X-Timestamp: 0.000000\r\n" +
"\r\n"
// ServeHTTP responds to HTTP requests with the MJPEG stream, implementing the http.Handler interface.
func (s *Stream) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.Println("Stream:", r.RemoteAddr, "connected")
w.Header().Add("Content-Type", "multipart/x-mixed-replace;boundary="+boundaryWord)
c := make(chan []byte)
s.lock.Lock()
s.m[c] = true
s.lock.Unlock()
for {
time.Sleep(s.FrameInterval)
b := <-c
_, err := w.Write(b)
if err != nil {
break
}
}
s.lock.Lock()
delete(s.m, c)
s.lock.Unlock()
log.Println("Stream:", r.RemoteAddr, "disconnected")
}
// UpdateJPEG pushes a new JPEG frame onto the clients.
func (s *Stream) UpdateJPEG(jpeg []byte) {
header := fmt.Sprintf(headerf, len(jpeg))
if len(s.frame) < len(jpeg)+len(header) {
s.frame = make([]byte, (len(jpeg)+len(header))*2)
}
copy(s.frame, header)
copy(s.frame[len(header):], jpeg)
s.lock.Lock()
for c := range s.m {
// Select to skip streams which are sleeping to drop frames.
// This might need more thought.
select {
case c <- s.frame:
default:
}
}
s.lock.Unlock()
}
// NewStream initializes and returns a new Stream.
func NewStream() *Stream {
return &Stream{
m: make(map[chan []byte]bool),
frame: make([]byte, len(headerf)),
FrameInterval: 50 * time.Millisecond,
}
}
我的任何运行代码是:
package main
import (
"fmt"
"log"
"net/http"
"github.com/hybridgroup/mjpeg"
_ "github.com/hybridgroup/mjpeg"
"gocv.io/x/gocv"
)
func main() {
deviceID := 0
webcam, err := gocv.OpenVideoCapture(deviceID)
if err != nil {
fmt.Printf("Error opening video capture device: %v\n", deviceID)
return
}
// create the mjpeg stream
stream := mjpeg.NewStream()
// start capturing
go func(webcam *gocv.VideoCapture, stream *mjpeg.Stream) {
defer webcam.Close()
window := gocv.NewWindow("Capture Window")
defer window.Close()
img := gocv.NewMat()
defer img.Close()
fmt.Printf("Start reading device: %v\n", deviceID)
for {
if ok := webcam.Read(&img); !ok {
fmt.Printf("Device closed: %v\n", deviceID)
return
}
if img.Empty() {
continue
}
buf, _ := gocv.IMEncode(".jpg", img)
stream.UpdateJPEG(buf)
window.IMShow(img)
if window.WaitKey(1) == 27 { // 27 => Esc
break
}
}
}(webcam, stream)
http.Handle("/", stream)
log.Fatal(http.ListenAndServe(":8080", nil))
}
推荐阅读
- android - 在后台模式下使用应用程序更改应用程序权限(从常规设置)时出现问题
- php - 如何计算用户在php中上传的图像、pdf、ppt或doc文件大小
- java - 我无法通过全局端口 3269 使用 ldap 在活动目录中创建用户
- angular - 如何链接 Angular 可观察对象?
- reactjs - 导航栏反应路由器与引导程序不起作用
- node.js - 使用 \t \r \n nodejs 加密字符串
- javascript - 多次添加事件监听器
- amazon-web-services - 如何根据 cloudmetrics 数据在 aws 中自动缩放?
- sql - 我们如何在 DB_link oracle 中的表上创建物化视图
- docker - docker restart 导致两个正在运行的容器