91 lines
1.5 KiB
Go
91 lines
1.5 KiB
Go
// Package h264conf contains a H264 configuration parser.
|
|
package h264conf
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
// Conf is a RTMP H264 configuration.
|
|
type Conf struct {
|
|
SPS []byte
|
|
PPS []byte
|
|
}
|
|
|
|
// Unmarshal decodes a Conf from bytes.
|
|
func (c *Conf) Unmarshal(buf []byte) error {
|
|
if len(buf) < 8 {
|
|
return fmt.Errorf("invalid size 1")
|
|
}
|
|
|
|
pos := 5
|
|
|
|
spsCount := buf[pos] & 0x1F
|
|
pos++
|
|
if spsCount != 1 {
|
|
return fmt.Errorf("sps count != 1 is unsupported")
|
|
}
|
|
|
|
spsLen := int(uint16(buf[pos])<<8 | uint16(buf[pos+1]))
|
|
pos += 2
|
|
if (len(buf) - pos) < spsLen {
|
|
return fmt.Errorf("invalid size 2")
|
|
}
|
|
|
|
c.SPS = buf[pos : pos+spsLen]
|
|
pos += spsLen
|
|
|
|
if (len(buf) - pos) < 3 {
|
|
return fmt.Errorf("invalid size 3")
|
|
}
|
|
|
|
ppsCount := buf[pos]
|
|
pos++
|
|
if ppsCount != 1 {
|
|
return fmt.Errorf("pps count != 1 is unsupported")
|
|
}
|
|
|
|
ppsLen := int(uint16(buf[pos])<<8 | uint16(buf[pos+1]))
|
|
pos += 2
|
|
if (len(buf) - pos) < ppsLen {
|
|
return fmt.Errorf("invalid size")
|
|
}
|
|
|
|
c.PPS = buf[pos : pos+ppsLen]
|
|
|
|
return nil
|
|
}
|
|
|
|
// Marshal encodes a Conf into bytes.
|
|
func (c Conf) Marshal() ([]byte, error) {
|
|
spsLen := len(c.SPS)
|
|
ppsLen := len(c.PPS)
|
|
|
|
buf := make([]byte, 11+spsLen+ppsLen)
|
|
|
|
buf[0] = 1
|
|
buf[1] = c.SPS[1]
|
|
buf[2] = c.SPS[2]
|
|
buf[3] = c.SPS[3]
|
|
buf[4] = 3 | 0xFC
|
|
buf[5] = 1 | 0xE0
|
|
pos := 6
|
|
|
|
buf[pos] = byte(spsLen >> 8)
|
|
buf[pos+1] = byte(spsLen)
|
|
pos += 2
|
|
|
|
copy(buf[pos:], c.SPS)
|
|
pos += spsLen
|
|
|
|
buf[pos] = 1
|
|
pos++
|
|
|
|
buf[pos] = byte(ppsLen >> 8)
|
|
buf[pos+1] = byte(ppsLen)
|
|
pos += 2
|
|
|
|
copy(buf[pos:], c.PPS)
|
|
|
|
return buf, nil
|
|
}
|