Skip to content

Instantly share code, notes, and snippets.

@iamtakingiteasy
Created October 17, 2017 20:06
Show Gist options
  • Select an option

  • Save iamtakingiteasy/fb7c605cfd275ea729523a50827ca7c1 to your computer and use it in GitHub Desktop.

Select an option

Save iamtakingiteasy/fb7c605cfd275ea729523a50827ca7c1 to your computer and use it in GitHub Desktop.
package mp4
import (
"encoding/binary"
"fmt"
"io"
)
const (
MaxUint32 = uint64(^uint32(0))
)
var (
Order = binary.BigEndian
)
type Version uint32
func (v Version) String() string {
a := rune((v >> 24) & 0xFF)
b := rune((v >> 16) & 0xFF)
c := rune((v >> 8) & 0xFF)
d := rune(v & 0xFF)
return string([]rune{a, b, c, d})
}
func VersionNew(name string) Version {
if len(name) != 4 {
panic(fmt.Sprintf("Invalid version %s", name))
}
return Version((uint32(name[0]) << 24) | (uint32(name[1]) << 16) | (uint32(name[2]) << 8) | uint32(name[3]))
}
type SerialBox interface {
BoxSerialize(w io.Writer)
BoxDeserialize(r io.Reader)
}
type Box struct {
Size uint32
Name Version
}
func (b *Box) BoxSerialize(w io.Writer) {
binary.Write(w, Order, b.Size)
binary.Write(w, Order, b.Name)
}
func (b *Box) BoxDeserialize(r io.Reader) {
binary.Read(r, Order, &b.Size)
binary.Read(r, Order, &b.Name)
}
func BoxNew(size uint32, name string) *Box {
return &Box{size, VersionNew(name)}
}
func (b *Box) String() string {
return fmt.Sprintf("Box{size=0x%x, name=%v}", b.Size, b.Name)
}
type FullBox struct {
Box
Version uint8
Flags uint32
}
func (b *FullBox) BoxSerialize(w io.Writer) {
b.Box.BoxSerialize(w)
binary.Write(w, Order, (uint32(b.Version)<<24)|b.Flags)
}
func (b *FullBox) BoxDeserialize(r io.Reader) {
b.Box.BoxDeserialize(r)
var tmp uint32
binary.Read(r, Order, &tmp)
b.Version = uint8((tmp >> 24) & 0xFF)
b.Flags = tmp & 0xFFFFFF
}
func FullBoxNew(name string, version uint8, flags uint32) *FullBox {
return &FullBox{Box{12, VersionNew(name)}, version, flags}
}
func (b *FullBox) String() string {
return fmt.Sprintf("FullBox{%s, version=0x%x, flags=0x%x}", b.Box.String(), b.Version, b.Flags)
}
package mp4
import (
"encoding/binary"
"fmt"
"github.com/eientei/videostreamer/util"
"io"
)
type MvhdBox struct {
FullBox
CreationTime uint64
ModificationTime uint64
Timescale uint32
Duration uint64
Rate uint32
Volume uint16
Reserved1 uint16
Reserved2 [2]uint32
Matrix [9]uint32
PreDefined [6]uint32
NextTrackID uint32
}
func (b *MvhdBox) BoxSerialize(w io.Writer) {
b.FullBox.BoxSerialize(w)
if b.FullBox.Version == 0 {
binary.Write(w, Order, uint32(b.CreationTime))
binary.Write(w, Order, uint32(b.ModificationTime))
binary.Write(w, Order, b.Timescale)
binary.Write(w, Order, uint32(b.Duration))
} else {
binary.Write(w, Order, b.CreationTime)
binary.Write(w, Order, b.ModificationTime)
binary.Write(w, Order, b.Timescale)
binary.Write(w, Order, b.Duration)
}
binary.Write(w, Order, b.Rate)
binary.Write(w, Order, b.Volume)
binary.Write(w, Order, b.Reserved1)
for _, r := range b.Reserved2 {
binary.Write(w, Order, r)
}
for _, m := range b.Matrix {
binary.Write(w, Order, m)
}
for _, p := range b.PreDefined {
binary.Write(w, Order, p)
}
binary.Write(w, Order, b.NextTrackID)
}
func (b *MvhdBox) BoxDeserialize(r io.Reader) {
b.FullBox.BoxDeserialize(r)
if b.FullBox.Version == 0 {
var tmp uint32
binary.Read(r, Order, &tmp)
b.CreationTime = uint64(tmp)
binary.Read(r, Order, &tmp)
b.ModificationTime = uint64(tmp)
binary.Read(r, Order, &b.Timescale)
binary.Read(r, Order, &tmp)
b.Duration = uint64(tmp)
} else {
binary.Read(r, Order, &b.CreationTime)
binary.Read(r, Order, &b.ModificationTime)
binary.Read(r, Order, &b.Timescale)
binary.Read(r, Order, &b.Duration)
}
binary.Read(r, Order, &b.Rate)
binary.Read(r, Order, &b.Volume)
binary.Read(r, Order, &b.Reserved1)
for i := 0; i < len(b.Reserved2); i++ {
binary.Read(r, Order, &b.Reserved2[i])
}
for i := 0; i < len(b.Matrix); i++ {
binary.Read(r, Order, &b.Matrix[i])
}
for i := 0; i < len(b.PreDefined); i++ {
binary.Read(r, Order, &b.PreDefined[i])
}
binary.Read(r, Order, &b.NextTrackID)
}
func MvhdBoxNew(version uint8, creationTime uint64, modificationTime uint64, timescale uint32, duration uint64, nextTrackID uint32) *MvhdBox {
var size uint32
if version == 0 {
size = 108
} else {
size = 120
}
return &MvhdBox{FullBox{Box{size, VersionNew("mvhd")}, version, 0}, creationTime, modificationTime, timescale, duration, 0x00010000, 0x0100, 0, [2]uint32{0, 0}, [9]uint32{0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000}, [6]uint32{0, 0, 0, 0, 0, 0}, nextTrackID}
}
func (b *MvhdBox) String() string {
return fmt.Sprintf("MvhdBox{%s, creationTime=0x%x, modificationTime=0x%x, timescale=0x%x, duration=0x%x, rate=0x%x, volume=0x%x, reserved1=0x%x, reserved2=%s, matrix=%s, predefined=%s, nextTrackID=0x%x}", b.FullBox.String(), b.CreationTime, b.ModificationTime, b.Timescale, b.Duration, b.Rate, b.Volume, b.Reserved1, util.RenderHexInts(b.Reserved2), util.RenderHexInts(b.Matrix), util.RenderHexInts(b.PreDefined), b.NextTrackID)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment