Enhance video resolution handling by adding model-specific logic and updating subtype parsing
This commit is contained in:
@@ -188,6 +188,7 @@ func buildStreamURL(cam *wyze.Camera) string {
|
||||
query.Set("uid", cam.P2PID)
|
||||
query.Set("enr", cam.ENR)
|
||||
query.Set("mac", cam.MAC)
|
||||
query.Set("model", cam.ProductModel)
|
||||
|
||||
if cam.DTLS == 1 {
|
||||
query.Set("dtls", "true")
|
||||
|
||||
+84
-13
@@ -15,10 +15,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
FrameSize1080P = 0
|
||||
FrameSize360P = 1
|
||||
FrameSize720P = 2
|
||||
FrameSize2K = 3
|
||||
FrameSize1080P = 0
|
||||
FrameSize360P = 1
|
||||
FrameSize720P = 2
|
||||
FrameSize2K = 3
|
||||
FrameSizeFloodlight = 4
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -51,6 +52,8 @@ const (
|
||||
KCmdAuthSuccess = 10009
|
||||
KCmdControlChannel = 10010
|
||||
KCmdControlChannelResp = 10011
|
||||
KCmdSetResolutionDB = 10052
|
||||
KCmdSetResolutionDBRes = 10053
|
||||
KCmdSetResolution = 10056
|
||||
KCmdSetResolutionResp = 10057
|
||||
)
|
||||
@@ -58,10 +61,11 @@ const (
|
||||
type Client struct {
|
||||
conn *tutk.Conn
|
||||
|
||||
host string
|
||||
uid string
|
||||
enr string
|
||||
mac string
|
||||
host string
|
||||
uid string
|
||||
enr string
|
||||
mac string
|
||||
model string
|
||||
|
||||
authKey string
|
||||
verbose bool
|
||||
@@ -99,6 +103,7 @@ func Dial(rawURL string) (*Client, error) {
|
||||
uid: query.Get("uid"),
|
||||
enr: query.Get("enr"),
|
||||
mac: query.Get("mac"),
|
||||
model: query.Get("model"),
|
||||
verbose: query.Get("verbose") == "true",
|
||||
}
|
||||
|
||||
@@ -148,20 +153,44 @@ func (c *Client) GetBackchannelCodec() (codecID uint16, sampleRate uint32, chann
|
||||
return c.audioCodecID, c.audioSampleRate, c.audioChannels
|
||||
}
|
||||
|
||||
func (c *Client) SetResolution(sd bool) error {
|
||||
func (c *Client) SetResolution(quality byte) error {
|
||||
var frameSize uint8
|
||||
var bitrate uint16
|
||||
|
||||
if sd {
|
||||
switch quality {
|
||||
case 0: // Auto/HD - use model's best
|
||||
frameSize = c.hdFrameSize()
|
||||
bitrate = BitrateMax
|
||||
case FrameSize360P: // 1 = SD/360P
|
||||
frameSize = FrameSize360P
|
||||
bitrate = BitrateSD
|
||||
} else {
|
||||
frameSize = FrameSize2K
|
||||
case FrameSize720P: // 2 = 720P
|
||||
frameSize = FrameSize720P
|
||||
bitrate = BitrateMax
|
||||
case FrameSize2K: // 3 = 2K
|
||||
if c.is2K() {
|
||||
frameSize = FrameSize2K
|
||||
} else {
|
||||
frameSize = c.hdFrameSize()
|
||||
}
|
||||
bitrate = BitrateMax
|
||||
case FrameSizeFloodlight: // 4 = Floodlight
|
||||
frameSize = c.hdFrameSize()
|
||||
bitrate = BitrateMax
|
||||
default:
|
||||
frameSize = quality
|
||||
bitrate = BitrateMax
|
||||
}
|
||||
|
||||
if c.verbose {
|
||||
fmt.Printf("[Wyze] SetResolution: sd=%v frameSize=%d bitrate=%d\n", sd, frameSize, bitrate)
|
||||
fmt.Printf("[Wyze] SetResolution: quality=%d frameSize=%d bitrate=%d model=%s\n", quality, frameSize, bitrate, c.model)
|
||||
}
|
||||
|
||||
// Use K10052 (doorbell format) for certain models
|
||||
if c.useDoorbellResolution() {
|
||||
k10052 := c.buildK10052(frameSize, bitrate)
|
||||
_, err := c.conn.WriteAndWaitIOCtrl(KCmdSetResolutionDB, k10052, KCmdSetResolutionDBRes, 5*time.Second)
|
||||
return err
|
||||
}
|
||||
|
||||
k10056 := c.buildK10056(frameSize, bitrate)
|
||||
@@ -379,6 +408,18 @@ func (c *Client) buildK10010(mediaType byte, enabled bool) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
func (c *Client) buildK10052(frameSize uint8, bitrate uint16) []byte {
|
||||
b := make([]byte, 22)
|
||||
copy(b, "HL") // magic
|
||||
b[2] = 5 // version
|
||||
binary.LittleEndian.PutUint16(b[4:], KCmdSetResolutionDB) // 10052
|
||||
binary.LittleEndian.PutUint16(b[6:], 6) // payload len
|
||||
binary.LittleEndian.PutUint16(b[16:], bitrate) // bitrate (2 bytes)
|
||||
b[18] = frameSize + 1 // frame size (1 byte)
|
||||
// b[19] = fps, b[20:22] = zeros
|
||||
return b
|
||||
}
|
||||
|
||||
func (c *Client) buildK10056(frameSize uint8, bitrate uint16) []byte {
|
||||
b := make([]byte, 21)
|
||||
copy(b, "HL") // magic
|
||||
@@ -493,3 +534,33 @@ func (c *Client) parseK10009(data []byte) (*AuthResponse, error) {
|
||||
|
||||
return &AuthResponse{}, nil
|
||||
}
|
||||
|
||||
func (c *Client) useDoorbellResolution() bool {
|
||||
switch c.model {
|
||||
case "WYZEDB3", "WVOD1", "HL_WCO2", "WYZEC1":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Client) hdFrameSize() uint8 {
|
||||
if c.isFloodlight() {
|
||||
return FrameSizeFloodlight
|
||||
}
|
||||
if c.is2K() {
|
||||
return FrameSize2K
|
||||
}
|
||||
return FrameSize1080P
|
||||
}
|
||||
|
||||
func (c *Client) is2K() bool {
|
||||
switch c.model {
|
||||
case "HL_CAM3P", "HL_PANP", "HL_CAM4", "HL_DB2", "HL_CFL2":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Client) isFloodlight() bool {
|
||||
return c.model == "HL_CFL2"
|
||||
}
|
||||
|
||||
+13
-4
@@ -29,9 +29,18 @@ func NewProducer(rawURL string) (*Producer, error) {
|
||||
u, _ := url.Parse(rawURL)
|
||||
query := u.Query()
|
||||
|
||||
sd := query.Get("subtype") == "sd"
|
||||
// 0 = HD (default), 1 = SD/360P, 2 = 720P, 3 = 2K, 4 = Floodlight
|
||||
var quality byte
|
||||
switch s := query.Get("subtype"); s {
|
||||
case "", "hd":
|
||||
quality = 0
|
||||
case "sd":
|
||||
quality = FrameSize360P
|
||||
default:
|
||||
quality = core.ParseByte(s)
|
||||
}
|
||||
|
||||
medias, err := probe(client, sd)
|
||||
medias, err := probe(client, quality)
|
||||
if err != nil {
|
||||
_ = client.Close()
|
||||
return nil, err
|
||||
@@ -132,8 +141,8 @@ func (p *Producer) Start() error {
|
||||
}
|
||||
}
|
||||
|
||||
func probe(client *Client, sd bool) ([]*core.Media, error) {
|
||||
_ = client.SetResolution(sd)
|
||||
func probe(client *Client, quality byte) ([]*core.Media, error) {
|
||||
_ = client.SetResolution(quality)
|
||||
_ = client.SetDeadline(time.Now().Add(core.ProbeTimeout))
|
||||
|
||||
var vcodec, acodec *core.Codec
|
||||
|
||||
Reference in New Issue
Block a user