Split MPLS header into FileType and Version
fixed types on AppInfoPlaylist
Added STNTable to PlayItem and added STNTable parser
Unexported Parse functions on most structs
Combined extraneous reads
Added StreamEntry parser
Added StreamAttributes parser
This commit is contained in:
lordwelch 2019-03-26 23:56:09 -07:00
parent f7141aae07
commit 8f3efef8d6

431
main.go
View File

@ -145,7 +145,8 @@ const (
// MPLS is a struct representing an MPLS file // MPLS is a struct representing an MPLS file
type MPLS struct { type MPLS struct {
Header string FileType string
Version string
PlaylistStart int PlaylistStart int
PlaylistMarkStart int PlaylistMarkStart int
ExtensionDataStart int ExtensionDataStart int
@ -156,8 +157,8 @@ type MPLS struct {
// AppInfoPlaylist sucks // AppInfoPlaylist sucks
type AppInfoPlaylist struct { type AppInfoPlaylist struct {
Len int Len int
PlaybackType int PlaybackType byte
PlaybackCount int PlaybackCount uint16
UOMask uint64 UOMask uint64
PlaylistFlags uint16 PlaylistFlags uint16
} }
@ -184,6 +185,7 @@ type PlayItem struct {
AngleCount byte AngleCount byte
AngleFlags byte AngleFlags byte
Angles []CLPI Angles []CLPI
StreamTable STNTable
} }
// STNTable STream Number Table // STNTable STream Number Table
@ -234,37 +236,78 @@ type CLPI struct {
STCID byte STCID byte
} }
type errReader struct {
RS *bytes.Reader
err error
}
func (er *errReader) Read(p []byte) (n int, err error) {
if er.err != nil {
return 0, er.err
}
n, er.err = er.RS.Read(p)
if n != len(p) {
er.err = fmt.Errorf("%s", "Invalid read")
}
return n, er.err
}
func (er *errReader) Seek(offset int64, whence int) (int64, error) {
if er.err != nil {
return 0, er.err
}
var n64 int64
n64, er.err = er.Seek(offset, whence)
return n64, er.err
}
func main() { func main() {
Mpls, err := Parse(os.Args[1]) var (
file io.Reader
Mpls MPLS
err error
)
file, err = os.Open(filepath.Clean(os.Args[1]))
if err != nil {
panic(err)
}
Mpls, err = Parse(file)
fmt.Println(Mpls) fmt.Println(Mpls)
panic(err) panic(err)
} }
// Parse parses an MPLS file into an MPLS struct // Parse parses an MPLS file into an MPLS struct
func Parse(fiLename string) (Mpls MPLS, err error) { func Parse(reader io.Reader) (Mpls MPLS, err error) {
var ( var (
file *bytes.Reader file []byte
f []byte
) )
f, err = ioutil.ReadFile(filepath.Clean(fiLename)) file, err = ioutil.ReadAll(reader)
if err != nil { if err != nil {
return MPLS{}, err return MPLS{}, err
} }
file = bytes.NewReader(f)
err = Mpls.Parse(file) err = Mpls.Parse(file)
return Mpls, err return Mpls, err
} }
// Parse reads MPLS data from an io.ReadSeeker // Parse reads MPLS data from an io.ReadSeeker #nosec G104
func (Mpls *MPLS) Parse(file io.ReadSeeker) error { func (Mpls *MPLS) Parse(file []byte) error {
var ( var (
buf [10]byte buf [10]byte
n int n int
err error err error
) )
n, err = file.Read(buf[:8]) reader := &errReader{
RS: bytes.NewReader(file),
err: nil,
}
n, err = reader.Read(buf[:8])
if err != nil || n != 8 { if err != nil || n != 8 {
return err return err
} }
@ -276,139 +319,94 @@ func (Mpls *MPLS) Parse(file io.ReadSeeker) error {
fmt.Fprintf(os.Stderr, "warning: mpls may not work it is version %s\n", str[4:8]) fmt.Fprintf(os.Stderr, "warning: mpls may not work it is version %s\n", str[4:8])
} }
Mpls.Header = str Mpls.FileType = str[:4]
Mpls.Version = str[4:8]
Mpls.PlaylistStart, err = readInt32(file, buf[:4]) Mpls.PlaylistStart, _ = readInt32(reader, buf[:])
fmt.Println("int:", Mpls.PlaylistStart, "binary:", buf[:4]) fmt.Println("int:", Mpls.PlaylistStart, "binary:", buf[:4])
if err != nil {
return err
}
Mpls.PlaylistMarkStart, err = readInt32(file, buf[:4]) Mpls.PlaylistMarkStart, _ = readInt32(reader, buf[:])
fmt.Println("int:", Mpls.PlaylistMarkStart, "binary:", buf[:4]) fmt.Println("int:", Mpls.PlaylistMarkStart, "binary:", buf[:4])
if err != nil {
return err
}
Mpls.ExtensionDataStart, err = readInt32(file, buf[:4]) Mpls.ExtensionDataStart, _ = readInt32(reader, buf[:])
fmt.Println("int:", Mpls.ExtensionDataStart, "binary:", buf[:4]) fmt.Println("int:", Mpls.ExtensionDataStart, "binary:", buf[:4])
if err != nil {
return err
}
_, err = file.Seek(20, io.SeekCurrent) reader.Seek(20, io.SeekCurrent)
if err != nil {
return err
}
err = Mpls.AppInfoPlaylist.parse(file)
if err != nil {
return err
}
_, err = file.Seek(int64(Mpls.PlaylistStart), io.SeekStart) Mpls.AppInfoPlaylist.parse(reader)
if err != nil {
return err
}
err = Mpls.Playlist.Parse(file) reader.Seek(int64(Mpls.PlaylistStart), io.SeekStart)
if err != nil {
return err Mpls.Playlist.parse(reader)
}
return nil return reader.err
} }
// Parse reads AppInfoPlaylist data from an io.ReadSeeker // parse reads AppInfoPlaylist data from an *errReader #nosec G104
func (aip *AppInfoPlaylist) parse(file io.ReadSeeker) error { func (aip *AppInfoPlaylist) parse(reader *errReader) error {
var ( var (
buf [10]byte buf [10]byte
err error
n int
) )
aip.Len, err = readInt32(file, buf[:4]) aip.Len, _ = readInt32(reader, buf[:])
fmt.Println("int:", aip.Len, "binary:", buf[:4]) fmt.Println("int:", aip.Len, "binary:", buf[:4])
if err != nil {
return err
}
n, err = file.Read(buf[:4]) reader.Read(buf[:1])
if err != nil || n != 4 {
return err aip.PlaybackType = buf[1]
}
aip.PlaybackType = int(buf[1])
fmt.Println("int:", aip.PlaybackType, "binary:", buf[1]) fmt.Println("int:", aip.PlaybackType, "binary:", buf[1])
aip.PlaybackCount = int(binary.BigEndian.Uint16(buf[2:4])) aip.PlaybackCount, _ = readUInt16(reader, buf[:])
fmt.Println("int:", aip.PlaybackCount, "binary:", buf[2:4]) fmt.Println("int:", aip.PlaybackCount, "binary:", buf[:2])
aip.UOMask, err = readUInt64(file, buf[:8]) aip.UOMask, _ = readUInt64(reader, buf[:])
fmt.Println("int:", aip.UOMask, "binary:", buf[:8]) fmt.Println("int:", aip.UOMask, "binary:", buf[:8])
if err != nil || n != 1 {
return err aip.PlaylistFlags, _ = readUInt16(reader, buf[:])
}
aip.PlaylistFlags, err = readUInt16(file, buf[:2])
fmt.Println("int:", aip.PlaylistFlags, "binary:", buf[:2]) fmt.Println("int:", aip.PlaylistFlags, "binary:", buf[:2])
if err != nil || n != 1 {
return err return reader.err
}
return nil
} }
// Parse reads Playlist data from an io.ReadSeeker // parse reads Playlist data from an *errReader #nosec G104
func (p *Playlist) Parse(file io.ReadSeeker) error { func (p *Playlist) parse(reader *errReader) error {
var ( var (
buf [10]byte buf [10]byte
err error err error
) )
p.Len, err = readInt32(file, buf[:]) p.Len, _ = readInt32(reader, buf[:])
fmt.Println("int:", p.Len, "binary:", buf[:4]) fmt.Println("int:", p.Len, "binary:", buf[:4])
if err != nil {
return err reader.Seek(2, io.SeekCurrent)
}
_, err = file.Seek(2, io.SeekCurrent) p.PlayItemCount, _ = readUInt16(reader, buf[:])
if err != nil {
return err
}
p.PlayItemCount, err = readUInt16(file, buf[:])
fmt.Println("int:", p.PlayItemCount, "binary:", buf[:2]) fmt.Println("int:", p.PlayItemCount, "binary:", buf[:2])
if err != nil {
return err p.SubPathCount, _ = readUInt16(reader, buf[:])
}
p.SubPathCount, err = readUInt16(file, buf[:])
fmt.Println("int:", p.SubPathCount, "binary:", buf[:2]) fmt.Println("int:", p.SubPathCount, "binary:", buf[:2])
if err != nil {
return err
}
for i := 0; i < int(p.PlayItemCount); i++ { for i := 0; i < int(p.PlayItemCount); i++ {
var item PlayItem var item PlayItem
err = item.Parse(file) err = item.parse(reader)
if err != nil { if err != nil {
return err return err
} }
p.PlayItems = append(p.PlayItems, item) p.PlayItems = append(p.PlayItems, item)
} }
return nil return reader.err
} }
// Parse reads PlayItem data from an io.ReadSeeker // parse reads PlayItem data from an *errReader #nosec G104
func (pi *PlayItem) Parse(file io.Reader) error { func (pi *PlayItem) parse(reader *errReader) error {
var ( var (
buf [10]byte buf [10]byte
n int
err error
) )
pi.Len, err = readUInt16(file, buf[:]) pi.Len, _ = readUInt16(reader, buf[:])
fmt.Println("int:", pi.Len, "binary:", buf[:2]) fmt.Println("int:", pi.Len, "binary:", buf[:2])
if err != nil {
return err
}
n, err = file.Read(buf[:9]) reader.Read(buf[:9])
if err != nil || n != 9 {
return err
}
str := string(buf[:9]) str := string(buf[:9])
if str[5:9] != "M2TS" { if str[5:9] != "M2TS" {
@ -417,121 +415,220 @@ func (pi *PlayItem) Parse(file io.Reader) error {
pi.Clpi.ClipFile = str[:5] pi.Clpi.ClipFile = str[:5]
pi.Clpi.ClipID = str[5:9] pi.Clpi.ClipID = str[5:9]
pi.Flags, err = readUInt16(file, buf[:]) pi.Flags, _ = readUInt16(reader, buf[:])
if err != nil {
return err reader.Read(buf[:1])
}
n, err = file.Read(buf[:1])
if err != nil || n != 1 {
return err
}
pi.Clpi.STCID = buf[0] pi.Clpi.STCID = buf[0]
pi.InTime, err = readInt32(file, buf[:]) pi.InTime, _ = readInt32(reader, buf[:])
if err != nil {
return err
}
pi.OutTime, err = readInt32(file, buf[:]) pi.OutTime, _ = readInt32(reader, buf[:])
if err != nil {
return err
}
pi.UOMask, err = readUInt64(file, buf[:]) pi.UOMask, _ = readUInt64(reader, buf[:])
if err != nil {
return err reader.Read(buf[:2])
}
n, err = file.Read(buf[:1])
if err != nil || n != 1 {
return err
}
pi.RandomAccessFlag = buf[0] pi.RandomAccessFlag = buf[0]
n, err = file.Read(buf[:1]) pi.StillMode = buf[1]
if err != nil || n != 1 {
return err
}
pi.StillMode = buf[0]
pi.StillTime, err = readUInt16(file, buf[:]) pi.StillTime, _ = readUInt16(reader, buf[:])
if err != nil {
return err
}
if pi.Flags&1 == 1 { if pi.Flags&1 == 1 {
n, err = file.Read(buf[:1]) reader.Read(buf[:2])
if err != nil || n != 1 {
return err
}
pi.AngleCount = buf[0] pi.AngleCount = buf[0]
n, err = file.Read(buf[:1]) pi.AngleFlags = buf[1]
if err != nil || n != 1 {
return err
}
pi.AngleFlags = buf[0]
for i := 0; i < int(pi.AngleCount); i++ { for i := 0; i < int(pi.AngleCount); i++ {
var angle CLPI var angle CLPI
err = angle.Parse(file) angle.parse(reader)
if err != nil {
return err
}
pi.Angles = append(pi.Angles, angle) pi.Angles = append(pi.Angles, angle)
} }
} }
return nil pi.StreamTable.parse(reader)
return reader.err
} }
// Parse reads angle data from an io.ReadSeeker // parse reads angle data from an *errReader #nosec G104
func (clpi *CLPI) Parse(file io.Reader) error { func (clpi *CLPI) parse(reader *errReader) error {
var ( var (
buf [10]byte buf [10]byte
n int
err error
) )
n, err = file.Read(buf[:9]) reader.Read(buf[:])
if err != nil || n != 9 {
return err
}
str := string(buf[:9]) str := string(buf[:9])
clpi.ClipFile = str[:5] clpi.ClipFile = str[:5]
clpi.ClipID = str[5:9] clpi.ClipID = str[5:9]
n, err = file.Read(buf[:1]) clpi.STCID = buf[9]
if err != nil || n != 1 { return reader.err
return err
}
clpi.STCID = buf[0]
return nil
} }
func readUInt16(file io.Reader, buf []byte) (uint16, error) { // parse reads Stream data from an *errReader #nosec G104
n, err := file.Read(buf[:2]) func (stnt *STNTable) parse(reader *errReader) error {
var (
buf [10]byte
err error
)
stnt.Len, _ = readUInt16(reader, buf[:])
reader.Read(buf[:9])
stnt.PrimaryVideoStreamCount = buf[2]
stnt.PrimaryAudioStreamCount = buf[3]
stnt.PrimaryPGStreamCount = buf[4]
stnt.PrimaryIGStreamCount = buf[5]
stnt.SecondaryAudioStreamCount = buf[6]
stnt.SecondaryVideoStreamCount = buf[7]
stnt.PIPPGStreamCount = buf[8]
reader.Seek(5, io.SeekCurrent)
for i := 0; i < int(stnt.PrimaryVideoStreamCount); i++ {
var stream PrimaryStream
err = stream.parse(reader)
if err != nil {
return err
}
stnt.PrimaryVideoStreams = append(stnt.PrimaryVideoStreams, stream)
}
for i := 0; i < int(stnt.PrimaryAudioStreamCount); i++ {
var stream PrimaryStream
err = stream.parse(reader)
if err != nil {
return err
}
stnt.PrimaryAudioStreams = append(stnt.PrimaryAudioStreams, stream)
}
for i := 0; i < int(stnt.PrimaryIGStreamCount); i++ {
var stream PrimaryStream
err = stream.parse(reader)
if err != nil {
return err
}
stnt.PrimaryIGStreams = append(stnt.PrimaryIGStreams, stream)
}
for i := 0; i < int(stnt.PrimaryAudioStreamCount); i++ {
var stream PrimaryStream
err = stream.parse(reader)
if err != nil {
return err
}
stnt.PrimaryAudioStreams = append(stnt.PrimaryAudioStreams, stream)
}
return reader.err
}
// parse reads Stream data from an *errReader #nosec G104
func (ps *PrimaryStream) parse(reader *errReader) error {
ps.StreamEntry.parse(reader)
ps.StreamAttributes.parse(reader)
return reader.err
}
// parse reads Stream data from an *errReader #nosec G104
func (se *StreamEntry) parse(reader *errReader) error {
var (
buf [10]byte
)
reader.Read(buf[:])
se.Len = buf[0]
se.Type = buf[1]
switch se.Type {
case 1:
se.PID = binary.BigEndian.Uint16(buf[2:4])
case 2, 4:
se.SubPathID = buf[2]
se.SubClipID = buf[3]
se.PID = binary.BigEndian.Uint16(buf[4:6])
case 3:
se.SubPathID = buf[2]
se.PID = binary.BigEndian.Uint16(buf[3:5])
}
return reader.err
}
// parse reads Stream data from an *errReader #nosec G104
func (sa *StreamAttributes) parse(reader *errReader) error {
var (
buf [10]byte
)
reader.Read(buf[:2])
sa.Len = buf[0]
sa.Encoding = buf[1]
switch sa.Encoding {
case VTMPEG1Video, VTMPEG2Video, VTVC1, VTH264:
reader.Read(buf[:1])
sa.Format = buf[0] & 0xf0 >> 4
sa.Rate = buf[0] & 0x0F
case ATMPEG1Audio, ATMPEG2Audio, ATLPCM, ATAC3, ATDTS, ATTRUEHD, ATAC3Plus, ATDTSHD, ATDTSHDMaster:
reader.Read(buf[:4])
sa.Format = buf[0] & 0xf0 >> 4
sa.Rate = buf[0] & 0x0F
sa.Language = string(buf[1:4])
case PresentationGraphics, InteractiveGraphics:
reader.Read(buf[:3])
sa.Language = string(buf[:3])
case TextSubtitle:
reader.Read(buf[:4])
sa.CharacterCode = buf[0]
sa.Language = string(buf[1:4])
default:
fmt.Fprintf(os.Stderr, "warning: unrecognized encoding: '%02X'", sa.Encoding)
}
return reader.err
}
func readUInt16(reader io.Reader, buf []byte) (uint16, error) {
n, err := reader.Read(buf[:2])
if err != nil || n != 2 { if err != nil || n != 2 {
return 0, err return 0, err
} }
return binary.BigEndian.Uint16(buf[:2]), nil return binary.BigEndian.Uint16(buf[:2]), nil
} }
func readInt32(file io.Reader, buf []byte) (int, error) { func readInt32(reader io.Reader, buf []byte) (int, error) {
n, err := readUInt32(file, buf) n, err := readUInt32(reader, buf)
return int(n), err return int(n), err
} }
func readUInt32(file io.Reader, buf []byte) (uint32, error) { func readUInt32(reader io.Reader, buf []byte) (uint32, error) {
n, err := file.Read(buf[:4]) n, err := reader.Read(buf[:4])
if err != nil || n != 4 { if err != nil || n != 4 {
return 0, err return 0, err
} }
return binary.BigEndian.Uint32(buf[:4]), nil return binary.BigEndian.Uint32(buf[:4]), nil
} }
func readUInt64(file io.Reader, buf []byte) (uint64, error) { func readUInt64(reader io.Reader, buf []byte) (uint64, error) {
n, err := file.Read(buf[:8]) n, err := reader.Read(buf[:8])
if err != nil || n != 8 { if err != nil || n != 8 {
return 0, err return 0, err
} }