parsed upto the beginning of the playlist

This commit is contained in:
lordwelch 2019-03-12 00:31:34 -07:00
parent c338840e4d
commit 534b11210a

271
main.go
View File

@ -7,8 +7,10 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
) )
// User Operation mask table
const ( const (
ChapterSearchMask = 1 << iota ChapterSearchMask = 1 << iota
TimeSearchMask TimeSearchMask
@ -37,13 +39,20 @@ const (
SelectMenuLanguageMask SelectMenuLanguageMask
) )
// Playlist Flags
const ( const (
PlaylistRandomAccess = 1 << iota PlaylistRandomAccess = 1 << iota
AudioMixApp AudioMixApp
LosslessMayBypassMixer LosslessMayBypassMixer
// reserved reserved
) )
const (
IsDifferentAudios = 1 << (iota + 7)
IsSeamlessAngleChange
)
// MPLS is a struct representing an MPLS file
type MPLS struct { type MPLS struct {
Header string Header string
playlistStart int playlistStart int
@ -53,51 +62,40 @@ type MPLS struct {
Playlist Playlist Playlist Playlist
} }
// AppInfoPlaylist sucks
type AppInfoPlaylist struct { type AppInfoPlaylist struct {
Len int Len int
PlaybackType int PlaybackType int
PlaybackCount int PlaybackCount int
UOMask uint64 UOMask uint64
AppInfoPlaylistFlags uint16 PlaylistFlags uint16
} }
// Playlist sucks
type Playlist struct { type Playlist struct {
len int len int
NumberOfPlayItems uint16 playItemCount uint16
numberOfSubpaths uint16 subPathCount uint16
PlayItems PlayItem playItems []PlayItem
} }
// reserved = 1 << (iota + 7) // PlayItem contains information about a an item in the playlist
const (
IsDifferentAudios = 1 << (iota + 7)
IsSeamlessAngleChange
)
type PlayItem struct { type PlayItem struct {
len uint16 len uint16
clpi CLPI
ClipFile string flags uint16 // multiangle/connection condition
ClipID string // M2TS inTime int32
outTime int32
// Reserved 11 bits UOMask uint64
IsMultiAngle bool // (1 bit) RandomAccessFlag byte
ConnectionCondition byte // (4 bits) stillMode byte
stillTime uint16
STCID byte angleCount byte
InTime uint16 angleFlags byte
OutTime uint16 angles []CLPI
UOMask uint64
RandomAccessFlag byte // 1 bit - 7 reserved
StillMode byte
stillTime uint16
angleCount byte
AngleFlag byte
} }
// CLPI contains the filename and the codec ID
type CLPI struct { type CLPI struct {
ClipFile string ClipFile string
ClipID string // M2TS ClipID string // M2TS
@ -105,20 +103,34 @@ type CLPI struct {
} }
func main() { 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 ( var (
buf [10]byte file *bytes.Reader
n int f []byte
n64 int64
Mpls MPLS
) )
f, err := ioutil.ReadFile(filename)
f, err = ioutil.ReadFile(filepath.Clean(filename))
if err != nil { 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]) n, err = file.Read(buf[:8])
if err != nil || n != 8 { if err != nil || n != 8 {
@ -126,7 +138,7 @@ func parse(filename string) error {
} }
str := string(buf[:8]) str := string(buf[:8])
if str[:4] != "MPLS" { 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" { if str[4:8] != "0200" {
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])
@ -135,72 +147,142 @@ func parse(filename string) error {
Mpls.Header = str Mpls.Header = str
Mpls.playlistStart, err = readInt32(file, buf[:4]) Mpls.playlistStart, err = readInt32(file, buf[:4])
fmt.Println("int:", Mpls.playlistStart, "binary:", buf[:4])
if err != nil { if err != nil {
return err 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]) Mpls.playlistMarkStart, err = readInt32(file, buf[:4])
if err != nil || n != 1 { fmt.Println("int:", Mpls.playlistMarkStart, "binary:", buf[:4])
if err != nil {
return err return err
} }
Mpls.AppInfoPlaylist.PlaybackType = int(buf[1])
switch Mpls.AppInfoPlaylist.PlaybackType { Mpls.extensionDataStart, err = readInt32(file, buf[:4])
case 2, 3: fmt.Println("int:", Mpls.extensionDataStart, "binary:", buf[:4])
Mpls.AppInfoPlaylist.PlaybackCount = int(binary.BigEndian.Uint16(buf[3:4])) if err != nil {
fmt.Println("uint:", Mpls.AppInfoPlaylist.PlaybackCount, "binary:", buf[3:4])
}
Mpls.AppInfoPlaylist.UOMask, err = readUInt64(file, buf[:8])
if err != nil || n != 1 {
return err 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 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 { if err != nil {
return err return err
} }
return nil 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 ( var (
n64 int64
err error
buf [10]byte buf [10]byte
err error
n int
) )
n64, err = file.Seek(PlaylistStart, io.SeekStart) aip.Len, err = readInt32(file, buf[:4])
if err != nil || n64 != 20 { fmt.Println("int:", aip.Len, "binary:", buf[:4])
return err
}
fmt.Println("uint:", PlaylistStart, "binary:", buf[:4])
p.len, err = readInt32(file, buf[:4])
if err != nil { if err != nil {
return err 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 return nil
} }
@ -213,11 +295,16 @@ func readUInt16(file io.Reader, buf []byte) (uint16, error) {
} }
func readInt32(file io.Reader, buf []byte) (int, 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]) n, err := file.Read(buf[:4])
if err != nil || n != 4 { if err != nil || n != 4 {
return 0, err 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) { func readUInt64(file io.Reader, buf []byte) (uint64, error) {