Files
monibuca/plugin/mp4/pkg/box/dinf.go
2025-02-13 10:12:39 +08:00

194 lines
4.0 KiB
Go

package box
import (
"bytes"
"encoding/binary"
"io"
)
var (
TypeURL = BoxType{'u', 'r', 'l', ' '}
TypeURN = BoxType{'u', 'r', 'n', ' '}
)
// aligned(8) class DataEntryUrlBox (bit(24) flags) extends FullBox('url ', version = 0, flags) {
// string location;
// }
// aligned(8) class DataEntryUrnBox (bit(24) flags) extends FullBox('urn ', version = 0, flags) {
// string name;
// string location;
// }
// aligned(8) class DataReferenceBox extends FullBox('dref', version = 0, 0) {
// unsigned int(32) entry_count;
// for (i=1; i <= entry_count; i++) {
// DataEntryBox(entry_version, entry_flags) data_entry;
// }
// }
type DataInformationBox struct {
BaseBox
Dref *DataReferenceBox
}
type DataReferenceBox struct {
FullBox
Entries []IBox
}
type DataEntryUrlBox struct {
FullBox
Location string
}
type DataEntryUrnBox struct {
FullBox
Name string
Location string
}
func CreateDataInformationBox() *DataInformationBox {
dref := CreateDataReferenceBox()
return &DataInformationBox{
BaseBox: BaseBox{
typ: TypeDINF,
size: uint32(BasicBoxLen + dref.size),
},
Dref: dref,
}
}
func CreateDataReferenceBox() *DataReferenceBox {
url := CreateDataEntryUrlBox("")
return &DataReferenceBox{
FullBox: FullBox{
BaseBox: BaseBox{
typ: TypeDREF,
size: uint32(FullBoxLen + 4 + url.size), // 4 for entry_count
},
Version: 0,
Flags: [3]byte{0, 0, 0},
},
Entries: []IBox{url},
}
}
func CreateDataEntryUrlBox(location string) *DataEntryUrlBox {
return &DataEntryUrlBox{
FullBox: FullBox{
BaseBox: BaseBox{
typ: TypeURL,
size: uint32(FullBoxLen + len(location)),
},
Version: 0,
Flags: [3]byte{0, 0, 1}, // self-contained flag
},
Location: location,
}
}
func CreateDataEntryUrnBox(name, location string) *DataEntryUrnBox {
return &DataEntryUrnBox{
FullBox: FullBox{
BaseBox: BaseBox{
typ: TypeURN,
size: uint32(FullBoxLen + len(name) + 1 + len(location)),
},
Version: 0,
Flags: [3]byte{0, 0, 0},
},
Name: name,
Location: location,
}
}
func (box *DataInformationBox) WriteTo(w io.Writer) (n int64, err error) {
return WriteTo(w, box.Dref)
}
func (box *DataInformationBox) Unmarshal(buf []byte) (b IBox, err error) {
b, err = ReadFrom(bytes.NewReader(buf))
if err != nil {
return nil, err
}
if dref, ok := b.(*DataReferenceBox); ok {
box.Dref = dref
}
return box, nil
}
func (box *DataReferenceBox) WriteTo(w io.Writer) (n int64, err error) {
var tmp [4]byte
binary.BigEndian.PutUint32(tmp[:], uint32(len(box.Entries)))
nn, err := w.Write(tmp[:])
if err != nil {
return int64(nn), err
}
n = int64(nn)
for _, entry := range box.Entries {
var en int64
en, err = WriteTo(w, entry)
if err != nil {
return
}
n += en
}
return
}
func (box *DataReferenceBox) Unmarshal(buf []byte) (IBox, error) {
if len(buf) < 4 {
return nil, io.ErrShortBuffer
}
entryCount := binary.BigEndian.Uint32(buf)
r := bytes.NewReader(buf[4:])
box.Entries = make([]IBox, 0, entryCount)
for i := uint32(0); i < entryCount; i++ {
entry, err := ReadFrom(r)
if err != nil {
break
}
box.Entries = append(box.Entries, entry)
}
return box, nil
}
func (box *DataEntryUrlBox) WriteTo(w io.Writer) (n int64, err error) {
if len(box.Location) > 0 {
nn, err := w.Write([]byte(box.Location))
return int64(nn), err
}
return 0, nil
}
func (box *DataEntryUrlBox) Unmarshal(buf []byte) (IBox, error) {
if len(buf) > 0 {
box.Location = string(buf)
}
return box, nil
}
func (box *DataEntryUrnBox) WriteTo(w io.Writer) (n int64, err error) {
nn, err := w.Write([]byte(box.Name + "\x00" + box.Location))
return int64(nn), err
}
func (box *DataEntryUrnBox) Unmarshal(buf []byte) (IBox, error) {
parts := bytes.SplitN(buf, []byte{0}, 2)
if len(parts) > 0 {
box.Name = string(parts[0])
if len(parts) > 1 {
box.Location = string(parts[1])
}
}
return box, nil
}
func init() {
RegisterBox[*DataInformationBox](TypeDINF)
RegisterBox[*DataReferenceBox](TypeDREF)
RegisterBox[*DataEntryUrlBox](TypeURL)
RegisterBox[*DataEntryUrnBox](TypeURN)
}