Browse Source

Add option for limiting output frame rate

pull/9/head
Valentin Vidic 3 months ago
parent
commit
99e4412937
3 changed files with 36 additions and 8 deletions
  1. +28
    -3
      chunker.go
  2. +6
    -4
      mjpeg-proxy.go
  3. +2
    -1
      sources.json

+ 28
- 3
chunker.go View File

@ -29,6 +29,7 @@ import (
"net/http"
"net/url"
"strings"
"time"
)
/* Sample source stream starts like this:
@ -53,9 +54,10 @@ type Chunker struct {
resp *http.Response
boundary string
stop chan struct{}
rate float64
}
func NewChunker(id, source, username, password string) (*Chunker, error) {
func NewChunker(id, source, username, password string, rate float64) (*Chunker, error) {
chunker := new(Chunker)
sourceUrl, err := url.Parse(source)
@ -70,6 +72,7 @@ func NewChunker(id, source, username, password string) (*Chunker, error) {
chunker.source = source
chunker.username = username
chunker.password = password
chunker.rate = rate
return chunker, nil
}
@ -153,6 +156,13 @@ func (chunker *Chunker) Start(pubChan chan []byte) {
var failure error
mr := multipart.NewReader(body, chunker.boundary)
var ticker *time.Ticker
firstFrame := true
if chunker.rate > 0 {
interval := float64(time.Second) / chunker.rate
ticker = time.NewTicker(time.Duration(interval))
}
ChunkLoop:
for {
part, err := mr.NextPart()
@ -181,11 +191,26 @@ ChunkLoop:
break ChunkLoop
}
select {
select { // check for stop
case <-chunker.stop:
break ChunkLoop
case pubChan <- data:
default:
}
if !firstFrame && ticker != nil {
select {
case <-ticker.C: // use frame
default: // skip frame
continue ChunkLoop
}
}
firstFrame = false
pubChan <- data
}
if ticker != nil {
ticker.Stop()
}
if failure != nil {


+ 6
- 4
mjpeg-proxy.go View File

@ -41,10 +41,11 @@ type configSource struct {
Username string
Password string
Path string
Rate float64
}
func startSource(source, username, password, proxyUrl string) error {
chunker, err := NewChunker(proxyUrl, source, username, password)
func startSource(source, username, password, proxyUrl string, rate float64) error {
chunker, err := NewChunker(proxyUrl, source, username, password, rate)
if err != nil {
return fmt.Errorf("chunker[%s]: create failed: %s", proxyUrl, err)
}
@ -82,7 +83,7 @@ func loadConfig(filename string) error {
return fmt.Errorf("duplicate proxy path: %s", conf.Path)
}
err = startSource(conf.Source, conf.Username, conf.Password, conf.Path)
err = startSource(conf.Source, conf.Username, conf.Password, conf.Path, conf.Rate)
if err != nil {
return err
}
@ -140,6 +141,7 @@ func main() {
sources := flag.String("sources", "", "JSON configuration file to load sources from")
bind := flag.String("bind", ":8080", "proxy bind address")
path := flag.String("path", "/", "proxy serving path")
rate := flag.Float64("rate", 0, "limit output frame rate")
maxprocs := flag.Int("maxprocs", 0, "limit number of CPUs used")
flag.DurationVar(&stopDelay, "stopduration", 60*time.Second, "follow source after last client")
flag.IntVar(&tcpSendBuffer, "sendbuffer", 4096, "limit buffering of frames")
@ -154,7 +156,7 @@ func main() {
if *sources != "" {
err = loadConfig(*sources)
} else {
err = startSource(*source, *username, *password, *path)
err = startSource(*source, *username, *password, *path, *rate)
}
if err != nil {
fmt.Println("config:", err)


+ 2
- 1
sources.json View File

@ -1,7 +1,8 @@
[
{
"Source" : "http://213.193.89.202/axis-cgi/mjpg/video.cgi",
"Path" : "/source1"
"Path" : "/source1",
"Rate" : 1.0
},
{
"Source" : "http://klosterplatz.selfip.info/axis-cgi/mjpg/video.cgi",


Loading…
Cancel
Save