patterngoMinor
Webcam frame splitter
Viewed 0 times
webcamframesplitter
Problem
I wrote a camera streaming app for pizero.
Since the pizero is too weak to do any video encoding I am using it to just capture usb webcam frames (mjpeg format) and forward them over udp to a powerful pc that does the video encoding.
When the light conditions are low there is a lot of noise introduced to the frames and they grow in size, overflowing the udp write size limit.
To tackle the issue I wrote a func that splits the frame in parts and forwards the pieces to the encoder.
What I am looking for in this review is the following:
Performance - App runs on pizero where resources are limited. I am using buffered channels and I am not sure if I implemented them correctly.
Best practices
Hidden pitfalls - If any, point out if I shot myself in the foot.
Code contains the whole camera implementation plus the server side.
Please review both.
My programming level is beginner. This is my first project.
Camera:
```
package main
import (
"bytes"
"fmt"
"log"
"math"
"net"
"os/exec"
"sync"
"time"
"labix.org/v2/mgo/bson"
)
const (
FFMPEG_ENCODER = "192.168.178.200:8000"
CAM_ADDR = ":5000"
PACKET = 60000
)
type msg struct {
Fragment bool
FragmentID int
LastFragment bool
Data []byte
}
type reporting struct {
Fps int
Size int
Fragments float64
Encoding time.Duration
Writing time.Duration
}
func main() {
conn, err := udpDial()
if err != nil {
log.Fatal(err)
}
var stderr bytes.Buffer
//bash script with commands for interfacing with the camera.
//script outputs to stdout.
cmd := exec.Command("./v4l2")
pipe, _ := cmd.StdoutPipe()
defer pipe.Close()
cmd.Stderr = &stderr
if err := cmd.Start(); err != nil {
fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
}
//pizero - has issues serializing.
buffer := make(chan [][]byte, 500)
var wg sync.WaitGroup
var sta
Since the pizero is too weak to do any video encoding I am using it to just capture usb webcam frames (mjpeg format) and forward them over udp to a powerful pc that does the video encoding.
When the light conditions are low there is a lot of noise introduced to the frames and they grow in size, overflowing the udp write size limit.
To tackle the issue I wrote a func that splits the frame in parts and forwards the pieces to the encoder.
What I am looking for in this review is the following:
Performance - App runs on pizero where resources are limited. I am using buffered channels and I am not sure if I implemented them correctly.
Best practices
Hidden pitfalls - If any, point out if I shot myself in the foot.
Code contains the whole camera implementation plus the server side.
Please review both.
My programming level is beginner. This is my first project.
Camera:
```
package main
import (
"bytes"
"fmt"
"log"
"math"
"net"
"os/exec"
"sync"
"time"
"labix.org/v2/mgo/bson"
)
const (
FFMPEG_ENCODER = "192.168.178.200:8000"
CAM_ADDR = ":5000"
PACKET = 60000
)
type msg struct {
Fragment bool
FragmentID int
LastFragment bool
Data []byte
}
type reporting struct {
Fps int
Size int
Fragments float64
Encoding time.Duration
Writing time.Duration
}
func main() {
conn, err := udpDial()
if err != nil {
log.Fatal(err)
}
var stderr bytes.Buffer
//bash script with commands for interfacing with the camera.
//script outputs to stdout.
cmd := exec.Command("./v4l2")
pipe, _ := cmd.StdoutPipe()
defer pipe.Close()
cmd.Stderr = &stderr
if err := cmd.Start(); err != nil {
fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
}
//pizero - has issues serializing.
buffer := make(chan [][]byte, 500)
var wg sync.WaitGroup
var sta
Solution
Readability
To ease the readability (and testability) of your code, I would recommend you to split it in multiple functions communicating via multiple channels.
For instance, for the client:
Your
With this approach, you will need a fixed amount of goroutines (instead of starting a new one for each frame:
which might qualify as "I shot myself in the foot").
Statistics
Regarding the statistics, if see multiple possibilities:
-
Performance
If you need to make your code faster, you will need to identify the bottlenecks. For this, I recommend you to profile your code : https://blog.golang.org/profiling-go-programs
To ease the readability (and testability) of your code, I would recommend you to split it in multiple functions communicating via multiple channels.
For instance, for the client:
func getOutput(command string) (io.ReadCloser, error) // to launch the v4l2
func readFrames(in io.ReadCloser, out <-chan Frame)
func splitFrames(in chan<- Frame, out <-chan Fragment)
func sendFragments(in <-chan Fragment)Your
main would then consist of creating the different channels and launching those functions as goroutines (except for getOutput).With this approach, you will need a fixed amount of goroutines (instead of starting a new one for each frame:
go processFrame(frame, buffer, &statistic),which might qualify as "I shot myself in the foot").
Statistics
Regarding the statistics, if see multiple possibilities:
- pass the object as a variable (current usage)
- or make it a global variable
- or make it a channel of
Report(the signification ofValuedepends on theOperation):
-
type Report struct {
Operation string
Value int
Duration time.Duration
}Performance
If you need to make your code faster, you will need to identify the bottlenecks. For this, I recommend you to profile your code : https://blog.golang.org/profiling-go-programs
- Add the code
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")...
- transfer the
*.profilefile to your computer
- analyze the function calls
Code Snippets
func getOutput(command string) (io.ReadCloser, error) // to launch the v4l2
func readFrames(in io.ReadCloser, out <-chan Frame)
func splitFrames(in chan<- Frame, out <-chan Fragment)
func sendFragments(in <-chan Fragment)type Report struct {
Operation string
Value int
Duration time.Duration
}Context
StackExchange Code Review Q#159710, answer score: 3
Revisions (0)
No revisions yet.