Skip to content

Commit 2ad5743

Browse files
committed
Initial commit
0 parents  commit 2ad5743

File tree

13 files changed

+1389
-0
lines changed

13 files changed

+1389
-0
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Milan Nikolic <[email protected]>

COPYING

Lines changed: 674 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
## cam2ip
2+
3+
Turn any webcam into ip camera.
4+
5+
Example (in web browser):
6+
7+
http://localhost:56000/mjpeg
8+
or
9+
10+
http://localhost:56000/html
11+
12+
### Requirements
13+
14+
* [OpenCV 2.x](http://opencv.org/)
15+
16+
17+
### Download
18+
19+
Binaries are compiled with static OpenCV library:
20+
21+
- [Linux 64bit](https://github.com/gen2brain/cam2ip/releases/download/1.0/cam2ip-1.0-64bit.tar.gz)
22+
- [Windows 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.0/cam2ip-1.0.zip)
23+
- [RPi 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.0/cam2ip-1.0-RPi.tar.gz)
24+
25+
26+
### Installation
27+
28+
go get -v github.com/gen2brain/cam2ip
29+
30+
This will install app in `$GOPATH/bin/cam2ip`.
31+
32+
### Usage
33+
34+
```
35+
Usage of ./cam2ip:
36+
-bind-addr string
37+
Bind address (default ":56000")
38+
-delay int
39+
Delay between frames, in milliseconds (default 10)
40+
-frame-height float
41+
Frame height (default 480)
42+
-frame-width float
43+
Frame width (default 640)
44+
-htpasswd-file string
45+
Path to htpasswd file, if empty auth is disabled
46+
-index int
47+
Camera index
48+
```
49+
50+
### Handlers
51+
52+
* `/html`: HTML handler, frames are pushed to canvas over websocket
53+
* `/jpeg`: Static JPEG handler
54+
* `/mjpeg`: Motion JPEG, supported natively in major web browsers

cam2ip.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"os"
7+
8+
"github.com/gen2brain/cam2ip/camera"
9+
"github.com/gen2brain/cam2ip/server"
10+
)
11+
12+
const (
13+
name = "cam2ip"
14+
version = "1.0"
15+
)
16+
17+
func main() {
18+
srv := server.NewServer()
19+
20+
flag.IntVar(&srv.Index, "index", 0, "Camera index")
21+
flag.IntVar(&srv.Delay, "delay", 10, "Delay between frames, in milliseconds")
22+
flag.Float64Var(&srv.FrameWidth, "frame-width", 640, "Frame width")
23+
flag.Float64Var(&srv.FrameHeight, "frame-height", 480, "Frame height")
24+
flag.StringVar(&srv.Bind, "bind-addr", ":56000", "Bind address")
25+
flag.StringVar(&srv.Htpasswd, "htpasswd-file", "", "Path to htpasswd file, if empty auth is disabled")
26+
flag.Parse()
27+
28+
srv.Name = name
29+
srv.Version = version
30+
31+
var err error
32+
33+
if srv.Htpasswd != "" {
34+
if _, err = os.Stat(srv.Htpasswd); err != nil {
35+
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
36+
os.Exit(1)
37+
}
38+
}
39+
40+
srv.Camera, err = camera.NewCamera(srv.Index)
41+
if err != nil {
42+
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
43+
os.Exit(1)
44+
}
45+
46+
srv.Camera.SetProperty(camera.PropFrameWidth, srv.FrameWidth)
47+
srv.Camera.SetProperty(camera.PropFrameHeight, srv.FrameHeight)
48+
49+
defer srv.Camera.Close()
50+
51+
fmt.Fprintf(os.Stderr, "Listening on %s\n", srv.Bind)
52+
53+
err = srv.ListenAndServe()
54+
if err != nil {
55+
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
56+
os.Exit(1)
57+
}
58+
}

camera/camera.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Package camera.
2+
package camera
3+
4+
import (
5+
"fmt"
6+
"image"
7+
8+
"github.com/lazywei/go-opencv/opencv"
9+
)
10+
11+
// Property identifiers.
12+
const (
13+
PropPosMsec = iota
14+
PropPosFrames
15+
PropPosAviRatio
16+
PropFrameWidth
17+
PropFrameHeight
18+
PropFps
19+
PropFourcc
20+
PropFrameCount
21+
PropFormat
22+
PropMode
23+
PropBrightness
24+
PropContrast
25+
PropSaturation
26+
PropHue
27+
PropGain
28+
PropExposure
29+
PropConvertRgb
30+
PropWhiteBalanceU
31+
PropRectification
32+
PropMonocrome
33+
PropSharpness
34+
PropAutoExposure
35+
PropGamma
36+
PropTemperature
37+
PropTrigger
38+
PropTriggerDelay
39+
PropWhiteBalanceV
40+
PropZoom
41+
PropFocus
42+
PropGuid
43+
PropIsoSpeed
44+
PropMaxDc1394
45+
PropBacklight
46+
PropPan
47+
PropTilt
48+
PropRoll
49+
PropIris
50+
PropSettings
51+
PropBuffersize
52+
)
53+
54+
// Camera represents camera.
55+
type Camera struct {
56+
Index int
57+
camera *opencv.Capture
58+
}
59+
60+
// NewCamera returns new Camera for given camera index.
61+
func NewCamera(index int) (camera *Camera, err error) {
62+
camera = &Camera{}
63+
camera.Index = index
64+
65+
camera.camera = opencv.NewCameraCapture(index)
66+
if camera.camera == nil {
67+
err = fmt.Errorf("camera: can not open camera %d", index)
68+
}
69+
70+
return
71+
}
72+
73+
// Read reads next frame from camera and returns image.
74+
func (c *Camera) Read() (img image.Image, err error) {
75+
if c.camera.GrabFrame() {
76+
frame := c.camera.RetrieveFrame(1)
77+
img = frame.ToImage()
78+
} else {
79+
err = fmt.Errorf("camera: can not grab frame")
80+
}
81+
82+
return
83+
}
84+
85+
// GetProperty returns the specified camera property.
86+
func (c *Camera) GetProperty(id int) float64 {
87+
return c.camera.GetProperty(id)
88+
}
89+
90+
// SetProperty sets a camera property.
91+
func (c *Camera) SetProperty(id int, value float64) int {
92+
return c.camera.SetProperty(id, value)
93+
}
94+
95+
// Close closes camera.
96+
func (c *Camera) Close() (err error) {
97+
if c.camera == nil {
98+
err = fmt.Errorf("camera: camera is not opened")
99+
}
100+
101+
c.camera.Release()
102+
c.camera = nil
103+
return
104+
}

camera/camera_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package camera
2+
3+
import (
4+
"fmt"
5+
"image/jpeg"
6+
"io/ioutil"
7+
"os"
8+
"path/filepath"
9+
"testing"
10+
"time"
11+
)
12+
13+
func TestCamera(t *testing.T) {
14+
camera, err := NewCamera(1)
15+
if err != nil {
16+
t.Fatal(err)
17+
}
18+
19+
defer camera.Close()
20+
21+
tmpdir, err := ioutil.TempDir(os.TempDir(), "cam2ip")
22+
if err != nil {
23+
t.Error(err)
24+
}
25+
26+
defer os.RemoveAll(tmpdir)
27+
28+
var width, height float64 = 640, 480
29+
camera.SetProperty(PropFrameWidth, width)
30+
camera.SetProperty(PropFrameHeight, height)
31+
32+
if camera.GetProperty(PropFrameWidth) != width {
33+
t.Error("FrameWidth not correct")
34+
}
35+
36+
if camera.GetProperty(PropFrameHeight) != height {
37+
t.Error("FrameHeight not correct")
38+
}
39+
40+
var i int
41+
var n int = 10
42+
43+
timeout := time.After(time.Duration(n) * time.Second)
44+
45+
for {
46+
select {
47+
case <-timeout:
48+
//fmt.Printf("Fps: %d\n", i/n)
49+
return
50+
default:
51+
i += 1
52+
53+
img, err := camera.Read()
54+
if err != nil {
55+
t.Error(err)
56+
}
57+
58+
file, err := os.Create(filepath.Join(tmpdir, fmt.Sprintf("%03d.jpg", i)))
59+
if err != nil {
60+
t.Error(err)
61+
}
62+
63+
err = jpeg.Encode(file, img, &jpeg.Options{Quality: 75})
64+
if err != nil {
65+
t.Error(err)
66+
}
67+
68+
err = file.Close()
69+
if err != nil {
70+
t.Error(err)
71+
}
72+
}
73+
}
74+
}

camera/encode.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package camera
2+
3+
import (
4+
"image"
5+
//"image/jpeg"
6+
"io"
7+
8+
jpeg "github.com/kjk/golibjpegturbo"
9+
)
10+
11+
// NewEncoder returns a new Encoder.
12+
func NewEncoder(w io.Writer) *Encoder {
13+
return &Encoder{w}
14+
}
15+
16+
// Encoder struct.
17+
type Encoder struct {
18+
w io.Writer
19+
}
20+
21+
// Encode encodes image to JPEG.
22+
func (e Encoder) Encode(img image.Image) error {
23+
err := jpeg.Encode(e.w, img, &jpeg.Options{Quality: 75})
24+
if err != nil {
25+
return err
26+
}
27+
28+
return nil
29+
}

0 commit comments

Comments
 (0)