add frag atom support

This commit is contained in:
nareix 2016-04-18 00:20:01 +08:00
parent bac553e58e
commit 82b17612dd
3 changed files with 581 additions and 26 deletions

View File

@ -340,6 +340,72 @@ var atoms = {
], ],
}, },
movieFrag: {
cc4: 'moof',
fields: [
['$atoms', [
['header', '*movieFragHeader'],
['tracks', '[]*trackFrag'],
]],
],
},
trackFragDecodeTime: {
cc4: 'tfdt',
},
movieFragHeader: {
cc4: 'mfhd',
fields: [
['version', 'int8'],
['flags', 'int24'],
['seqNum', 'int32'],
],
},
trackFrag: {
cc4: 'traf',
fields: [
['$atoms', [
['header', '*trackFragHeader'],
['decodeTime', '*trackFragDecodeTime'],
['run', '*trackFragRun'],
]],
],
},
trackFragRun: {
cc4: 'trun',
},
trackFragHeader: {
cc4: 'tfhd',
},
/*
// need hand write
trackFragRun: {
cc4: 'trun',
fields: [
['version', 'int8'],
['flags', 'int24'],
['sampleCount', 'int32'],
['dataOffset', 'int32'],
['entries', '[]int32'],
],
},
trackFragHeader: {
cc4: 'tfhd',
fields: [
['version', 'int8'],
['flags', 'int24'],
['id', 'int32'],
['sampleDescriptionIndex', 'int32'],
['_', '[12]byte'],
],
},
*/
}; };
var DeclReadFunc = (opts) => { var DeclReadFunc = (opts) => {

View File

@ -1,15 +1,15 @@
package atom package atom
import ( import (
"io"
"fmt"
"bytes" "bytes"
"fmt"
"io"
"github.com/nareix/bits"
) )
type GolombBitReader struct { type GolombBitReader struct {
R io.Reader R io.Reader
buf [1]byte buf [1]byte
left byte left byte
} }
@ -21,7 +21,7 @@ func (self *GolombBitReader) ReadBit() (res uint, err error) {
self.left = 8 self.left = 8
} }
self.left-- self.left--
res = uint(self.buf[0]>>self.left)&1 res = uint(self.buf[0]>>self.left) & 1
return return
} }
@ -31,7 +31,7 @@ func (self *GolombBitReader) ReadBits(n int) (res uint, err error) {
if bit, err = self.ReadBit(); err != nil { if bit, err = self.ReadBit(); err != nil {
return return
} }
res |= bit<<uint(n-i-1) res |= bit << uint(n-i-1)
} }
return return
} }
@ -51,7 +51,7 @@ func (self *GolombBitReader) ReadExponentialGolombCode() (res uint, err error) {
if res, err = self.ReadBits(i); err != nil { if res, err = self.ReadBits(i); err != nil {
return return
} }
res += (1<<uint(i)) - 1 res += (1 << uint(i)) - 1
return return
} }
@ -59,27 +59,27 @@ func (self *GolombBitReader) ReadSE() (res uint, err error) {
if res, err = self.ReadExponentialGolombCode(); err != nil { if res, err = self.ReadExponentialGolombCode(); err != nil {
return return
} }
if res & 0x01 != 0 { if res&0x01 != 0 {
res = (res+1)/2 res = (res + 1) / 2
} else { } else {
res = -res/2 res = -res / 2
} }
return return
} }
type H264SPSInfo struct { type H264SPSInfo struct {
ProfileIdc uint ProfileIdc uint
LevelIdc uint LevelIdc uint
MbWidth uint MbWidth uint
MbHeight uint MbHeight uint
CropLeft uint CropLeft uint
CropRight uint CropRight uint
CropTop uint CropTop uint
CropBottom uint CropBottom uint
Width uint Width uint
Height uint Height uint
} }
@ -176,7 +176,7 @@ func ParseH264SPS(data []byte) (res *H264SPSInfo, err error) {
} }
} }
// log2_max_frame_num_minus4 // log2_max_frame_num_minus4
if _, err = r.ReadExponentialGolombCode(); err != nil { if _, err = r.ReadExponentialGolombCode(); err != nil {
return return
} }
@ -269,8 +269,8 @@ func ParseH264SPS(data []byte) (res *H264SPSInfo, err error) {
} }
} }
self.Width = (self.MbWidth*16) - self.CropLeft*2 - self.CropRight*2 self.Width = (self.MbWidth * 16) - self.CropLeft*2 - self.CropRight*2
self.Height = ((2-frame_mbs_only_flag)*self.MbHeight*16) - self.CropTop*2 - self.CropBottom*2 self.Height = ((2 - frame_mbs_only_flag) * self.MbHeight * 16) - self.CropTop*2 - self.CropBottom*2
res = self res = self
return return
@ -279,10 +279,10 @@ func ParseH264SPS(data []byte) (res *H264SPSInfo, err error) {
type AVCDecoderConfRecord struct { type AVCDecoderConfRecord struct {
AVCProfileIndication int AVCProfileIndication int
ProfileCompatibility int ProfileCompatibility int
AVCLevelIndication int AVCLevelIndication int
LengthSizeMinusOne int LengthSizeMinusOne int
SPS [][]byte SPS [][]byte
PPS [][]byte PPS [][]byte
} }
func WriteSampleByNALU(w io.Writer, nalu []byte) (size int, err error) { func WriteSampleByNALU(w io.Writer, nalu []byte) (size int, err error) {
@ -327,11 +327,11 @@ func WriteAVCDecoderConfRecord(w io.Writer, self AVCDecoderConfRecord) (err erro
if err = WriteInt(w, self.AVCLevelIndication, 1); err != nil { if err = WriteInt(w, self.AVCLevelIndication, 1); err != nil {
return return
} }
if err = WriteInt(w, self.LengthSizeMinusOne | 0xfc, 1); err != nil { if err = WriteInt(w, self.LengthSizeMinusOne|0xfc, 1); err != nil {
return return
} }
if err = WriteInt(w, len(self.SPS) | 0xe0, 1); err != nil { if err = WriteInt(w, len(self.SPS)|0xe0, 1); err != nil {
return return
} }
for _, data := range self.SPS { for _, data := range self.SPS {
@ -412,3 +412,269 @@ func ReadAVCDecoderConfRecord(r *io.LimitedReader) (self AVCDecoderConfRecord, e
return return
} }
const (
TFHD_BASE_DATA_OFFSET = 0x01
TFHD_STSD_ID = 0x02
TFHD_DEFAULT_DURATION = 0x08
TFHD_DEFAULT_SIZE = 0x10
TFHD_DEFAULT_FLAGS = 0x20
TFHD_DURATION_IS_EMPTY = 0x010000
TFHD_DEFAULT_BASE_IS_MOOF = 0x020000
)
type TrackFragHeader struct {
Version int
Flags int
Id int
DefaultSize int
DefaultDuration int
DefaultFlags int
BaseDataOffset int64
StsdId int
}
func WalkTrackFragHeader(w Walker, self *TrackFragHeader) {
w.StartStruct("TrackFragHeader")
w.Name("Flags")
w.HexInt(self.Flags)
w.Name("Id")
w.Int(self.Id)
w.Name("DefaultDuration")
w.Int(self.DefaultDuration)
w.Name("DefaultSize")
w.Int(self.DefaultSize)
w.Name("DefaultFlags")
w.HexInt(self.DefaultFlags)
w.EndStruct()
}
func WriteTrackFragHeader(w io.WriteSeeker, self *TrackFragHeader) (err error) {
panic("unimplmented")
return
}
func ReadTrackFragHeader(r *io.LimitedReader) (res *TrackFragHeader, err error) {
self := &TrackFragHeader{}
if self.Version, err = ReadInt(r, 1); err != nil {
return
}
if self.Flags, err = ReadInt(r, 3); err != nil {
return
}
if self.Id, err = ReadInt(r, 4); err != nil {
return
}
if self.Flags&TFHD_BASE_DATA_OFFSET != 0 {
if self.BaseDataOffset, err = bits.ReadInt64BE(r, 64); err != nil {
return
}
}
if self.Flags&TFHD_STSD_ID != 0 {
if self.StsdId, err = ReadInt(r, 4); err != nil {
return
}
}
if self.Flags&TFHD_DEFAULT_DURATION != 0 {
if self.DefaultDuration, err = ReadInt(r, 4); err != nil {
return
}
}
if self.Flags&TFHD_DEFAULT_SIZE != 0 {
if self.DefaultSize, err = ReadInt(r, 4); err != nil {
return
}
}
if self.Flags&TFHD_DEFAULT_FLAGS != 0 {
if self.DefaultFlags,err = ReadInt(r, 4); err != nil {
return
}
}
res = self
return
}
const (
TRUN_DATA_OFFSET = 0x01
TRUN_FIRST_SAMPLE_FLAGS = 0x04
TRUN_SAMPLE_DURATION = 0x100
TRUN_SAMPLE_SIZE = 0x200
TRUN_SAMPLE_FLAGS = 0x400
TRUN_SAMPLE_CTS = 0x800
)
type TrackFragRunEntry struct {
Duration int
Size int
Flags int
Cts int
}
type TrackFragRun struct {
Version int
Flags int
FirstSampleFlags int
DataOffset int
Entries []TrackFragRunEntry
}
func WalkTrackFragRun(w Walker, self *TrackFragRun) {
w.StartStruct("TrackFragRun")
w.Name("Flags")
w.HexInt(self.Flags)
w.Name("FirstSampleFlags")
w.HexInt(self.FirstSampleFlags)
w.Name("DataOffset")
w.Int(self.DataOffset)
w.Name("EntriesCount")
w.Int(len(self.Entries))
for i := 0; i < 10 && i < len(self.Entries); i++ {
entry := self.Entries[i]
w.Println(fmt.Sprintf("Entry[%d] Flags=%x Duration=%d Size=%d Cts=%d",
i, entry.Flags, entry.Duration, entry.Size, entry.Cts))
}
w.EndStruct()
}
func WriteTrackFragRun(w io.WriteSeeker, self *TrackFragRun) (err error) {
panic("unimplmented")
return
}
func ReadTrackFragRun(r *io.LimitedReader) (res *TrackFragRun, err error) {
self := &TrackFragRun{}
if self.Version, err = ReadInt(r, 1); err != nil {
return
}
if self.Flags, err = ReadInt(r, 3); err != nil {
return
}
var count int
if count, err = ReadInt(r, 4); err != nil {
return
}
if self.Flags&TRUN_DATA_OFFSET != 0 {
if self.DataOffset, err = ReadInt(r, 4); err != nil {
return
}
}
if self.Flags&TRUN_FIRST_SAMPLE_FLAGS != 0 {
if self.FirstSampleFlags, err = ReadInt(r, 4); err != nil {
return
}
}
for i := 0; i < count; i++ {
var flags int
if i > 0 {
flags = self.Flags
} else {
flags = self.FirstSampleFlags
}
entry := TrackFragRunEntry{}
if flags&TRUN_SAMPLE_DURATION != 0 {
if entry.Duration, err = ReadInt(r, 4); err != nil {
return
}
}
if flags&TRUN_SAMPLE_SIZE != 0 {
if entry.Size, err = ReadInt(r, 4); err != nil {
return
}
}
if flags&TRUN_SAMPLE_FLAGS != 0 {
if entry.Flags, err = ReadInt(r, 4); err != nil {
return
}
}
if flags&TRUN_SAMPLE_CTS != 0 {
if entry.Cts, err = ReadInt(r, 4); err != nil {
return
}
}
self.Entries = append(self.Entries, entry)
}
res = self
return
}
type TrackFragDecodeTime struct {
Version int
Flags int
Time int64
}
func ReadTrackFragDecodeTime(r *io.LimitedReader) (res *TrackFragDecodeTime, err error) {
self := &TrackFragDecodeTime{}
if self.Version, err = ReadInt(r, 1); err != nil {
return
}
if self.Flags, err = ReadInt(r, 3); err != nil {
return
}
if self.Version != 0 {
if self.Time, err = bits.ReadInt64BE(r, 64); err != nil {
return
}
} else {
if self.Time, err = bits.ReadInt64BE(r, 32); err != nil {
return
}
}
res = self
return
}
func WriteTrackFragDecodeTime(w io.WriteSeeker, self *TrackFragDecodeTime) (err error) {
var aw *Writer
if aw, err = WriteAtomHeader(w, "tfdt"); err != nil {
return
}
w = aw
if err = WriteInt(w, self.Version, 1); err != nil {
return
}
if err = WriteInt(w, self.Flags, 3); err != nil {
return
}
if self.Version != 0 {
if err = bits.WriteInt64BE(w, self.Time, 64); err != nil {
return
}
} else {
if err = bits.WriteInt64BE(w, self.Time, 32); err != nil {
return
}
}
if err = aw.Close(); err != nil {
return
}
return
}
func WalkTrackFragDecodeTime(w Walker, self *TrackFragDecodeTime) {
w.StartStruct("TrackFragDecodeTime")
w.Name("Version")
w.Int(self.Version)
w.Name("Flags")
w.Int(self.Flags)
w.Name("Time")
w.Int64(self.Time)
w.EndStruct()
return
}

View File

@ -2475,3 +2475,226 @@ func WalkChunkOffset(w Walker, self *ChunkOffset) {
w.EndStruct() w.EndStruct()
return return
} }
type MovieFrag struct {
Header *MovieFragHeader
Tracks []*TrackFrag
}
func ReadMovieFrag(r *io.LimitedReader) (res *MovieFrag, err error) {
self := &MovieFrag{}
for r.N > 0 {
var cc4 string
var ar *io.LimitedReader
if ar, cc4, err = ReadAtomHeader(r, ""); err != nil {
return
}
switch cc4 {
case "mfhd":
{
if self.Header, err = ReadMovieFragHeader(ar); err != nil {
return
}
}
case "traf":
{
var item *TrackFrag
if item, err = ReadTrackFrag(ar); err != nil {
return
}
self.Tracks = append(self.Tracks, item)
}
}
if _, err = ReadDummy(ar, int(ar.N)); err != nil {
return
}
}
res = self
return
}
func WriteMovieFrag(w io.WriteSeeker, self *MovieFrag) (err error) {
var aw *Writer
if aw, err = WriteAtomHeader(w, "moof"); err != nil {
return
}
w = aw
if self.Header != nil {
if err = WriteMovieFragHeader(w, self.Header); err != nil {
return
}
}
if self.Tracks != nil {
for _, elem := range self.Tracks {
if err = WriteTrackFrag(w, elem); err != nil {
return
}
}
}
if err = aw.Close(); err != nil {
return
}
return
}
func WalkMovieFrag(w Walker, self *MovieFrag) {
w.StartStruct("MovieFrag")
if self.Header != nil {
WalkMovieFragHeader(w, self.Header)
}
for i, item := range self.Tracks {
if w.FilterArrayItem("MovieFrag", "Tracks", i, len(self.Tracks)) {
if item != nil {
WalkTrackFrag(w, item)
}
} else {
w.ArrayLeft(i, len(self.Tracks))
break
}
}
w.EndStruct()
return
}
type MovieFragHeader struct {
Version int
Flags int
SeqNum int
}
func ReadMovieFragHeader(r *io.LimitedReader) (res *MovieFragHeader, err error) {
self := &MovieFragHeader{}
if self.Version, err = ReadInt(r, 1); err != nil {
return
}
if self.Flags, err = ReadInt(r, 3); err != nil {
return
}
if self.SeqNum, err = ReadInt(r, 4); err != nil {
return
}
res = self
return
}
func WriteMovieFragHeader(w io.WriteSeeker, self *MovieFragHeader) (err error) {
var aw *Writer
if aw, err = WriteAtomHeader(w, "mfhd"); err != nil {
return
}
w = aw
if err = WriteInt(w, self.Version, 1); err != nil {
return
}
if err = WriteInt(w, self.Flags, 3); err != nil {
return
}
if err = WriteInt(w, self.SeqNum, 4); err != nil {
return
}
if err = aw.Close(); err != nil {
return
}
return
}
func WalkMovieFragHeader(w Walker, self *MovieFragHeader) {
w.StartStruct("MovieFragHeader")
w.Name("Version")
w.Int(self.Version)
w.Name("Flags")
w.Int(self.Flags)
w.Name("SeqNum")
w.Int(self.SeqNum)
w.EndStruct()
return
}
type TrackFrag struct {
Header *TrackFragHeader
DecodeTime *TrackFragDecodeTime
Run *TrackFragRun
}
func ReadTrackFrag(r *io.LimitedReader) (res *TrackFrag, err error) {
self := &TrackFrag{}
for r.N > 0 {
var cc4 string
var ar *io.LimitedReader
if ar, cc4, err = ReadAtomHeader(r, ""); err != nil {
return
}
switch cc4 {
case "tfhd":
{
if self.Header, err = ReadTrackFragHeader(ar); err != nil {
return
}
}
case "tfdt":
{
if self.DecodeTime, err = ReadTrackFragDecodeTime(ar); err != nil {
return
}
}
case "trun":
{
if self.Run, err = ReadTrackFragRun(ar); err != nil {
return
}
}
}
if _, err = ReadDummy(ar, int(ar.N)); err != nil {
return
}
}
res = self
return
}
func WriteTrackFrag(w io.WriteSeeker, self *TrackFrag) (err error) {
var aw *Writer
if aw, err = WriteAtomHeader(w, "traf"); err != nil {
return
}
w = aw
if self.Header != nil {
if err = WriteTrackFragHeader(w, self.Header); err != nil {
return
}
}
if self.DecodeTime != nil {
if err = WriteTrackFragDecodeTime(w, self.DecodeTime); err != nil {
return
}
}
if self.Run != nil {
if err = WriteTrackFragRun(w, self.Run); err != nil {
return
}
}
if err = aw.Close(); err != nil {
return
}
return
}
func WalkTrackFrag(w Walker, self *TrackFrag) {
w.StartStruct("TrackFrag")
if self.Header != nil {
WalkTrackFragHeader(w, self.Header)
}
if self.DecodeTime != nil {
WalkTrackFragDecodeTime(w, self.DecodeTime)
}
if self.Run != nil {
WalkTrackFragRun(w, self.Run)
}
w.EndStruct()
return
}