add quality slider to webcam and implemented H264
This commit is contained in:
@@ -3,8 +3,12 @@
|
||||
package capture
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/draw"
|
||||
"image/jpeg"
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -117,12 +121,44 @@ func NowWebcam(ctx context.Context, env *rt.Env) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
quality := env.WebcamQuality
|
||||
codec := env.WebcamCodec
|
||||
outFormat := format
|
||||
|
||||
if codec == "h264" && format == "jpeg" && h264Available() {
|
||||
img, err := jpeg.Decode(bytes.NewReader(frameBytes))
|
||||
if err == nil {
|
||||
bounds := img.Bounds()
|
||||
w, h := bounds.Dx(), bounds.Dy()
|
||||
if w%2 != 0 || h%2 != 0 {
|
||||
log.Printf("webcam: h264 skipped for odd dimensions (%dx%d), falling back to jpeg", w, h)
|
||||
} else {
|
||||
rgba := toRGBA(img)
|
||||
if h264Bytes, err := encodeH264Frame(rgba); err == nil && len(h264Bytes) > 0 {
|
||||
frameBytes = h264Bytes
|
||||
outFormat = "h264"
|
||||
} else {
|
||||
log.Printf("webcam: h264 encode failed, falling back to jpeg: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if outFormat == "jpeg" && quality > 0 && quality < 100 {
|
||||
img, err := jpeg.Decode(bytes.NewReader(frameBytes))
|
||||
if err == nil {
|
||||
if reencoded, err := encodeJPEG(img, quality); err == nil {
|
||||
frameBytes = reencoded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frame := wire.Frame{
|
||||
Type: "frame",
|
||||
Header: wire.FrameHeader{
|
||||
Monitor: deviceIndex,
|
||||
FPS: 0,
|
||||
Format: format,
|
||||
Format: outFormat,
|
||||
Webcam: true,
|
||||
},
|
||||
Data: frameBytes,
|
||||
@@ -296,3 +332,13 @@ func closeWebcamLocked() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toRGBA(img image.Image) *image.RGBA {
|
||||
if rgba, ok := img.(*image.RGBA); ok {
|
||||
return rgba
|
||||
}
|
||||
b := img.Bounds()
|
||||
rgba := image.NewRGBA(b)
|
||||
draw.Draw(rgba, b, img, b.Min, draw.Src)
|
||||
return rgba
|
||||
}
|
||||
|
||||
@@ -1579,6 +1579,35 @@ func HandleCommand(ctx context.Context, env *runtime.Env, envelope map[string]in
|
||||
env.WebcamUseMaxFPS = useMax
|
||||
sendCommandResultSafe(env, cmdID, true, "")
|
||||
return nil
|
||||
case "webcam_set_quality":
|
||||
payload, _ := envelope["payload"].(map[string]interface{})
|
||||
quality := 0
|
||||
codec := ""
|
||||
if payload != nil {
|
||||
if q, ok := payloadInt(payload, "quality"); ok {
|
||||
quality = q
|
||||
}
|
||||
if v, ok := payload["codec"].(string); ok {
|
||||
codec = v
|
||||
}
|
||||
}
|
||||
if quality < 0 {
|
||||
quality = 0
|
||||
}
|
||||
if quality > 100 {
|
||||
quality = 100
|
||||
}
|
||||
switch codec {
|
||||
case "jpeg", "h264":
|
||||
// valid
|
||||
default:
|
||||
codec = "jpeg"
|
||||
}
|
||||
env.WebcamQuality = quality
|
||||
env.WebcamCodec = codec
|
||||
log.Printf("webcam: set quality=%d codec=%s", quality, codec)
|
||||
sendCommandResultSafe(env, cmdID, true, "")
|
||||
return nil
|
||||
case "webcam_stop":
|
||||
env.WebcamMu.Lock()
|
||||
log.Printf("webcam: stop requested")
|
||||
|
||||
@@ -37,6 +37,8 @@ type Env struct {
|
||||
WebcamDeviceIndex int
|
||||
WebcamFPS int
|
||||
WebcamUseMaxFPS bool
|
||||
WebcamQuality int
|
||||
WebcamCodec string
|
||||
WebcamCancel context.CancelFunc
|
||||
WebcamDone chan struct{}
|
||||
WebcamMu sync.Mutex
|
||||
|
||||
Reference in New Issue
Block a user