Squash integration of the reviewed Go core, frontend audit fixes, release tooling, and deployment hygiene. CI passed all Server/Client jobs.
71 lines
1.9 KiB
Go
71 lines
1.9 KiB
Go
package nativecapture
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"io"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
envelopeHeaderBytes = 28
|
|
maxMediaBytes = 1024 * 1024
|
|
maxStatusBytes = 4 * 1024
|
|
)
|
|
|
|
type FrameKind uint8
|
|
|
|
const (
|
|
FramePCM FrameKind = 1
|
|
FrameH264 FrameKind = 2
|
|
FrameStatus FrameKind = 3
|
|
FrameVP8 FrameKind = 4
|
|
)
|
|
|
|
type Frame struct {
|
|
Kind FrameKind
|
|
KeyFrame bool
|
|
Timestamp time.Duration
|
|
Duration time.Duration
|
|
Data []byte
|
|
}
|
|
|
|
func readFrame(input io.Reader) (Frame, error) {
|
|
header := make([]byte, envelopeHeaderBytes)
|
|
if _, err := io.ReadFull(input, header); err != nil {
|
|
return Frame{}, err
|
|
}
|
|
kind := FrameKind(header[5])
|
|
size := binary.BigEndian.Uint32(header[24:])
|
|
maximum := uint32(maxMediaBytes)
|
|
if kind == FrameStatus {
|
|
maximum = maxStatusBytes
|
|
}
|
|
if string(header[:4]) != "SMED" || header[4] != 1 || header[7] != 0 ||
|
|
(kind != FramePCM && kind != FrameH264 && kind != FrameVP8 && kind != FrameStatus) ||
|
|
size == 0 || size > maximum {
|
|
return Frame{}, errors.New("native capture frame header is invalid")
|
|
}
|
|
timestamp100ns := binary.BigEndian.Uint64(header[8:16])
|
|
duration100ns := binary.BigEndian.Uint64(header[16:24])
|
|
if kind == FrameStatus {
|
|
if header[6] != 0 || timestamp100ns != 0 || duration100ns != 0 {
|
|
return Frame{}, errors.New("native capture status frame is invalid")
|
|
}
|
|
} else if duration100ns == 0 || (kind == FramePCM && header[6] != 0) ||
|
|
((kind == FrameH264 || kind == FrameVP8) && header[6] > 1) {
|
|
return Frame{}, errors.New("native capture media frame is invalid")
|
|
}
|
|
data := make([]byte, size)
|
|
if _, err := io.ReadFull(input, data); err != nil {
|
|
return Frame{}, err
|
|
}
|
|
return Frame{
|
|
Kind: kind,
|
|
KeyFrame: (kind == FrameH264 || kind == FrameVP8) && header[6] == 1,
|
|
Timestamp: time.Duration(timestamp100ns) * 100 * time.Nanosecond,
|
|
Duration: time.Duration(duration100ns) * 100 * time.Nanosecond,
|
|
Data: data,
|
|
}, nil
|
|
}
|