api change

This commit is contained in:
nareix 2016-04-21 15:58:22 +08:00
parent 3a136cd8f5
commit 7d1af58451
3 changed files with 75 additions and 84 deletions

View File

@ -17,7 +17,7 @@ type Demuxer struct {
}
func (self *Demuxer) Streams() (streams []av.Stream) {
for _, stream := range(self.streams) {
for _, stream := range self.streams {
streams = append(streams, stream)
}
return
@ -69,7 +69,7 @@ func (self *Demuxer) ReadHeader() (err error) {
}
if atrack.Media != nil && atrack.Media.Info != nil && atrack.Media.Info.Sample != nil {
stream.sample = atrack.Media.Info.Sample
stream.SetTimeScale(int64(atrack.Media.Header.TimeScale))
stream.timeScale = int64(atrack.Media.Header.TimeScale)
} else {
err = fmt.Errorf("sample table not found")
return
@ -219,7 +219,7 @@ func (self *Stream) isSampleValid() bool {
return true
}
func (self *Stream) incSampleIndex() {
func (self *Stream) incSampleIndex() (duration int64) {
self.sampleIndexInChunk++
if self.sampleIndexInChunk == self.sample.SampleToChunk.Entries[self.chunkGroupIndex].SamplesPerChunk {
self.chunkIndex++
@ -239,8 +239,9 @@ func (self *Stream) incSampleIndex() {
}
sttsEntry := self.sample.TimeToSample.Entries[self.sttsEntryIndex]
duration = int64(sttsEntry.Duration)
self.sampleIndexInSttsEntry++
self.dts += int64(sttsEntry.Duration)
self.dts += duration
if self.sampleIndexInSttsEntry == sttsEntry.Count {
self.sampleIndexInSttsEntry = 0
self.sttsEntryIndex++
@ -262,6 +263,7 @@ func (self *Stream) incSampleIndex() {
}
self.sampleIndex++
return
}
func (self *Stream) sampleCount() int {
@ -282,33 +284,41 @@ func (self *Stream) sampleCount() int {
}
}
func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
func (self *Demuxer) ReadPacket() (streamIndex int, pkt av.Packet, err error) {
var choose *Stream
for _, stream := range(self.streams) {
if choose == nil || stream.TsToTime(stream.dts) < choose.TsToTime(choose.dts) {
for i, stream := range self.streams {
if choose == nil || stream.tsToTime(stream.dts) < choose.tsToTime(choose.dts) {
choose = stream
streamIndex = i
}
}
if false {
fmt.Printf("ReadPacket: choose index=%v time=%v\n", choose.idx, choose.TsToTime(choose.dts))
fmt.Printf("ReadPacket: choose index=%v time=%v\n", choose.idx, choose.tsToTime(choose.dts))
}
pkt, err = choose.readPacket()
return
}
func (self *Demuxer) Time() (time float64) {
if len(self.streams) > 0 {
stream := self.streams[0]
time = stream.tsToTime(stream.dts)
}
pkt.StreamIdx = choose.idx
pkt.Pts, pkt.Dts, pkt.IsKeyFrame, pkt.Data, err = choose.readSample()
return
}
func (self *Demuxer) SeekToTime(time float64) (err error) {
for _, stream := range(self.streams) {
for _, stream := range self.streams {
if stream.IsVideo() {
if err = stream.seekToTime(time); err != nil {
return
}
time = stream.TsToTime(stream.dts)
time = stream.tsToTime(stream.dts)
break
}
}
for _, stream := range(self.streams) {
for _, stream := range self.streams {
if !stream.IsVideo() {
if err = stream.seekToTime(time); err != nil {
return
@ -319,11 +329,12 @@ func (self *Demuxer) SeekToTime(time float64) (err error) {
return
}
func (self *Stream) readSample() (pts int64, dts int64, isKeyFrame bool, data []byte, err error) {
func (self *Stream) readPacket() (pkt av.Packet, err error) {
if !self.isSampleValid() {
err = io.EOF
return
}
//fmt.Println("readPacket", self.sampleIndex)
chunkOffset := self.sample.ChunkOffset.Entries[self.chunkIndex]
sampleSize := 0
@ -334,54 +345,46 @@ func (self *Stream) readSample() (pts int64, dts int64, isKeyFrame bool, data []
}
sampleOffset := int64(chunkOffset) + self.sampleOffsetInChunk
if _, err = self.r.Seek(int64(sampleOffset), 0); err != nil {
if _, err = self.r.Seek(sampleOffset, 0); err != nil {
return
}
data = make([]byte, sampleSize)
if _, err = self.r.Read(data); err != nil {
pkt.Data = make([]byte, sampleSize)
if _, err = self.r.Read(pkt.Data); err != nil {
return
}
if self.sample.SyncSample != nil {
if self.sample.SyncSample.Entries[self.syncSampleIndex]-1 == self.sampleIndex {
isKeyFrame = true
pkt.IsKeyFrame = true
}
}
//println("pts/dts", self.ptsEntryIndex, self.dtsEntryIndex)
dts = self.dts
if self.sample.CompositionOffset != nil && len(self.sample.CompositionOffset.Entries) > 0 {
pts = self.dts + int64(self.sample.CompositionOffset.Entries[self.cttsEntryIndex].Offset)
} else {
pts = dts
cts := int64(self.sample.CompositionOffset.Entries[self.cttsEntryIndex].Offset)
pkt.CompositionTime = self.tsToTime(cts)
}
self.incSampleIndex()
duration := self.incSampleIndex()
pkt.Duration = self.tsToTime(duration)
return
}
func (self *Stream) duration() float64 {
total := int64(0)
for _, entry := range self.sample.TimeToSample.Entries {
total += int64(entry.Duration * entry.Count)
}
return float64(total) / float64(self.TimeScale())
}
func (self *Stream) seekToTime(time float64) (err error) {
index := self.timeToSampleIndex(time)
if err = self.setSampleIndex(index); err != nil {
return
}
if false {
fmt.Printf("stream[%d]: seekToTime index=%v time=%v cur=%v\n", self.idx, index, time, self.TsToTime(self.dts))
fmt.Printf("stream[%d]: seekToTime index=%v time=%v cur=%v\n", self.idx, index, time, self.tsToTime(self.dts))
}
return
}
func (self *Stream) timeToSampleIndex(time float64) int {
targetTs := self.TimeToTs(time)
targetTs := self.timeToTs(time)
targetIndex := 0
startTs := int64(0)
@ -419,4 +422,3 @@ func (self *Stream) timeToSampleIndex(time float64) int {
return targetIndex
}

View File

@ -4,10 +4,10 @@ import (
"bytes"
"fmt"
"github.com/nareix/av"
"github.com/nareix/codec/aacparser"
"github.com/nareix/codec/h264parser"
"github.com/nareix/mp4/atom"
"github.com/nareix/mp4/isom"
"github.com/nareix/codec/h264parser"
"github.com/nareix/codec/aacparser"
"io"
)
@ -62,6 +62,7 @@ func (self *Muxer) NewStream() av.Stream {
},
}
stream.timeScale = 90000
stream.muxer = self
self.streams = append(self.streams, stream)
@ -69,12 +70,8 @@ func (self *Muxer) NewStream() av.Stream {
}
func (self *Stream) fillTrackAtom() (err error) {
if self.sampleIndex > 0 {
self.sttsEntry.Count++
}
self.trackAtom.Media.Header.TimeScale = int(self.TimeScale())
self.trackAtom.Media.Header.Duration = int(self.lastDts)
self.trackAtom.Media.Header.TimeScale = int(self.timeScale)
self.trackAtom.Media.Header.Duration = int(self.duration)
if self.Type() == av.H264 {
width, height := self.Width(), self.Height()
@ -130,14 +127,6 @@ func (self *Stream) fillTrackAtom() (err error) {
return
}
func (self *Muxer) writeMdat(data []byte) (pos int64, err error) {
if pos, err = self.mdatWriter.Seek(0, 1); err != nil {
return
}
_, err = self.mdatWriter.Write(data)
return
}
func (self *Muxer) WriteHeader() (err error) {
if self.mdatWriter, err = atom.WriteAtomHeader(self.W, "mdat"); err != nil {
return
@ -145,11 +134,12 @@ func (self *Muxer) WriteHeader() (err error) {
return
}
func (self *Muxer) WriteSample(pkt av.Packet) (err error) {
pts, dts, isKeyFrame, frame := pkt.Pts, pkt.Dts, pkt.IsKeyFrame, pkt.Data
stream := self.streams[pkt.StreamIdx]
func (self *Muxer) WritePacket(streamIndex int, pkt av.Packet) (err error) {
stream := self.streams[streamIndex]
frame := pkt.Data
if stream.Type() == av.AAC && aacparser.IsADTSFrame(frame) {
sampleRate := stream.SampleRate()
for len(frame) > 0 {
var payload []byte
var samples int
@ -157,20 +147,21 @@ func (self *Muxer) WriteSample(pkt av.Packet) (err error) {
if _, payload, samples, framelen, err = aacparser.ReadADTSFrame(frame); err != nil {
return
}
delta := int64(samples) * stream.TimeScale() / int64(stream.SampleRate())
pts += delta
dts += delta
frame = frame[framelen:]
if stream.writeSample(pts, dts, isKeyFrame, payload); err != nil {
newpkt := pkt
newpkt.Data = payload
newpkt.Duration = float64(samples)/float64(sampleRate)
if err = stream.writePacket(newpkt); err != nil {
return
}
frame = frame[framelen:]
}
return
}
return stream.writeSample(pts, dts, isKeyFrame, frame)
return stream.writePacket(pkt)
}
func (self *Stream) writeSample(pts int64, dts int64, isKeyFrame bool, data []byte) (err error) {
func (self *Stream) writePacket(pkt av.Packet) (err error) {
var filePos int64
var sampleSize int
@ -179,7 +170,7 @@ func (self *Stream) writeSample(pts int64, dts int64, isKeyFrame bool, data []by
}
if self.Type() == av.H264 {
nalus, _ := h264parser.SplitNALUs(data)
nalus, _ := h264parser.SplitNALUs(pkt.Data)
h264parser.WalkNALUsAVCC(nalus, func(b []byte) {
sampleSize += len(b)
_, err = self.muxer.mdatWriter.Write(b)
@ -188,35 +179,25 @@ func (self *Stream) writeSample(pts int64, dts int64, isKeyFrame bool, data []by
return
}
} else {
sampleSize = len(data)
if _, err = self.muxer.mdatWriter.Write(data); err != nil {
sampleSize = len(pkt.Data)
if _, err = self.muxer.mdatWriter.Write(pkt.Data); err != nil {
return
}
}
if isKeyFrame && self.sample.SyncSample != nil {
if pkt.IsKeyFrame && self.sample.SyncSample != nil {
self.sample.SyncSample.Entries = append(self.sample.SyncSample.Entries, self.sampleIndex+1)
}
if self.sampleIndex > 0 {
if dts <= self.lastDts {
err = fmt.Errorf("dts must be incremental")
return
}
duration := int(dts - self.lastDts)
if self.sttsEntry == nil || duration != self.sttsEntry.Duration {
self.sample.TimeToSample.Entries = append(self.sample.TimeToSample.Entries, atom.TimeToSampleEntry{Duration: duration})
self.sttsEntry = &self.sample.TimeToSample.Entries[len(self.sample.TimeToSample.Entries)-1]
}
self.sttsEntry.Count++
duration := int(self.timeToTs(pkt.Duration))
if self.sttsEntry == nil || duration != self.sttsEntry.Duration {
self.sample.TimeToSample.Entries = append(self.sample.TimeToSample.Entries, atom.TimeToSampleEntry{Duration: duration})
self.sttsEntry = &self.sample.TimeToSample.Entries[len(self.sample.TimeToSample.Entries)-1]
}
self.sttsEntry.Count++
if self.sample.CompositionOffset != nil {
if pts < dts {
err = fmt.Errorf("pts must greater than dts")
return
}
offset := int(pts - dts)
offset := int(self.timeToTs(pkt.CompositionTime))
if self.cttsEntry == nil || offset != self.cttsEntry.Offset {
table := self.sample.CompositionOffset
table.Entries = append(table.Entries, atom.CompositionOffsetEntry{Offset: offset})
@ -225,7 +206,7 @@ func (self *Stream) writeSample(pts int64, dts int64, isKeyFrame bool, data []by
self.cttsEntry.Count++
}
self.lastDts = dts
self.duration += int64(duration)
self.sampleIndex++
self.sample.ChunkOffset.Entries = append(self.sample.ChunkOffset.Entries, int(filePos))
self.sample.SampleSize.Entries = append(self.sample.SampleSize.Entries, sampleSize)
@ -248,7 +229,7 @@ func (self *Muxer) WriteTrailer() (err error) {
if err = stream.fillTrackAtom(); err != nil {
return
}
dur := stream.duration()
dur := stream.tsToTime(stream.duration)
stream.trackAtom.Header.Duration = int(float64(timeScale) * dur)
if dur > maxDur {
maxDur = dur

View File

@ -11,7 +11,10 @@ type Stream struct {
trackAtom *atom.Track
r io.ReadSeeker
idx int
idx int
timeScale int64
duration int64
muxer *Muxer
@ -35,7 +38,12 @@ type Stream struct {
sttsEntry *atom.TimeToSampleEntry
cttsEntry *atom.CompositionOffsetEntry
writeMdat func([]byte) (int64, error)
lastDts int64
}
func (self *Stream) timeToTs(time float64) int64 {
return int64(time * float64(self.timeScale))
}
func (self *Stream) tsToTime(ts int64) float64 {
return float64(ts) / float64(self.timeScale)
}