-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2ad5743
Showing
13 changed files
with
1,389 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Milan Nikolic <gen2brain@gmail.com> |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
## cam2ip | ||
|
||
Turn any webcam into ip camera. | ||
|
||
Example (in web browser): | ||
|
||
http://localhost:56000/mjpeg | ||
or | ||
|
||
http://localhost:56000/html | ||
|
||
### Requirements | ||
|
||
* [OpenCV 2.x](http://opencv.org/) | ||
|
||
|
||
### Download | ||
|
||
Binaries are compiled with static OpenCV library: | ||
|
||
- [Linux 64bit](https://github.com/gen2brain/cam2ip/releases/download/1.0/cam2ip-1.0-64bit.tar.gz) | ||
- [Windows 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.0/cam2ip-1.0.zip) | ||
- [RPi 32bit](https://github.com/gen2brain/cam2ip/releases/download/1.0/cam2ip-1.0-RPi.tar.gz) | ||
|
||
|
||
### Installation | ||
|
||
go get -v github.com/gen2brain/cam2ip | ||
|
||
This will install app in `$GOPATH/bin/cam2ip`. | ||
|
||
### Usage | ||
|
||
``` | ||
Usage of ./cam2ip: | ||
-bind-addr string | ||
Bind address (default ":56000") | ||
-delay int | ||
Delay between frames, in milliseconds (default 10) | ||
-frame-height float | ||
Frame height (default 480) | ||
-frame-width float | ||
Frame width (default 640) | ||
-htpasswd-file string | ||
Path to htpasswd file, if empty auth is disabled | ||
-index int | ||
Camera index | ||
``` | ||
|
||
### Handlers | ||
|
||
* `/html`: HTML handler, frames are pushed to canvas over websocket | ||
* `/jpeg`: Static JPEG handler | ||
* `/mjpeg`: Motion JPEG, supported natively in major web browsers |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/gen2brain/cam2ip/camera" | ||
"github.com/gen2brain/cam2ip/server" | ||
) | ||
|
||
const ( | ||
name = "cam2ip" | ||
version = "1.0" | ||
) | ||
|
||
func main() { | ||
srv := server.NewServer() | ||
|
||
flag.IntVar(&srv.Index, "index", 0, "Camera index") | ||
flag.IntVar(&srv.Delay, "delay", 10, "Delay between frames, in milliseconds") | ||
flag.Float64Var(&srv.FrameWidth, "frame-width", 640, "Frame width") | ||
flag.Float64Var(&srv.FrameHeight, "frame-height", 480, "Frame height") | ||
flag.StringVar(&srv.Bind, "bind-addr", ":56000", "Bind address") | ||
flag.StringVar(&srv.Htpasswd, "htpasswd-file", "", "Path to htpasswd file, if empty auth is disabled") | ||
flag.Parse() | ||
|
||
srv.Name = name | ||
srv.Version = version | ||
|
||
var err error | ||
|
||
if srv.Htpasswd != "" { | ||
if _, err = os.Stat(srv.Htpasswd); err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", err.Error()) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
srv.Camera, err = camera.NewCamera(srv.Index) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", err.Error()) | ||
os.Exit(1) | ||
} | ||
|
||
srv.Camera.SetProperty(camera.PropFrameWidth, srv.FrameWidth) | ||
srv.Camera.SetProperty(camera.PropFrameHeight, srv.FrameHeight) | ||
|
||
defer srv.Camera.Close() | ||
|
||
fmt.Fprintf(os.Stderr, "Listening on %s\n", srv.Bind) | ||
|
||
err = srv.ListenAndServe() | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "%s\n", err.Error()) | ||
os.Exit(1) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// Package camera. | ||
package camera | ||
|
||
import ( | ||
"fmt" | ||
"image" | ||
|
||
"github.com/lazywei/go-opencv/opencv" | ||
) | ||
|
||
// Property identifiers. | ||
const ( | ||
PropPosMsec = iota | ||
PropPosFrames | ||
PropPosAviRatio | ||
PropFrameWidth | ||
PropFrameHeight | ||
PropFps | ||
PropFourcc | ||
PropFrameCount | ||
PropFormat | ||
PropMode | ||
PropBrightness | ||
PropContrast | ||
PropSaturation | ||
PropHue | ||
PropGain | ||
PropExposure | ||
PropConvertRgb | ||
PropWhiteBalanceU | ||
PropRectification | ||
PropMonocrome | ||
PropSharpness | ||
PropAutoExposure | ||
PropGamma | ||
PropTemperature | ||
PropTrigger | ||
PropTriggerDelay | ||
PropWhiteBalanceV | ||
PropZoom | ||
PropFocus | ||
PropGuid | ||
PropIsoSpeed | ||
PropMaxDc1394 | ||
PropBacklight | ||
PropPan | ||
PropTilt | ||
PropRoll | ||
PropIris | ||
PropSettings | ||
PropBuffersize | ||
) | ||
|
||
// Camera represents camera. | ||
type Camera struct { | ||
Index int | ||
camera *opencv.Capture | ||
} | ||
|
||
// NewCamera returns new Camera for given camera index. | ||
func NewCamera(index int) (camera *Camera, err error) { | ||
camera = &Camera{} | ||
camera.Index = index | ||
|
||
camera.camera = opencv.NewCameraCapture(index) | ||
if camera.camera == nil { | ||
err = fmt.Errorf("camera: can not open camera %d", index) | ||
} | ||
|
||
return | ||
} | ||
|
||
// Read reads next frame from camera and returns image. | ||
func (c *Camera) Read() (img image.Image, err error) { | ||
if c.camera.GrabFrame() { | ||
frame := c.camera.RetrieveFrame(1) | ||
img = frame.ToImage() | ||
} else { | ||
err = fmt.Errorf("camera: can not grab frame") | ||
} | ||
|
||
return | ||
} | ||
|
||
// GetProperty returns the specified camera property. | ||
func (c *Camera) GetProperty(id int) float64 { | ||
return c.camera.GetProperty(id) | ||
} | ||
|
||
// SetProperty sets a camera property. | ||
func (c *Camera) SetProperty(id int, value float64) int { | ||
return c.camera.SetProperty(id, value) | ||
} | ||
|
||
// Close closes camera. | ||
func (c *Camera) Close() (err error) { | ||
if c.camera == nil { | ||
err = fmt.Errorf("camera: camera is not opened") | ||
} | ||
|
||
c.camera.Release() | ||
c.camera = nil | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package camera | ||
|
||
import ( | ||
"fmt" | ||
"image/jpeg" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestCamera(t *testing.T) { | ||
camera, err := NewCamera(1) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
defer camera.Close() | ||
|
||
tmpdir, err := ioutil.TempDir(os.TempDir(), "cam2ip") | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
defer os.RemoveAll(tmpdir) | ||
|
||
var width, height float64 = 640, 480 | ||
camera.SetProperty(PropFrameWidth, width) | ||
camera.SetProperty(PropFrameHeight, height) | ||
|
||
if camera.GetProperty(PropFrameWidth) != width { | ||
t.Error("FrameWidth not correct") | ||
} | ||
|
||
if camera.GetProperty(PropFrameHeight) != height { | ||
t.Error("FrameHeight not correct") | ||
} | ||
|
||
var i int | ||
var n int = 10 | ||
|
||
timeout := time.After(time.Duration(n) * time.Second) | ||
|
||
for { | ||
select { | ||
case <-timeout: | ||
//fmt.Printf("Fps: %d\n", i/n) | ||
return | ||
default: | ||
i += 1 | ||
|
||
img, err := camera.Read() | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
file, err := os.Create(filepath.Join(tmpdir, fmt.Sprintf("%03d.jpg", i))) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
err = jpeg.Encode(file, img, &jpeg.Options{Quality: 75}) | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
|
||
err = file.Close() | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package camera | ||
|
||
import ( | ||
"image" | ||
//"image/jpeg" | ||
"io" | ||
|
||
jpeg "github.com/kjk/golibjpegturbo" | ||
) | ||
|
||
// NewEncoder returns a new Encoder. | ||
func NewEncoder(w io.Writer) *Encoder { | ||
return &Encoder{w} | ||
} | ||
|
||
// Encoder struct. | ||
type Encoder struct { | ||
w io.Writer | ||
} | ||
|
||
// Encode encodes image to JPEG. | ||
func (e Encoder) Encode(img image.Image) error { | ||
err := jpeg.Encode(e.w, img, &jpeg.Options{Quality: 75}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.