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
type MPLS struct {
Header string
FileType string
Version string
PlaylistStart int
PlaylistMarkStart int
ExtensionDataStart int
@ -156,8 +157,8 @@ type MPLS struct {
// AppInfoPlaylist sucks
type AppInfoPlaylist struct {
Len int
PlaybackType int
PlaybackCount int
PlaybackType byte
PlaybackCount uint16
UOMask uint64
PlaylistFlags uint16
}
@ -184,6 +185,7 @@ type PlayItem struct {
AngleCount byte
AngleFlags byte
Angles []CLPI
StreamTable STNTable
}
// STNTable STream Number Table
@ -234,37 +236,78 @@ type CLPI struct {
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() {
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)
panic(err)
}
// 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 (
file *bytes.Reader
f []byte
file []byte
)
f, err = ioutil.ReadFile(filepath.Clean(fiLename))
file, err = ioutil.ReadAll(reader)
if err != nil {
return MPLS{}, err
}
file = bytes.NewReader(f)
err = Mpls.Parse(file)
return Mpls, err
}
// Parse reads MPLS data from an io.ReadSeeker
func (Mpls *MPLS) Parse(file io.ReadSeeker) error {
// Parse reads MPLS data from an io.ReadSeeker #nosec G104
func (Mpls *MPLS) Parse(file []byte) error {
var (
buf [10]byte
n int
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 {
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])
}
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])
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])
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])
if err != nil {
return err
}
_, err = file.Seek(20, io.SeekCurrent)
if err != nil {
return err
}
err = Mpls.AppInfoPlaylist.parse(file)
if err != nil {
return err
}
reader.Seek(20, io.SeekCurrent)
_, err = file.Seek(int64(Mpls.PlaylistStart), io.SeekStart)
if err != nil {
return err
}
Mpls.AppInfoPlaylist.parse(reader)
err = Mpls.Playlist.Parse(file)
if err != nil {
return err
}
return nil
reader.Seek(int64(Mpls.PlaylistStart), io.SeekStart)
Mpls.Playlist.parse(reader)
return reader.err
}
// Parse reads AppInfoPlaylist data from an io.ReadSeeker
func (aip *AppInfoPlaylist) parse(file io.ReadSeeker) error {
// parse reads AppInfoPlaylist data from an *errReader #nosec G104
func (aip *AppInfoPlaylist) parse(reader *errReader) error {
var (
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])
if err != nil {
return err
}
n, err = file.Read(buf[:4])
if err != nil || n != 4 {
return err
}
aip.PlaybackType = int(buf[1])
reader.Read(buf[:1])
aip.PlaybackType = buf[1]
fmt.Println("int:", aip.PlaybackType, "binary:", buf[1])
aip.PlaybackCount = int(binary.BigEndian.Uint16(buf[2:4]))
fmt.Println("int:", aip.PlaybackCount, "binary:", buf[2:4])
aip.PlaybackCount, _ = readUInt16(reader, buf[:])
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])
if err != nil || n != 1 {
return err
}
aip.PlaylistFlags, err = readUInt16(file, buf[:2])
aip.PlaylistFlags, _ = readUInt16(reader, buf[:])
fmt.Println("int:", aip.PlaylistFlags, "binary:", buf[:2])
if err != nil || n != 1 {
return err
}
return nil
return reader.err
}
// Parse reads Playlist data from an io.ReadSeeker
func (p *Playlist) Parse(file io.ReadSeeker) error {
// parse reads Playlist data from an *errReader #nosec G104
func (p *Playlist) parse(reader *errReader) error {
var (
buf [10]byte
err error
)
p.Len, err = readInt32(file, buf[:])
p.Len, _ = readInt32(reader, buf[:])
fmt.Println("int:", p.Len, "binary:", buf[:4])
if err != nil {
return err
}
_, err = file.Seek(2, io.SeekCurrent)
if err != nil {
return err
}
p.PlayItemCount, err = readUInt16(file, buf[:])
reader.Seek(2, io.SeekCurrent)
p.PlayItemCount, _ = readUInt16(reader, buf[:])
fmt.Println("int:", p.PlayItemCount, "binary:", buf[:2])
if err != nil {
return err
}
p.SubPathCount, err = readUInt16(file, buf[:])
p.SubPathCount, _ = readUInt16(reader, buf[:])
fmt.Println("int:", p.SubPathCount, "binary:", buf[:2])
if err != nil {
return err
}
for i := 0; i < int(p.PlayItemCount); i++ {
var item PlayItem
err = item.Parse(file)
err = item.parse(reader)
if err != nil {
return err
}
p.PlayItems = append(p.PlayItems, item)
}
return nil
return reader.err
}
// Parse reads PlayItem data from an io.ReadSeeker
func (pi *PlayItem) Parse(file io.Reader) error {
// parse reads PlayItem data from an *errReader #nosec G104
func (pi *PlayItem) parse(reader *errReader) error {
var (
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])
if err != nil {
return err
}
n, err = file.Read(buf[:9])
if err != nil || n != 9 {
return err
}
reader.Read(buf[:9])
str := string(buf[:9])
if str[5:9] != "M2TS" {
@ -417,121 +415,220 @@ func (pi *PlayItem) Parse(file io.Reader) error {
pi.Clpi.ClipFile = str[:5]
pi.Clpi.ClipID = str[5:9]
pi.Flags, err = readUInt16(file, buf[:])
if err != nil {
return err
}
pi.Flags, _ = readUInt16(reader, buf[:])
reader.Read(buf[:1])
n, err = file.Read(buf[:1])
if err != nil || n != 1 {
return err
}
pi.Clpi.STCID = buf[0]
pi.InTime, err = readInt32(file, buf[:])
if err != nil {
return err
}
pi.InTime, _ = readInt32(reader, buf[:])
pi.OutTime, err = readInt32(file, buf[:])
if err != nil {
return err
}
pi.OutTime, _ = readInt32(reader, buf[:])
pi.UOMask, err = readUInt64(file, buf[:])
if err != nil {
return err
}
pi.UOMask, _ = readUInt64(reader, buf[:])
reader.Read(buf[:2])
n, err = file.Read(buf[:1])
if err != nil || n != 1 {
return err
}
pi.RandomAccessFlag = buf[0]
n, err = file.Read(buf[:1])
if err != nil || n != 1 {
return err
}
pi.StillMode = buf[0]
pi.StillMode = buf[1]
pi.StillTime, err = readUInt16(file, buf[:])
if err != nil {
return err
}
pi.StillTime, _ = readUInt16(reader, buf[:])
if pi.Flags&1 == 1 {
n, err = file.Read(buf[:1])
if err != nil || n != 1 {
return err
}
reader.Read(buf[:2])
pi.AngleCount = buf[0]
n, err = file.Read(buf[:1])
if err != nil || n != 1 {
return err
}
pi.AngleFlags = buf[0]
pi.AngleFlags = buf[1]
for i := 0; i < int(pi.AngleCount); i++ {
var angle CLPI
err = angle.Parse(file)
if err != nil {
return err
}
angle.parse(reader)
pi.Angles = append(pi.Angles, angle)
}
}
return nil
pi.StreamTable.parse(reader)
return reader.err
}
// Parse reads angle data from an io.ReadSeeker
func (clpi *CLPI) Parse(file io.Reader) error {
// parse reads angle data from an *errReader #nosec G104
func (clpi *CLPI) parse(reader *errReader) error {
var (
buf [10]byte
n int
err error
)
n, err = file.Read(buf[:9])
if err != nil || n != 9 {
return err
}
reader.Read(buf[:])
str := string(buf[:9])
clpi.ClipFile = str[:5]
clpi.ClipID = str[5:9]
n, err = file.Read(buf[:1])
if err != nil || n != 1 {
return err
}
clpi.STCID = buf[0]
return nil
clpi.STCID = buf[9]
return reader.err
}
func readUInt16(file io.Reader, buf []byte) (uint16, error) {
n, err := file.Read(buf[:2])
// parse reads Stream data from an *errReader #nosec G104
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 {
return 0, err
}
return binary.BigEndian.Uint16(buf[:2]), nil
}
func readInt32(file io.Reader, buf []byte) (int, error) {
n, err := readUInt32(file, buf)
func readInt32(reader io.Reader, buf []byte) (int, error) {
n, err := readUInt32(reader, buf)
return int(n), err
}
func readUInt32(file io.Reader, buf []byte) (uint32, error) {
n, err := file.Read(buf[:4])
func readUInt32(reader io.Reader, buf []byte) (uint32, error) {
n, err := reader.Read(buf[:4])
if err != nil || n != 4 {
return 0, err
}
return binary.BigEndian.Uint32(buf[:4]), nil
}
func readUInt64(file io.Reader, buf []byte) (uint64, error) {
n, err := file.Read(buf[:8])
func readUInt64(reader io.Reader, buf []byte) (uint64, error) {
n, err := reader.Read(buf[:8])
if err != nil || n != 8 {
return 0, err
}