Skip to content

Instantly share code, notes, and snippets.

@castaneai
Last active July 4, 2020 10:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save castaneai/269c651fbc6d2ac7f4147b722bb0275a to your computer and use it in GitHub Desktop.
Save castaneai/269c651fbc6d2ac7f4147b722bb0275a to your computer and use it in GitHub Desktop.
mp4 parsing

要約

+ pinf
|
+--+ schi
   |
   +-- user
   +-- cert
   +-- righ
   +-- name
   +-- chtb

調べる方法

mp4dump [MP4FILE]

[ftyp] size=8+24
  major_brand = M4A 
  minor_version = 0
  compatible_brand = M4A 
  compatible_brand = mp42
  compatible_brand = isom
  compatible_brand = 
[moov] size=8+75216
  [mvhd] size=12+96
 ...

手動でバイナリを読むのに参考になったコード

https://github.com/abema/go-mp4

special padding とかまじかよ・・・。。このソースコード見てなかったら後数時間なやんでただろう https://github.com/SteveMarshall/mp4-quicktime/blob/master/atom.py#L33

package main
import (
"log"
"os"
"encoding/binary"
"encoding/hex"
"io"
"fmt"
)
// atomName => padding size
var boxAtomPaddings = map[string]int64{
"moov": 0,
"trak": 0,
"mdia": 0,
"minf": 0,
"stsd": 8,
"stbl": 0,
"mp4a": 28,
}
func main() {
f, err := os.Open("a.m4a")
if err != nil {
log.Fatalln(err)
}
dumper := hex.Dumper(os.Stdout)
defer dumper.Close()
if _, err := readAllAtoms(f); err != nil {
log.Fatalln(err)
}
}
type Atom struct {
Name string
DataStartPos int64
DataLen int64
Children map[string]*Atom
}
func readAllAtoms(r io.ReadSeeker) (map[string]*Atom, error) {
atoms := make(map[string]*Atom)
for {
atom, err := readAtom(r)
if err != nil {
if err != io.EOF {
return nil, err
}
break
}
atoms[atom.Name] = atom
}
return atoms, nil
}
func readAtom(r io.ReadSeeker) (*Atom, error) {
var length uint32
if err := binary.Read(r, binary.BigEndian, &length); err != nil {
return nil, err
}
nameb := make([]byte, 4)
if err := binary.Read(r, binary.BigEndian, &nameb); err != nil {
return nil, err
}
name := string(nameb)
startPos, err := r.Seek(0, io.SeekCurrent)
if err != nil {
return nil, err
}
dataLen := int64(length - 8)
catoms := make(map[string]*Atom)
pad, isBox := boxAtomPaddings[name]
if isBox {
r.Seek(pad, io.SeekCurrent)
for {
catom, err := readAtom(r)
if err != nil {
return nil, err
}
catoms[catom.Name] = catom
cur, err := r.Seek(0, io.SeekCurrent)
if err != nil {
return nil, err
}
if cur >= startPos + dataLen {
break
}
}
} else {
if _, err := r.Seek(dataLen, io.SeekCurrent); err != nil {
return nil, err
}
}
fmt.Printf("%s (start: %d, len: %d)\n", name, startPos, dataLen)
return &Atom {
Name: name,
DataStartPos: startPos,
DataLen: dataLen,
Children: catoms,
}, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment