Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
gen2brain committed Oct 3, 2017
0 parents commit 2ad5743
Show file tree
Hide file tree
Showing 13 changed files with 1,389 additions and 0 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Milan Nikolic <gen2brain@gmail.com>
674 changes: 674 additions & 0 deletions COPYING

Large diffs are not rendered by default.

54 changes: 54 additions & 0 deletions README.md
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
58 changes: 58 additions & 0 deletions cam2ip.go
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)
}
}
104 changes: 104 additions & 0 deletions camera/camera.go
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
}
74 changes: 74 additions & 0 deletions camera/camera_test.go
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)
}
}
}
}
29 changes: 29 additions & 0 deletions camera/encode.go
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
}
Loading

0 comments on commit 2ad5743

Please sign in to comment.