vdk/format/fmp4/esio/esio.go
kunmeng 0e65c9d1cc
Some checks failed
CodeQL / Analyze (cpp) (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
将包名改为 git.r-2.top/kunmeng/vdk
2025-01-24 14:45:45 +08:00

163 lines
3.1 KiB
Go

package esio
import (
"errors"
"fmt"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
)
type StreamDescriptor struct {
ESID uint16
DependsOn *uint16
URL *string
OCR *uint16
DecoderConfig *DecoderConfigDescriptor
SLConfig *SLConfigDescriptor
}
// Tag identifies element stream descriptor types
type Tag uint8
// ISO/IEC 14496-1:2004 7.2.2 Table 1
const (
TagForbidden = Tag(iota)
TagObjectDescriptor
TagInitialObjectDescriptor
TagESDescriptor
TagDecoderConfigDescriptor
TagDecoderSpecificInfo
TagSLConfigDescriptor
)
const (
esFlagStreamDependence = 0x80
esFlagURL = 0x40
esFlagOCR = 0x20
)
func ParseStreamDescriptor(start []byte) (desc *StreamDescriptor, remainder []byte, err error) {
// ISO/IEC 14496-1:2004 7.2.6.5.1
tag, d, remainder, err := parseHeader(start)
if err != nil {
err = fmt.Errorf("ES_Descriptor: %w", err)
return
} else if tag != TagESDescriptor {
err = fmt.Errorf("expected ES_Descriptor but got tag %02X", tag)
return
}
desc = &StreamDescriptor{ESID: pio.U16BE(d)}
flags := d[2]
d = d[3:]
if flags&esFlagStreamDependence != 0 {
v := pio.U16BE(d)
desc.DependsOn = &v
d = d[2:]
}
if flags&esFlagURL != 0 {
urlLength := d[0]
v := string(d[1 : 1+urlLength])
desc.URL = &v
d = d[1+urlLength:]
}
if flags&esFlagOCR != 0 {
v := pio.U16BE(d)
desc.OCR = &v
d = d[2:]
}
for len(d) > 0 {
var child []byte
tag, child, d, err = parseHeader(d)
if err != nil {
err = fmt.Errorf("ES_Descriptor: %w", err)
return
}
switch tag {
case TagDecoderConfigDescriptor:
desc.DecoderConfig, err = parseDecoderConfig(child)
case TagSLConfigDescriptor:
desc.SLConfig, err = parseSLConfig(child)
}
if err != nil {
return
}
}
remainder = d
return
}
func (s *StreamDescriptor) Marshal() ([]byte, error) {
var b builder
cursor := b.Descriptor(TagESDescriptor)
b.WriteU16(s.ESID)
var flags uint8
if s.DependsOn != nil {
flags |= esFlagStreamDependence
}
if s.URL != nil {
flags |= esFlagURL
}
if s.OCR != nil {
flags |= esFlagOCR
}
b.WriteByte(flags)
if s.DependsOn != nil {
b.WriteU16(*s.DependsOn)
}
if s.URL != nil {
b.WriteByte(byte(len(*s.URL)))
b.Write([]byte(*s.URL))
}
if s.OCR != nil {
b.WriteU16(*s.OCR)
}
if err := s.DecoderConfig.appendTo(&b); err != nil {
return nil, err
}
if err := s.SLConfig.appendTo(&b); err != nil {
return nil, err
}
cursor.DescriptorDone(-1)
return b.Bytes(), nil
}
func parseLength(start []byte) (length int, d []byte, err error) {
// ISO/IEC 14496-1:2004 8.3.3
d = start
for i := 0; i < 4; i++ {
if len(d) == 0 {
err = errors.New("short tag")
return
}
v := d[0]
d = d[1:]
length <<= 7
length |= int(v & 0x7f)
if v&0x80 == 0 {
break
}
}
return
}
func parseHeader(start []byte) (tag Tag, contents, d []byte, err error) {
d = start
if len(d) < 2 {
err = errors.New("short tag")
return
}
tag = Tag(d[0])
length, d, err := parseLength(d[1:])
if err != nil {
return
}
if length > len(d) {
err = fmt.Errorf("short tag: %02x: expected %d bytes but only got %d", tag, length, len(d))
return
}
contents = d[:length]
d = d[length:]
return
}