parsed upto the beginning of the playlist
This commit is contained in:
parent
c338840e4d
commit
534b11210a
253
main.go
253
main.go
@ -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
|
|
||||||
IsMultiAngle bool // (1 bit)
|
|
||||||
ConnectionCondition byte // (4 bits)
|
|
||||||
|
|
||||||
STCID byte
|
|
||||||
InTime uint16
|
|
||||||
OutTime uint16
|
|
||||||
|
|
||||||
UOMask uint64
|
UOMask uint64
|
||||||
|
RandomAccessFlag byte
|
||||||
RandomAccessFlag byte // 1 bit - 7 reserved
|
stillMode byte
|
||||||
|
|
||||||
StillMode byte
|
|
||||||
|
|
||||||
stillTime uint16
|
stillTime uint16
|
||||||
angleCount byte
|
angleCount byte
|
||||||
AngleFlag byte
|
angleFlags byte
|
||||||
|
angles []CLPI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 (
|
||||||
|
file *bytes.Reader
|
||||||
|
f []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
f, err = ioutil.ReadFile(filepath.Clean(filename))
|
||||||
|
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 {
|
||||||
var (
|
var (
|
||||||
buf [10]byte
|
buf [10]byte
|
||||||
n int
|
n int
|
||||||
n64 int64
|
err error
|
||||||
Mpls MPLS
|
|
||||||
)
|
)
|
||||||
f, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
file := bytes.NewReader(f)
|
|
||||||
|
|
||||||
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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user