From 534b11210a82cdd7e3888af8c94aff2ea9f092c9 Mon Sep 17 00:00:00 2001 From: lordwelch Date: Tue, 12 Mar 2019 00:31:34 -0700 Subject: [PATCH] parsed upto the beginning of the playlist --- main.go | 271 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 179 insertions(+), 92 deletions(-) diff --git a/main.go b/main.go index b265322..29df155 100644 --- a/main.go +++ b/main.go @@ -7,8 +7,10 @@ import ( "io" "io/ioutil" "os" + "path/filepath" ) +// User Operation mask table const ( ChapterSearchMask = 1 << iota TimeSearchMask @@ -37,13 +39,20 @@ const ( SelectMenuLanguageMask ) +// Playlist Flags const ( PlaylistRandomAccess = 1 << iota AudioMixApp LosslessMayBypassMixer - // reserved + reserved ) +const ( + IsDifferentAudios = 1 << (iota + 7) + IsSeamlessAngleChange +) + +// MPLS is a struct representing an MPLS file type MPLS struct { Header string playlistStart int @@ -53,51 +62,40 @@ type MPLS struct { Playlist Playlist } +// AppInfoPlaylist sucks type AppInfoPlaylist struct { - Len int - PlaybackType int - PlaybackCount int - UOMask uint64 - AppInfoPlaylistFlags uint16 + Len int + PlaybackType int + PlaybackCount int + UOMask uint64 + PlaylistFlags uint16 } + +// Playlist sucks type Playlist struct { - len int - NumberOfPlayItems uint16 - numberOfSubpaths uint16 - PlayItems PlayItem + len int + playItemCount uint16 + subPathCount uint16 + playItems []PlayItem } -// reserved = 1 << (iota + 7) -const ( - IsDifferentAudios = 1 << (iota + 7) - IsSeamlessAngleChange -) - +// PlayItem contains information about a an item in the playlist type PlayItem struct { - len uint16 - - ClipFile string - ClipID string // M2TS - - // Reserved 11 bits - IsMultiAngle bool // (1 bit) - ConnectionCondition byte // (4 bits) - - STCID byte - InTime uint16 - OutTime uint16 - - UOMask uint64 - - RandomAccessFlag byte // 1 bit - 7 reserved - - StillMode byte - - stillTime uint16 - angleCount byte - AngleFlag byte + len uint16 + clpi CLPI + flags uint16 // multiangle/connection condition + inTime int32 + outTime int32 + UOMask uint64 + RandomAccessFlag byte + stillMode byte + stillTime uint16 + angleCount byte + angleFlags byte + angles []CLPI } +// CLPI contains the filename and the codec ID type CLPI struct { ClipFile string ClipID string // M2TS @@ -105,20 +103,34 @@ type CLPI struct { } func main() { - parse(os.Args[1]) + Mpls, err := Parse(os.Args[1]) + fmt.Println(Mpls) + panic(err) } -func parse(filename string) error { + +// Parse parses an MPLS file into an MPLS struct +func Parse(filename string) (Mpls MPLS, err error) { var ( - buf [10]byte - n int - n64 int64 - Mpls MPLS + file *bytes.Reader + f []byte ) - f, err := ioutil.ReadFile(filename) + + f, err = ioutil.ReadFile(filepath.Clean(filename)) if err != nil { - return err + return MPLS{}, err } - file := bytes.NewReader(f) + 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 { + var ( + buf [10]byte + n int + err error + ) n, err = file.Read(buf[:8]) if err != nil || n != 8 { @@ -126,7 +138,7 @@ func parse(filename string) error { } str := string(buf[:8]) if str[:4] != "MPLS" { - return fmt.Errorf("%s is not an mpls file it must start with 'MPLS' it started with '%s'", filename, str[:4]) + return fmt.Errorf("not an mpls file it must start with 'MPLS' it started with '%s'", str[:4]) } if str[4:8] != "0200" { fmt.Fprintf(os.Stderr, "warning: mpls may not work it is version %s\n", str[4:8]) @@ -135,72 +147,142 @@ func parse(filename string) error { Mpls.Header = str Mpls.playlistStart, err = readInt32(file, buf[:4]) + fmt.Println("int:", Mpls.playlistStart, "binary:", buf[:4]) if err != nil { return err } - fmt.Println("uint:", Mpls.playlistStart, "binary:", buf[:4]) - Mpls.playlistMarkStart, err = readInt32(file, buf[:4]) - if err != nil { - return err - } - fmt.Println("uint:", Mpls.playlistMarkStart, "binary:", buf[:4]) - Mpls.extensionDataStart, err = readInt32(file, buf[:4]) - if err != nil { - return err - } - fmt.Println("uint:", Mpls.extensionDataStart, "binary:", buf[:4]) - n64, err = file.Seek(20, io.SeekCurrent) - if err != nil || n64 != 20 { - return err - } - Mpls.AppInfoPlaylist.Len, err = readInt32(file, buf[:4]) - if err != nil { - return err - } - fmt.Println("uint:", Mpls.AppInfoPlaylist.Len, "binary:", buf[:4]) - n, err = file.Read(buf[:4]) - if err != nil || n != 1 { + Mpls.playlistMarkStart, err = readInt32(file, buf[:4]) + fmt.Println("int:", Mpls.playlistMarkStart, "binary:", buf[:4]) + if err != nil { return err } - Mpls.AppInfoPlaylist.PlaybackType = int(buf[1]) - switch Mpls.AppInfoPlaylist.PlaybackType { - case 2, 3: - Mpls.AppInfoPlaylist.PlaybackCount = int(binary.BigEndian.Uint16(buf[3:4])) - fmt.Println("uint:", Mpls.AppInfoPlaylist.PlaybackCount, "binary:", buf[3:4]) - } - Mpls.AppInfoPlaylist.UOMask, err = readUInt64(file, buf[:8]) - if err != nil || n != 1 { + + Mpls.extensionDataStart, err = readInt32(file, buf[:4]) + fmt.Println("int:", Mpls.extensionDataStart, "binary:", buf[:4]) + if err != nil { return err } - Mpls.AppInfoPlaylist.AppInfoPlaylistFlags, err = readUInt16(file, buf[:2]) - if err != nil || n != 1 { + + _, err = file.Seek(20, io.SeekCurrent) + if err != nil { return err } - err = Mpls.Playlist.parsePlaylist(file, int64(Mpls.playlistStart)) + err = Mpls.AppInfoPlaylist.parse(file) + if err != nil { + return err + } + + _, err = file.Seek(int64(Mpls.playlistStart), io.SeekStart) + if err != nil { + return err + } + + err = Mpls.Playlist.Parse(file) if err != nil { return err } return nil } -func (p Playlist) parsePlaylist(file io.ReadSeeker, PlaylistStart int64) error { +// Parse reads AppInfoPlaylist data from an io.ReadSeeker +func (aip *AppInfoPlaylist) parse(file io.ReadSeeker) error { var ( - n64 int64 - err error buf [10]byte + err error + n int ) - n64, err = file.Seek(PlaylistStart, io.SeekStart) - if err != nil || n64 != 20 { - return err - } - fmt.Println("uint:", PlaylistStart, "binary:", buf[:4]) - p.len, err = readInt32(file, buf[:4]) + aip.Len, err = readInt32(file, buf[:4]) + fmt.Println("int:", aip.Len, "binary:", buf[:4]) if err != nil { return err } - file.Read(buf[:5]) + n, err = file.Read(buf[:4]) + if err != nil || n != 4 { + return err + } + aip.PlaybackType = int(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.UOMask, err = readUInt64(file, buf[:8]) + fmt.Println("int:", aip.UOMask, "binary:", buf[:8]) + if err != nil || n != 1 { + return err + } + aip.PlaylistFlags, err = readUInt16(file, buf[:2]) + fmt.Println("int:", aip.PlaylistFlags, "binary:", buf[:2]) + if err != nil || n != 1 { + return err + } + return nil +} + +// Parse reads Playlist data from an io.ReadSeeker +func (p *Playlist) Parse(file io.ReadSeeker) error { + var ( + buf [10]byte + err error + ) + + p.len, err = readInt32(file, 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[:]) + fmt.Println("int:", p.playItemCount, "binary:", buf[:2]) + if err != nil { + return err + } + p.subPathCount, err = readUInt16(file, 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) + if err != nil { + return err + } + p.playItems = append(p.playItems, item) + } + + return nil +} + +// Parse reads PlayItem data from an io.ReadSeeker +func (pi *PlayItem) Parse(file io.Reader) error { + var ( + buf [10]byte + n int + err error + ) + + pi.len, err = readUInt16(file, 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 + } + str := string(buf[:9]) + if str[5:9] != "M2TS" { + fmt.Fprintf(os.Stderr, "warning: this playlist may be faulty it has a play item that is '%s' not 'M2TS'", str[4:8]) + } + pi.clpi.file = str[:5] + pi.clpi.Codec = str[5:9] + return nil } @@ -213,11 +295,16 @@ func readUInt16(file io.Reader, buf []byte) (uint16, error) { } func readInt32(file io.Reader, buf []byte) (int, error) { + n, err := readUInt32(file, buf) + return int(n), err +} + +func readUInt32(file io.Reader, buf []byte) (uint32, error) { n, err := file.Read(buf[:4]) if err != nil || n != 4 { return 0, err } - return int(binary.BigEndian.Uint32(buf[:4])), nil + return binary.BigEndian.Uint32(buf[:4]), nil } func readUInt64(file io.Reader, buf []byte) (uint64, error) {