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

View File

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

View File

@ -13,6 +13,9 @@ type Stream struct {
r io.ReadSeeker r io.ReadSeeker
idx int idx int
timeScale int64
duration int64
muxer *Muxer muxer *Muxer
sample *atom.SampleTable sample *atom.SampleTable
@ -35,7 +38,12 @@ type Stream struct {
sttsEntry *atom.TimeToSampleEntry sttsEntry *atom.TimeToSampleEntry
cttsEntry *atom.CompositionOffsetEntry cttsEntry *atom.CompositionOffsetEntry
writeMdat func([]byte) (int64, error) 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)
}