}
func (t *FlvDecoder) CutSeed(reader io.Reader, startT, duration time.Duration, w io.Writer, seeker io.Seeker, getIndex func(seedTo time.Duration) (int64, error)) (err error) {
- bufSize := humanize.KByte * 1100
buf := make([]byte, humanize.KByte*500)
buff := slice.New[byte]()
over := false
}
for c := 0; err == nil && !over; c++ {
- if buff.Size() < bufSize {
- n, e := reader.Read(buf)
- if n == 0 && errors.Is(e, io.EOF) {
- return io.EOF
- }
- err = buff.Append(buf[:n])
- continue
+ n, e := reader.Read(buf)
+ if n == 0 && errors.Is(e, io.EOF) {
+ return io.EOF
}
+ err = buff.Append(buf[:n])
if !t.init {
if frontBuf, dropOffset, e := t.InitFlv(buff.GetPureBuf()); e != nil {
} else {
if dropOffset != 0 {
_ = buff.RemoveFront(dropOffset)
- } else {
- bufSize *= 2
}
if len(frontBuf) == 0 {
continue
}
seek = true
startTM = 0
- buff.Clear()
+ buff.Reset()
}
- if dropOffset, e := t.oneF(buff.GetPureBuf(), wf); e != nil {
- return perrors.New(e.Error(), ActionOneFFlv)
- } else {
- if dropOffset != 0 {
- _ = buff.RemoveFront(dropOffset)
+ for {
+ if dropOffset, e := t.oneF(buff.GetPureBuf(), wf); e != nil {
+ return perrors.New(e.Error(), ActionOneFFlv)
} else {
- bufSize *= 2
+ if dropOffset != 0 {
+ _ = buff.RemoveFront(dropOffset)
+ } else {
+ break
+ }
}
}
}
}
func (t *FlvDecoder) GenFastSeed(reader io.Reader, save func(seedTo time.Duration, cuIndex int64) error) (err error) {
- bufSize := humanize.KByte * 1100
totalRead := 0
buf := make([]byte, humanize.KByte*500)
buff := slice.New[byte]()
firstFT := -1
for c := 0; err == nil && !over; c++ {
- if buff.Size() < bufSize {
- n, e := reader.Read(buf)
- if n == 0 && errors.Is(e, io.EOF) {
- return io.EOF
- }
- totalRead += n
- err = buff.Append(buf[:n])
- continue
+ n, e := reader.Read(buf)
+ if n == 0 && errors.Is(e, io.EOF) {
+ return io.EOF
}
+ totalRead += n
+ err = buff.Append(buf[:n])
if !t.init {
if frontBuf, dropOffset, e := t.InitFlv(buff.GetPureBuf()); e != nil {
} else {
if dropOffset != 0 {
_ = buff.RemoveFront(dropOffset)
- } else {
- bufSize *= 2
}
if len(frontBuf) == 0 {
continue
}
}
} else {
- if dropOffset, e := t.oneF(buff.GetPureBuf(), func(t, index int, buf []byte) error {
- if firstFT == -1 {
- firstFT = t
- }
- if e := save(time.Millisecond*time.Duration(t-firstFT), int64(totalRead-buff.Size()+index)); e != nil {
- return perrors.Join(ActionGenFastSeedFlv, e)
- }
- return nil
- }); e != nil {
- return perrors.Join(ActionGenFastSeedFlv, ActionOneFFlv, e)
- } else {
- if dropOffset != 0 {
- _ = buff.RemoveFront(dropOffset)
+ for {
+ if dropOffset, e := t.oneF(buff.GetPureBuf(), func(t, index int, buf []byte) error {
+ if firstFT == -1 {
+ firstFT = t
+ }
+ if e := save(time.Millisecond*time.Duration(t-firstFT), int64(totalRead-buff.Size()+index)); e != nil {
+ return perrors.Join(ActionGenFastSeedFlv, e)
+ }
+ return nil
+ }); e != nil {
+ return perrors.Join(ActionGenFastSeedFlv, ActionOneFFlv, e)
} else {
- bufSize *= 2
+ if dropOffset != 0 {
+ _ = buff.RemoveFront(dropOffset)
+ } else {
+ break
+ }
}
}
}
return
}
-type dealFMp4 func(t float64, index int, buf *slice.Buf[byte]) error
+type dealFMp4 func(t float64, index int, re io.Reader) error
func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
if len(buf) > humanize.MByte*100 {
return 0, ErrMisTraks
}
- t.buflock.Lock()
- defer t.buflock.Unlock()
-
- t.buf.Reset()
+ sbuf := slice.NewSliceIndexNoLock(buf)
defer func() {
if err != nil {
var (
haveKeyframe bool
- bufModified = t.buf.GetModified()
+ bufModified = sbuf.GetModified()
// maxSequenceNumber int //有时并不是单调增加
maxVT float64
maxAT float64
}
dropKeyFrame = func(index int) {
- t.buf.Reset()
+ sbuf.Reset()
haveKeyframe = false
cu = index
}
}
}
- // fmt.Println(ts.getT(), "frame0", keyframeMoof, t.buf.size(), m[0].i, m[6].n, m[6].e)
-
//deal frame
if keyframeMoof {
- if v, e := t.buf.HadModified(bufModified); e == nil && v && !t.buf.IsEmpty() {
+ if v, e := sbuf.HadModified(bufModified); e == nil && v && !sbuf.IsEmpty() {
if haveKeyframe && len(w) > 0 {
- err = w[0](video.getT(), cu, t.buf)
+ err = w[0](video.getT(), cu, sbuf)
dropKeyFrame(m[0].i)
return ErrNormal
}
cu = m[6].e
}
if haveKeyframe {
- if e := t.buf.Append(buf[m[0].i:m[6].e]); e != nil {
- return e
- }
+ sbuf.Append(m[0].i, m[6].e)
}
return nil
},
//deal frame
if keyframeMoof {
- if v, e := t.buf.HadModified(bufModified); e == nil && v && !t.buf.IsEmpty() {
+ if v, e := sbuf.HadModified(bufModified); e == nil && v && !sbuf.IsEmpty() {
if haveKeyframe && len(w) > 0 {
- err = w[0](video.getT(), cu, t.buf)
+ err = w[0](video.getT(), cu, sbuf)
dropKeyFrame(m[0].i)
return ErrNormal
}
cu = m[10].e
}
if haveKeyframe {
- if e := t.buf.Append(buf[m[0].i:m[10].e]); e != nil {
- return e
- }
- }
- return nil
- },
- },
- },
- )
-
- if errors.Is(err, ErrNormal) {
- err = nil
- }
-
- return
-}
-
-func (t *Fmp4Decoder) oneFNoBuf(buf []byte, w ...dealFMp4) (cu int, err error) {
- if len(buf) > humanize.MByte*100 {
- return 0, ErrBufTooLarge
- }
- if len(t.traks) == 0 {
- return 0, ErrMisTraks
- }
-
- defer func() {
- if err != nil {
- cu = 0
- }
- }()
-
- var (
- haveKeyframe bool
- // bufModified bool
- // maxSequenceNumber int //有时并不是单调增加
- maxVT float64
- maxAT float64
-
- //get timeStamp
- get_timeStamp = func(tfdt int) (ts timeStamp) {
- switch buf[tfdt+8] {
- case 0:
- ts.data = buf[tfdt+16 : tfdt+20]
- ts.timeStamp = int(F.Btoi32(buf, tfdt+16))
- case 1:
- ts.data = buf[tfdt+12 : tfdt+20]
- ts.timeStamp = int(F.Btoi64(buf, tfdt+12))
- }
- return
- }
-
- //get track type
- get_track_type = func(tfhd, tfdt int) (ts timeStamp, handlerType byte) {
- track, ok := t.traks[int(F.Btoi(buf, tfhd+12, 4))]
- if ok {
- ts := get_timeStamp(tfdt)
- // if track.firstTimeStamp == -1 {
- // track.firstTimeStamp = ts.timeStamp
- // }
-
- // ts.firstTimeStamp = track.firstTimeStamp
- ts.handlerType = track.handlerType
- ts.timescale = track.timescale
-
- // if ts.timeStamp > track.lastTimeStamp {
- // track.lastTimeStamp = ts.timeStamp
- // ts.resetTs()
- // }
-
- return ts, track.handlerType
- }
- return
- }
-
- //is SampleEntries error?
- checkSampleEntries = func(trun, mdat int) error {
- if buf[trun+11] == 'b' {
- for i := trun + 24; i < mdat; i += 12 {
- if F.Btoi(buf, i+4, 4) < 1000 {
- return errors.New("find sample size less then 1000")
- }
- }
- }
- return nil
- }
-
- //is t error?
- checkAndSetMaxT = func(ts timeStamp) (err error) {
- switch ts.handlerType {
- case 'v':
- if maxVT == 0 {
- maxVT = ts.getT()
- } else if maxVT == ts.getT() {
- err = ActionCheckTFail.New("equal VT detect")
- } else if maxVT > ts.getT() {
- err = ActionCheckTFail.New("lower VT detect")
- } else {
- maxVT = ts.getT()
- }
- case 'a':
- if maxAT == 0 {
- maxAT = ts.getT()
- } else if maxAT == ts.getT() {
- err = ActionCheckTFail.New("equal AT detect")
- } else if maxAT > ts.getT() {
- err = ActionCheckTFail.New("lower AT detect")
- } else {
- maxAT = ts.getT()
- }
- default:
- }
- return
- }
-
- dropKeyFrame = func(index int) {
- haveKeyframe = false
- cu = index
- }
- )
-
- ies, recycle, e := decode(buf, "moof")
- defer recycle(ies)
- if e != nil {
- return 0, e
- }
-
- var ErrNormal pe.Action = "ErrNormal"
-
- err = deals(ies,
- []dealIE{
- {
- boxNames: []string{"moof", "mfhd", "traf", "tfhd", "tfdt", "trun", "mdat"},
- fs: func(m []ie) error {
- var (
- keyframeMoof = buf[m[5].i+20] == byte(0x02)
- // moofSN = int(F.Btoi(buf, m[1].i+12, 4))
- video timeStamp
- )
-
- {
- ts, handlerType := get_track_type(m[3].i, m[4].i)
- if ts.handlerType == 'v' {
- if e := checkSampleEntries(m[5].i, m[6].i); e != nil {
- //skip
- dropKeyFrame(m[0].e)
- return pe.Join(ErrDecode, e)
- }
- }
- if handlerType == 'v' {
- video = ts
- }
- if e := checkAndSetMaxT(ts); e != nil {
- dropKeyFrame(m[0].e)
- return pe.Join(ErrDecode, e)
- }
- }
-
- // fmt.Println(ts.getT(), "frame0", keyframeMoof, t.buf.size(), m[0].i, m[6].n, m[6].e)
-
- //deal frame
- if keyframeMoof {
- if haveKeyframe && len(w) > 0 {
- err = w[0](video.getT(), cu, nil)
- dropKeyFrame(m[0].i)
- return ErrNormal
- }
- dropKeyFrame(m[0].i)
- haveKeyframe = true
- } else if !haveKeyframe {
- cu = m[6].e
- }
- return nil
- },
- },
- {
- boxNames: []string{"moof", "mfhd", "traf", "tfhd", "tfdt", "trun", "traf", "tfhd", "tfdt", "trun", "mdat"},
- fs: func(m []ie) error {
- var (
- keyframeMoof = buf[m[5].i+20] == byte(0x02) || buf[m[9].i+20] == byte(0x02)
- // moofSN = int(F.Btoi(buf, m[1].i+12, 4))
- video timeStamp
- audio timeStamp
- )
-
- {
- ts, handlerType := get_track_type(m[3].i, m[4].i)
- if handlerType == 'v' {
- if e := checkSampleEntries(m[5].i, m[6].i); e != nil {
- //skip
- dropKeyFrame(m[0].e)
- return pe.Join(ErrDecode, e)
- }
- }
- switch handlerType {
- case 'v':
- video = ts
- case 's':
- audio = ts
- }
- if e := checkAndSetMaxT(ts); e != nil {
- dropKeyFrame(m[0].e)
- return pe.Join(ErrDecode, e)
- }
- }
- {
- ts, handlerType := get_track_type(m[7].i, m[8].i)
- if handlerType == 'v' {
- if e := checkSampleEntries(m[9].i, m[10].i); e != nil {
- //skip
- dropKeyFrame(m[0].e)
- return pe.Join(ErrDecode, e)
- }
- }
- switch handlerType {
- case 'v':
- video = ts
- case 's':
- audio = ts
- }
- if e := checkAndSetMaxT(ts); e != nil {
- dropKeyFrame(m[0].e)
- return pe.Join(ErrDecode, e)
- }
- }
-
- //sync audio timeStamp
- if t.AVTDiff <= 0.1 {
- t.AVTDiff = 0.1
- }
- if diff := math.Abs(video.getT() - audio.getT()); diff > t.AVTDiff {
- return pe.Join(ErrDecode, fmt.Errorf("时间戳不匹配 %v %v (或许应调整fmp4音视频时间戳容差s>%.2f)", video.timeStamp, audio.timeStamp, diff))
- // copy(video.data, F.Itob64(int64(audio.getT()*float64(video.timescale))))
- }
-
- //deal frame
- if keyframeMoof {
- if haveKeyframe && len(w) > 0 {
- err = w[0](video.getT(), cu, nil)
- dropKeyFrame(m[0].i)
- return ErrNormal
- }
- dropKeyFrame(m[0].i)
- haveKeyframe = true
- } else if !haveKeyframe {
- cu = m[10].e
+ sbuf.Append(m[0].i, m[10].e)
}
return nil
},
func (t *Fmp4Decoder) CutSeed(reader io.Reader, startT, duration time.Duration, w io.Writer, seeker io.Seeker, getIndex func(seedTo time.Duration) (int64, error)) (err error) {
buf := make([]byte, humanize.MByte*3)
- buff := slice.New[byte]()
init := false
seek := false
over := false
durationM := duration.Seconds()
firstFT := -1.0
- wf := func(t float64, index int, buf *slice.Buf[byte]) (e error) {
+ t.buflock.Lock()
+ defer t.buflock.Unlock()
+ t.buf.Reset()
+
+ wf := func(t float64, index int, re io.Reader) (e error) {
if firstFT == -1 {
firstFT = t
}
cu := t - firstFT
over = duration != 0 && cu > durationM+startTM
if startTM <= cu && !over {
- _, e = w.Write(buf.GetPureBuf())
+ _, e = io.Copy(w, re)
}
return
}
if n == 0 && errors.Is(e, io.EOF) {
return io.EOF
}
- err = buff.Append(buf[:n])
+ err = t.buf.Append(buf[:n])
if !init {
- if frontBuf, e := t.Init_fmp4(buff.GetPureBuf()); e != nil {
+ if frontBuf, e := t.Init_fmp4(t.buf.GetPureBuf()); e != nil {
return pe.New(e.Error(), ActionInitFmp4)
} else {
if len(frontBuf) == 0 {
}
seek = true
startTM = 0
- buff.Clear()
+ t.buf.Reset()
}
for {
- if dropOffset, e := t.oneF(buff.GetPureBuf(), wf); e != nil {
+ if dropOffset, e := t.oneF(t.buf.GetPureBuf(), wf); e != nil {
return pe.New(e.Error(), ActionOneFFmp4)
} else {
if dropOffset != 0 {
- _ = buff.RemoveFront(dropOffset)
+ _ = t.buf.RemoveFront(dropOffset)
} else {
break
}
}
} else {
for {
- if dropOffset, e := t.oneFNoBuf(t.buf.GetPureBuf(), func(ts float64, index int, _ *slice.Buf[byte]) error {
+ if dropOffset, e := t.oneF(t.buf.GetPureBuf(), func(ts float64, index int, _ io.Reader) error {
if firstFT == -1 {
firstFT = ts
}