]> 127.0.0.1 Git - bili_danmu/.git/commitdiff
Improve 优化mp4切片下载 (#152)
authorqydysky <qydysky@foxmail.com>
Fri, 24 Jan 2025 18:16:59 +0000 (02:16 +0800)
committerGitHub <noreply@github.com>
Fri, 24 Jan 2025 18:16:59 +0000 (02:16 +0800)
* Improve 添加提示fmp4切片下载超时应大于

* Improve 优化mp4切片下载

* Improve 优化fmp4默认参数

Reply/flvDecode.go
Reply/flvDecode_test.go
Reply/fmp4Decode.go
Reply/fmp4Decode_test.go
Reply/stream.go
demo/config/config_K_v.json
go.mod
go.sum

index 068e32f71ecc2451e007f82f08c6ca496abc149f..528f3ae25a3de430da258164db4c067516f473fa 100644 (file)
@@ -35,6 +35,11 @@ var (
        ErrStreamId         = errors.New("ErrStreamId")
        ErrTagSize          = errors.New("ErrTagSize")
        ErrSignLost         = errors.New("ErrSignLost")
+
+       ActionInitFlv     perrors.Action = `InitFlv`
+       ActionGetIndexFlv perrors.Action = `GetIndexFlv`
+       ActionSeekFlv     perrors.Action = `SeekFlv`
+       ActionOneFFlv     perrors.Action = `OneFFlv`
 )
 
 type FlvDecoder struct {
@@ -315,7 +320,7 @@ func (t *FlvDecoder) CutSeed(reader io.Reader, startT, duration time.Duration, w
 
                if !t.init {
                        if frontBuf, dropOffset, e := t.InitFlv(buff.GetPureBuf()); e != nil {
-                               return perrors.New("InitFlv", e.Error())
+                               return perrors.New(e.Error(), ActionInitFlv)
                        } else {
                                if dropOffset != 0 {
                                        _ = buff.RemoveFront(dropOffset)
@@ -331,10 +336,10 @@ func (t *FlvDecoder) CutSeed(reader io.Reader, startT, duration time.Duration, w
                } else {
                        if !seek && seeker != nil && getIndex != nil {
                                if index, e := getIndex(startT); e != nil {
-                                       return perrors.New("s", e.Error())
+                                       return perrors.New(e.Error(), ActionGetIndexFlv)
                                } else {
                                        if _, e := seeker.Seek(index, io.SeekStart); e != nil {
-                                               return perrors.New("s", e.Error())
+                                               return perrors.New(e.Error(), ActionSeekFlv)
                                        }
                                }
                                seek = true
@@ -342,7 +347,7 @@ func (t *FlvDecoder) CutSeed(reader io.Reader, startT, duration time.Duration, w
                                buff.Clear()
                        }
                        if dropOffset, e := t.oneF(buff.GetPureBuf(), wf); e != nil {
-                               return perrors.New("skip", e.Error())
+                               return perrors.New(e.Error(), ActionOneFFlv)
                        } else {
                                if dropOffset != 0 {
                                        _ = buff.RemoveFront(dropOffset)
@@ -376,7 +381,7 @@ func (t *FlvDecoder) GenFastSeed(reader io.Reader, save func(seedTo time.Duratio
 
                if !t.init {
                        if frontBuf, dropOffset, e := t.InitFlv(buff.GetPureBuf()); e != nil {
-                               return perrors.New("InitFlv", e.Error())
+                               return perrors.New(e.Error(), ActionInitFlv)
                        } else {
                                if dropOffset != 0 {
                                        _ = buff.RemoveFront(dropOffset)
@@ -394,7 +399,7 @@ func (t *FlvDecoder) GenFastSeed(reader io.Reader, save func(seedTo time.Duratio
                                }
                                return save(time.Millisecond*time.Duration(t-firstFT), int64(totalRead-buff.Size()+index))
                        }); e != nil {
-                               return perrors.New("skip", e.Error())
+                               return perrors.New(e.Error(), ActionOneFFlv)
                        } else {
                                if dropOffset != 0 {
                                        _ = buff.RemoveFront(dropOffset)
index fb4995115bd41323849e100ddccbce7602a227b6..6e1d1c3b1ac3f96a0b3b477f73709ac618c54842 100644 (file)
@@ -73,19 +73,7 @@ func Test_FLVCut(t *testing.T) {
        }
 
        e := NewFlvDecoder().Cut(f, time.Minute*10, time.Second*20, cutf.File())
-       if perrors.Catch(e, "Read") {
-               t.Log("err Read", e)
-       }
-       if perrors.Catch(e, "InitFlv") {
-               t.Log("err InitFlv", e)
-       }
-       if perrors.Catch(e, "skip") {
-               t.Log("err skip", e)
-       }
-       if perrors.Catch(e, "cutW") {
-               t.Log("err cutW", e)
-       }
-       t.Log(e)
+       t.Log(perrors.ErrorFormat(e))
 }
 
 func Test_FLVGenFastSeed(t *testing.T) {
@@ -108,19 +96,7 @@ func Test_FLVGenFastSeed(t *testing.T) {
        e = NewFlvDecoder().GenFastSeed(f, func(seedTo time.Duration, cuIndex int64) error {
                return sf(seedTo, cuIndex)
        })
-       if perrors.Catch(e, "Read") {
-               t.Log("err Read", e)
-       }
-       if perrors.Catch(e, "InitFlv") {
-               t.Log("err InitFlv", e)
-       }
-       if perrors.Catch(e, "skip") {
-               t.Log("err skip", e)
-       }
-       if perrors.Catch(e, "cutW") {
-               t.Log("err cutW", e)
-       }
-       t.Log(e)
+       t.Log(perrors.ErrorFormat(e))
 }
 
 // 10s-30s 215.815423ms
@@ -154,17 +130,5 @@ func Test_FLVCutSeed(t *testing.T) {
        }
 
        e = NewFlvDecoder().CutSeed(f, time.Minute*10, time.Second*20, cutf.File(), f, gf)
-       if perrors.Catch(e, "Read") {
-               t.Log("err Read", e)
-       }
-       if perrors.Catch(e, "InitFlv") {
-               t.Log("err InitFlv", e)
-       }
-       if perrors.Catch(e, "skip") {
-               t.Log("err skip", e)
-       }
-       if perrors.Catch(e, "cutW") {
-               t.Log("err cutW", e)
-       }
-       t.Log(e)
+       t.Log(perrors.ErrorFormat(e))
 }
index a2bbf897b9e1ef0d7332e6d15e8602220d40bcac..c0418ff8f9a512191ae7e0d4ae07d8336b910ebd 100644 (file)
@@ -10,10 +10,17 @@ import (
 
        "github.com/dustin/go-humanize"
        F "github.com/qydysky/bili_danmu/F"
-       perrors "github.com/qydysky/part/errors"
+       pe "github.com/qydysky/part/errors"
        slice "github.com/qydysky/part/slice"
 )
 
+var (
+       ActionInitFmp4     pe.Action = `InitFmp4`
+       ActionGetIndexFmp4 pe.Action = `GetIndexFmp4`
+       ActionSeekFmp4     pe.Action = `SeekFmp4`
+       ActionOneFFmp4     pe.Action = `OneFFmp4`
+)
+
 var boxs map[string]bool
 
 func init() {
@@ -97,23 +104,24 @@ func (t *Fmp4Decoder) Init_fmp4(buf []byte) (b []byte, err error) {
                return
        }
 
-       err = deal(ies,
-               []string{"ftyp", "moov"},
-               func(m []ie) (bool, error) {
+       err = deal(ies, dealIE{
+               boxNames: []string{"ftyp", "moov"},
+               fs: func(m []ie) error {
                        ftypI = m[0].i
                        ftypE = m[0].e
                        moovI = m[1].i
                        moovE = m[1].e
-                       return true, nil
-               })
+                       return nil
+               },
+       })
 
        if err != nil {
                return nil, err
        }
 
-       err = deal(ies,
-               []string{"tkhd", "mdia", "mdhd", "hdlr"},
-               func(m []ie) (bool, error) {
+       err = deal(ies, dealIE{
+               boxNames: []string{"tkhd", "mdia", "mdhd", "hdlr"},
+               fs: func(m []ie) error {
                        tackId := int(F.Btoi(buf, m[0].i+20, 4))
                        t.traks[tackId] = &trak{
                                trackID: tackId,
@@ -122,8 +130,9 @@ func (t *Fmp4Decoder) Init_fmp4(buf []byte) (b []byte, err error) {
                                timescale:   int(F.Btoi(buf, m[2].i+20, 4)),
                                handlerType: buf[m[3].i+16],
                        }
-                       return false, nil
-               })
+                       return nil
+               },
+       })
 
        if err != nil {
                return nil, err
@@ -251,157 +260,161 @@ func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframe *slice.Buf[byte])
        }
 
        err = deals(ies,
-               [][]string{
-                       {"moof", "mfhd", "traf", "tfhd", "tfdt", "trun", "mdat"},
-                       {"moof", "mfhd", "traf", "tfhd", "tfdt", "trun", "traf", "tfhd", "tfdt", "trun", "mdat"}},
-               []func(m []ie) (bool, error){
-                       func(m []ie) (bool, error) {
-                               var (
-                                       keyframeMoof = buf[m[5].i+20] == byte(0x02)
-                                       // moofSN       = int(F.Btoi(buf, m[1].i+12, 4))
-                               )
-
-                               {
-                                       ts, _ := 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
+               []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))
+                                       )
+
+                                       {
+                                               ts, _ := 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
+                                                               t.buf.Reset()
+                                                               haveKeyframe = false
+                                                               cu = m[0].i
+                                                               return pe.Join(ErrDealIESkip.New(), e)
+                                                       }
+                                               }
+                                               if e := check_set_maxT(ts, func(_ timeStamp) error {
+                                                       return errors.New("skip")
+                                               }, func(_ timeStamp) error {
                                                        t.buf.Reset()
                                                        haveKeyframe = false
                                                        cu = m[0].i
-                                                       return false, e
+                                                       return errors.New("skip")
+                                               }); e != nil {
+                                                       return pe.Join(ErrDealIESkip.New(), e)
                                                }
                                        }
-                                       if e := check_set_maxT(ts, func(_ timeStamp) error {
-                                               return errors.New("skip")
-                                       }, func(_ timeStamp) error {
-                                               t.buf.Reset()
-                                               haveKeyframe = false
-                                               cu = m[0].i
-                                               return errors.New("skip")
-                                       }); e != nil {
-                                               return false, e
-                                       }
-                               }
 
-                               // fmt.Println(ts.getT(), "frame0", keyframeMoof, t.buf.size(), m[0].i, m[6].n, m[6].e)
+                                       // 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 e := t.buf.AppendTo(keyframe); e != nil {
-                                                       return false, e
+                                       //deal frame
+                                       if keyframeMoof {
+                                               if v, e := t.buf.HadModified(bufModified); e == nil && v && !t.buf.IsEmpty() {
+                                                       if e := t.buf.AppendTo(keyframe); e != nil {
+                                                               return pe.Join(ErrDealIEBreak.New(), e)
+                                                       }
+                                                       cu = m[0].i
+                                                       t.buf.Reset()
                                                }
-                                               cu = m[0].i
-                                               t.buf.Reset()
+                                               haveKeyframe = true
+                                       } else if !haveKeyframe {
+                                               cu = m[6].e
                                        }
-                                       haveKeyframe = true
-                               } else if !haveKeyframe {
-                                       cu = m[6].e
-                               }
-                               if haveKeyframe {
-                                       if e := t.buf.Append(buf[m[0].i:m[6].e]); e != nil {
-                                               return false, e
+                                       if haveKeyframe {
+                                               if e := t.buf.Append(buf[m[0].i:m[6].e]); e != nil {
+                                                       return pe.Join(ErrDealIEBreak.New(), e)
+                                               }
                                        }
-                               }
-                               return false, nil
+                                       return nil
+                               },
                        },
-                       func(m []ie) (bool, 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
-                               )
-
-                               // fmt.Println(moofSN, "frame1", keyframeMoof, t.buf.size(), m[0].i, m[10].n, m[10].e)
-
-                               {
-                                       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
+                       {
+                               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
+                                       )
+
+                                       // fmt.Println(moofSN, "frame1", keyframeMoof, t.buf.size(), m[0].i, m[10].n, m[10].e)
+
+                                       {
+                                               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
+                                                               t.buf.Reset()
+                                                               haveKeyframe = false
+                                                               cu = m[0].i
+                                                               return pe.Join(ErrDealIESkip.New(), e)
+                                                       }
+                                               }
+                                               switch handlerType {
+                                               case 'v':
+                                                       video = ts
+                                               case 's':
+                                                       audio = ts
+                                               }
+                                               if e := check_set_maxT(ts, func(_ timeStamp) error {
+                                                       return errors.New("skip")
+                                               }, func(_ timeStamp) error {
                                                        t.buf.Reset()
                                                        haveKeyframe = false
                                                        cu = m[0].i
-                                                       return false, e
+                                                       return errors.New("skip")
+                                               }); e != nil {
+                                                       return pe.Join(ErrDealIESkip.New(), e)
                                                }
                                        }
-                                       switch handlerType {
-                                       case 'v':
-                                               video = ts
-                                       case 's':
-                                               audio = ts
-                                       }
-                                       if e := check_set_maxT(ts, func(_ timeStamp) error {
-                                               return errors.New("skip")
-                                       }, func(_ timeStamp) error {
-                                               t.buf.Reset()
-                                               haveKeyframe = false
-                                               cu = m[0].i
-                                               return errors.New("skip")
-                                       }); e != nil {
-                                               return false, 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
+                                       {
+                                               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
+                                                               t.buf.Reset()
+                                                               haveKeyframe = false
+                                                               cu = m[0].i
+                                                               return pe.Join(ErrDealIESkip.New(), e)
+                                                       }
+                                               }
+                                               switch handlerType {
+                                               case 'v':
+                                                       video = ts
+                                               case 's':
+                                                       audio = ts
+                                               }
+                                               if e := check_set_maxT(ts, func(_ timeStamp) error {
+                                                       return errors.New("skip")
+                                               }, func(_ timeStamp) error {
                                                        t.buf.Reset()
                                                        haveKeyframe = false
                                                        cu = m[0].i
-                                                       return false, e
+                                                       return errors.New("skip")
+                                               }); e != nil {
+                                                       return pe.Join(ErrDealIESkip.New(), e)
                                                }
                                        }
-                                       switch handlerType {
-                                       case 'v':
-                                               video = ts
-                                       case 's':
-                                               audio = ts
+
+                                       //sync audio timeStamp
+                                       if t.AVTDiff <= 0.1 {
+                                               t.AVTDiff = 0.1
                                        }
-                                       if e := check_set_maxT(ts, func(_ timeStamp) error {
-                                               return errors.New("skip")
-                                       }, func(_ timeStamp) error {
-                                               t.buf.Reset()
-                                               haveKeyframe = false
-                                               cu = m[0].i
-                                               return errors.New("skip")
-                                       }); e != nil {
-                                               return false, e
+                                       if diff := math.Abs(video.getT() - audio.getT()); diff > t.AVTDiff {
+                                               return pe.Join(ErrDealIEBreak.New(), fmt.Errorf("时间戳不匹配 %v %v (或许应调整fmp4音视频时间戳容差s>%.2f)", video.timeStamp, audio.timeStamp, diff))
+                                               // copy(video.data, F.Itob64(int64(audio.getT()*float64(video.timescale))))
                                        }
-                               }
-
-                               //sync audio timeStamp
-                               if t.AVTDiff <= 0.1 {
-                                       t.AVTDiff = 0.1
-                               }
-                               if diff := math.Abs(video.getT() - audio.getT()); diff > t.AVTDiff {
-                                       return false, 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 v, e := t.buf.HadModified(bufModified); e == nil && v && !t.buf.IsEmpty() {
-                                               if e := t.buf.AppendTo(keyframe); e != nil {
-                                                       return false, e
+                                       //deal frame
+                                       if keyframeMoof {
+                                               if v, e := t.buf.HadModified(bufModified); e == nil && v && !t.buf.IsEmpty() {
+                                                       if e := t.buf.AppendTo(keyframe); e != nil {
+                                                               return pe.Join(ErrDealIEBreak.New(), e)
+                                                       }
+                                                       cu = m[0].i
+                                                       t.buf.Reset()
                                                }
-                                               cu = m[0].i
-                                               t.buf.Reset()
+                                               haveKeyframe = true
+                                       } else if !haveKeyframe {
+                                               cu = m[10].e
                                        }
-                                       haveKeyframe = true
-                               } else if !haveKeyframe {
-                                       cu = m[10].e
-                               }
-                               if haveKeyframe {
-                                       if e := t.buf.Append(buf[m[0].i:m[10].e]); e != nil {
-                                               return false, e
+                                       if haveKeyframe {
+                                               if e := t.buf.Append(buf[m[0].i:m[10].e]); e != nil {
+                                                       return pe.Join(ErrDealIEBreak.New(), e)
+                                               }
                                        }
-                               }
-                               return false, nil
-                       }})
+                                       return nil
+                               },
+                       },
+               })
        return
 }
 
@@ -511,165 +524,168 @@ func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
                return 0, e
        }
 
-       var ErrNormal = perrors.New("ErrNormal", "ErrNormal")
+       var ErrNormal = pe.New("ErrNormal", "ErrNormal")
 
        err = deals(ies,
-               [][]string{
-                       {"moof", "mfhd", "traf", "tfhd", "tfdt", "trun", "mdat"},
-                       {"moof", "mfhd", "traf", "tfhd", "tfdt", "trun", "traf", "tfhd", "tfdt", "trun", "mdat"}},
-               []func(m []ie) (bool, error){
-                       func(m []ie) (bool, 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
+               []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
+                                                               t.buf.Reset()
+                                                               haveKeyframe = false
+                                                               cu = m[0].i
+                                                               return pe.Join(ErrDealIESkip.New(), e)
+                                                       }
+                                               }
+                                               if handlerType == 'v' {
+                                                       video = ts
+                                               }
+                                               if e := check_set_maxT(ts, func(_ timeStamp) error {
+                                                       return errors.New("skip")
+                                               }, func(_ timeStamp) error {
                                                        t.buf.Reset()
                                                        haveKeyframe = false
                                                        cu = m[0].i
-                                                       return false, e
+                                                       return errors.New("skip")
+                                               }); e != nil {
+                                                       return pe.Join(ErrDealIESkip.New(), e)
                                                }
                                        }
-                                       if handlerType == 'v' {
-                                               video = ts
-                                       }
-                                       if e := check_set_maxT(ts, func(_ timeStamp) error {
-                                               return errors.New("skip")
-                                       }, func(_ timeStamp) error {
-                                               t.buf.Reset()
-                                               haveKeyframe = false
-                                               cu = m[0].i
-                                               return errors.New("skip")
-                                       }); e != nil {
-                                               return false, e
-                                       }
-                               }
 
-                               // fmt.Println(ts.getT(), "frame0", keyframeMoof, t.buf.size(), m[0].i, m[6].n, m[6].e)
+                                       // 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() {
-                                               cu = m[0].i
-                                               if haveKeyframe && len(w) > 0 {
-                                                       err = w[0](video.getT(), cu, t.buf)
+                                       //deal frame
+                                       if keyframeMoof {
+                                               if v, e := t.buf.HadModified(bufModified); e == nil && v && !t.buf.IsEmpty() {
+                                                       cu = m[0].i
+                                                       if haveKeyframe && len(w) > 0 {
+                                                               err = w[0](video.getT(), cu, t.buf)
+                                                               t.buf.Reset()
+                                                               return ErrNormal
+                                                       }
                                                        t.buf.Reset()
-                                                       return true, ErrNormal
                                                }
-                                               t.buf.Reset()
+                                               haveKeyframe = true
+                                       } else if !haveKeyframe {
+                                               cu = m[6].e
                                        }
-                                       haveKeyframe = true
-                               } else if !haveKeyframe {
-                                       cu = m[6].e
-                               }
-                               if haveKeyframe {
-                                       if e := t.buf.Append(buf[m[0].i:m[6].e]); e != nil {
-                                               return false, e
+                                       if haveKeyframe {
+                                               if e := t.buf.Append(buf[m[0].i:m[6].e]); e != nil {
+                                                       return pe.Join(ErrDealIEBreak.New(), e)
+                                               }
                                        }
-                               }
-                               return false, nil
+                                       return nil
+                               },
                        },
-                       func(m []ie) (bool, 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
+                       {
+                               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
+                                                               t.buf.Reset()
+                                                               haveKeyframe = false
+                                                               cu = m[0].i
+                                                               return pe.Join(ErrDealIESkip.New(), e)
+                                                       }
+                                               }
+                                               switch handlerType {
+                                               case 'v':
+                                                       video = ts
+                                               case 's':
+                                                       audio = ts
+                                               }
+                                               if e := check_set_maxT(ts, func(_ timeStamp) error {
+                                                       return errors.New("skip")
+                                               }, func(_ timeStamp) error {
                                                        t.buf.Reset()
                                                        haveKeyframe = false
                                                        cu = m[0].i
-                                                       return false, e
+                                                       return errors.New("skip")
+                                               }); e != nil {
+                                                       return pe.Join(ErrDealIESkip.New(), e)
                                                }
                                        }
-                                       switch handlerType {
-                                       case 'v':
-                                               video = ts
-                                       case 's':
-                                               audio = ts
-                                       }
-                                       if e := check_set_maxT(ts, func(_ timeStamp) error {
-                                               return errors.New("skip")
-                                       }, func(_ timeStamp) error {
-                                               t.buf.Reset()
-                                               haveKeyframe = false
-                                               cu = m[0].i
-                                               return errors.New("skip")
-                                       }); e != nil {
-                                               return false, 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
+                                       {
+                                               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
+                                                               t.buf.Reset()
+                                                               haveKeyframe = false
+                                                               cu = m[0].i
+                                                               return pe.Join(ErrDealIESkip.New(), e)
+                                                       }
+                                               }
+                                               switch handlerType {
+                                               case 'v':
+                                                       video = ts
+                                               case 's':
+                                                       audio = ts
+                                               }
+                                               if e := check_set_maxT(ts, func(_ timeStamp) error {
+                                                       return errors.New("skip")
+                                               }, func(_ timeStamp) error {
                                                        t.buf.Reset()
                                                        haveKeyframe = false
                                                        cu = m[0].i
-                                                       return false, e
+                                                       return errors.New("skip")
+                                               }); e != nil {
+                                                       return pe.Join(ErrDealIESkip.New(), e)
                                                }
                                        }
-                                       switch handlerType {
-                                       case 'v':
-                                               video = ts
-                                       case 's':
-                                               audio = ts
+
+                                       //sync audio timeStamp
+                                       if t.AVTDiff <= 0.1 {
+                                               t.AVTDiff = 0.1
                                        }
-                                       if e := check_set_maxT(ts, func(_ timeStamp) error {
-                                               return errors.New("skip")
-                                       }, func(_ timeStamp) error {
-                                               t.buf.Reset()
-                                               haveKeyframe = false
-                                               cu = m[0].i
-                                               return errors.New("skip")
-                                       }); e != nil {
-                                               return false, e
+                                       if diff := math.Abs(video.getT() - audio.getT()); diff > t.AVTDiff {
+                                               return pe.Join(ErrDealIEBreak.New(), fmt.Errorf("时间戳不匹配 %v %v (或许应调整fmp4音视频时间戳容差s>%.2f)", video.timeStamp, audio.timeStamp, diff))
+                                               // copy(video.data, F.Itob64(int64(audio.getT()*float64(video.timescale))))
                                        }
-                               }
-
-                               //sync audio timeStamp
-                               if t.AVTDiff <= 0.1 {
-                                       t.AVTDiff = 0.1
-                               }
-                               if diff := math.Abs(video.getT() - audio.getT()); diff > t.AVTDiff {
-                                       return false, 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 v, e := t.buf.HadModified(bufModified); e == nil && v && !t.buf.IsEmpty() {
-                                               cu = m[0].i
-                                               if haveKeyframe && len(w) > 0 {
-                                                       err = w[0](video.getT(), cu, t.buf)
+                                       //deal frame
+                                       if keyframeMoof {
+                                               if v, e := t.buf.HadModified(bufModified); e == nil && v && !t.buf.IsEmpty() {
+                                                       cu = m[0].i
+                                                       if haveKeyframe && len(w) > 0 {
+                                                               err = w[0](video.getT(), cu, t.buf)
+                                                               t.buf.Reset()
+                                                               return ErrNormal
+                                                       }
                                                        t.buf.Reset()
-                                                       return true, ErrNormal
                                                }
-                                               t.buf.Reset()
+                                               haveKeyframe = true
+                                       } else if !haveKeyframe {
+                                               cu = m[10].e
                                        }
-                                       haveKeyframe = true
-                               } else if !haveKeyframe {
-                                       cu = m[10].e
-                               }
-                               if haveKeyframe {
-                                       if e := t.buf.Append(buf[m[0].i:m[10].e]); e != nil {
-                                               return false, e
+                                       if haveKeyframe {
+                                               if e := t.buf.Append(buf[m[0].i:m[10].e]); e != nil {
+                                                       return pe.Join(ErrDealIEBreak.New(), e)
+                                               }
                                        }
-                               }
-                               return false, nil
+                                       return nil
+                               },
                        },
                },
        )
@@ -724,7 +740,7 @@ func (t *Fmp4Decoder) CutSeed(reader io.Reader, startT, duration time.Duration,
 
                if !init {
                        if frontBuf, e := t.Init_fmp4(buff.GetPureBuf()); e != nil {
-                               return perrors.New("Init_fmp4", e.Error())
+                               return pe.New(e.Error(), ActionInitFmp4)
                        } else {
                                if len(frontBuf) == 0 {
                                        bufSize *= 2
@@ -740,10 +756,10 @@ func (t *Fmp4Decoder) CutSeed(reader io.Reader, startT, duration time.Duration,
                } else {
                        if !seek && seeker != nil && getIndex != nil {
                                if index, e := getIndex(startT); e != nil {
-                                       return perrors.New("s", e.Error())
+                                       return pe.New(e.Error(), ActionGetIndexFmp4)
                                } else {
                                        if _, e := seeker.Seek(index, io.SeekStart); e != nil {
-                                               return perrors.New("s", e.Error())
+                                               return pe.New(e.Error(), ActionSeekFmp4)
                                        }
                                }
                                seek = true
@@ -751,7 +767,7 @@ func (t *Fmp4Decoder) CutSeed(reader io.Reader, startT, duration time.Duration,
                                buff.Clear()
                        }
                        if dropOffset, e := t.oneF(buff.GetPureBuf(), wf); e != nil {
-                               return perrors.New("w", e.Error())
+                               return pe.New(e.Error(), ActionOneFFmp4)
                        } else {
                                if dropOffset != 0 {
                                        _ = buff.RemoveFront(dropOffset)
@@ -786,7 +802,7 @@ func (t *Fmp4Decoder) GenFastSeed(reader io.Reader, save func(seedTo time.Durati
 
                if !init {
                        if frontBuf, e := t.Init_fmp4(buff.GetPureBuf()); e != nil {
-                               return perrors.New("Init_fmp4", e.Error())
+                               return pe.New(e.Error(), ActionInitFmp4)
                        } else {
                                if len(frontBuf) == 0 {
                                        bufSize *= 2
@@ -802,7 +818,7 @@ func (t *Fmp4Decoder) GenFastSeed(reader io.Reader, save func(seedTo time.Durati
                                }
                                return save(time.Second*time.Duration(t-firstFT), int64(totalRead-buff.Size()+index))
                        }); e != nil {
-                               return perrors.New("w", e.Error())
+                               return pe.New(e.Error(), ActionOneFFmp4)
                        } else {
                                if dropOffset != 0 {
                                        _ = buff.RemoveFront(dropOffset)
@@ -815,32 +831,39 @@ func (t *Fmp4Decoder) GenFastSeed(reader io.Reader, save func(seedTo time.Durati
        return
 }
 
-func deal(ies []ie, boxNames []string, fs func([]ie) (breakloop bool, err error)) (err error) {
-       return deals(ies, [][]string{boxNames}, []func([]ie) (breakloop bool, err error){fs})
+var (
+       ErrDealIEBreak = pe.Action(`ErrDealIEBreak`)
+       ErrDealIESkip  = pe.Action(`ErrDealIESkip`)
+)
+
+type dealIE struct {
+       matchCounts int
+       boxNames    []string
+       fs          func([]ie) (err error)
 }
 
-func deals(ies []ie, boxNames [][]string, fs []func([]ie) (breakloop bool, e error)) (err error) {
-       if len(boxNames) != len(fs) {
-               panic("boxNames与fs数量不相等")
+func (t *dealIE) deal(ies []ie, cu int) (err error) {
+       if t.boxNames[t.matchCounts] == ies[cu].n {
+               t.matchCounts += 1
+               if t.matchCounts == len(t.boxNames) {
+                       t.matchCounts = 0
+                       return t.fs(ies[cu+1-len(t.boxNames) : cu+1])
+               }
+       } else {
+               t.matchCounts = 0
        }
-       var matchCounts = make([]int, len(boxNames))
-       for cu := 0; cu < len(ies) && len(boxNames) != 0; cu++ {
-               for i := 0; i < len(boxNames); i++ {
-                       if ies[cu].n == boxNames[i][matchCounts[i]] {
-                               matchCounts[i] += 1
-                               if matchCounts[i] == len(boxNames[i]) {
-                                       matchCounts[i] = 0
-                                       if breakloop, e := fs[i](ies[cu-len(boxNames[i])+1 : cu+1]); e != nil {
-                                               return e
-                                       } else if breakloop {
-                                               boxNames = append(boxNames[:i], boxNames[i+1:]...)
-                                               fs = append(fs[:i], fs[i+1:]...)
-                                               matchCounts = append(matchCounts[:i], matchCounts[i+1:]...)
-                                               i -= 1
-                                       }
-                               }
-                       } else {
-                               matchCounts[i] = 0
+       return nil
+}
+
+func deal(ies []ie, dealIEf dealIE) (err error) {
+       return deals(ies, []dealIE{dealIEf})
+}
+
+func deals(ies []ie, dealIEs []dealIE) (err error) {
+       for cu := 0; cu < len(ies) && len(dealIEs) != 0; cu++ {
+               for i := 0; i < len(dealIEs); i++ {
+                       if e := dealIEs[i].deal(ies, cu); e != nil && !pe.Catch(e, ErrDealIESkip) {
+                               return e
                        }
                }
        }
@@ -848,8 +871,8 @@ func deals(ies []ie, boxNames [][]string, fs []func([]ie) (breakloop bool, e err
 }
 
 var (
-       ErrMisBox     = perrors.New("decode", "ErrMisBox")
-       ErrCantResync = perrors.New("decode")
+       ErrMisBox     = pe.New("decode", "ErrMisBox")
+       ErrCantResync = pe.New("decode")
 )
 
 func decode(buf []byte, reSyncboxName string) (m []ie, err error) {
@@ -885,7 +908,7 @@ func decode(buf []byte, reSyncboxName string) (m []ie, err error) {
 }
 
 var (
-       ErrUnkownBox = perrors.New("ErrUnkownBox")
+       ErrUnkownBox = pe.New("ErrUnkownBox")
 )
 
 func searchBox(buf []byte, cu *int) (boxName string, i int, e int, err error) {
index 367e437288be5b9ee142e3bb78b3f9a1cee4f6de..c286c4681c54409b5a2afa48083cab423311a410 100644 (file)
@@ -87,19 +87,7 @@ func Test_Mp4Cut(t *testing.T) {
        }
 
        e := NewFmp4Decoder().Cut(f, time.Minute*30, time.Second*20, cutf.File())
-       if perrors.Catch(e, "Read") {
-               t.Log("err Read", e)
-       }
-       if perrors.Catch(e, "Init_fmp4") {
-               t.Log("err Init_fmp4", e)
-       }
-       if perrors.Catch(e, "skip") {
-               t.Log("err skip", e)
-       }
-       if perrors.Catch(e, "cutW") {
-               t.Log("err cutW", e)
-       }
-       t.Log(e)
+       t.Log(perrors.ErrorFormat(e))
 }
 
 func Test_Mp4GenFastSeed(t *testing.T) {
@@ -118,19 +106,7 @@ func Test_Mp4GenFastSeed(t *testing.T) {
        e = NewFmp4Decoder().GenFastSeed(f, func(seedTo time.Duration, cuIndex int64) error {
                return sf(seedTo, cuIndex)
        })
-       if perrors.Catch(e, "Read") {
-               t.Log("err Read", e)
-       }
-       if perrors.Catch(e, "Init_fmp4") {
-               t.Log("err Init_fmp4", e)
-       }
-       if perrors.Catch(e, "skip") {
-               t.Log("err skip", e)
-       }
-       if perrors.Catch(e, "cutW") {
-               t.Log("err cutW", e)
-       }
-       t.Log(e)
+       t.Log(perrors.ErrorFormat(e))
 
        // VideoFastSeed.BeforeGet("testdata/1.fastSeed")
        // {
@@ -175,17 +151,5 @@ func Test_Mp4CutSeed(t *testing.T) {
        }
 
        e = NewFmp4Decoder().CutSeed(f, time.Minute*30, time.Second*20, cutf.File(), f, gf)
-       if perrors.Catch(e, "Read") {
-               t.Log("err Read", e)
-       }
-       if perrors.Catch(e, "Init_fmp4") {
-               t.Log("err Init_fmp4", e)
-       }
-       if perrors.Catch(e, "skip") {
-               t.Log("err skip", e)
-       }
-       if perrors.Catch(e, "cutW") {
-               t.Log("err cutW", e)
-       }
-       t.Log(e)
+       t.Log(perrors.ErrorFormat(e))
 }
index 70212066f3c9534220ba4af5ae7e5a71d6e7c87e..10b713ab0d8fd187741d30b321adf89468b4700f 100644 (file)
@@ -29,7 +29,7 @@ import (
        replyFunc "github.com/qydysky/bili_danmu/Reply/F"
        videoInfo "github.com/qydysky/bili_danmu/Reply/F/videoInfo"
        pctx "github.com/qydysky/part/ctx"
-       pe "github.com/qydysky/part/errors"
+       perrors "github.com/qydysky/part/errors"
        file "github.com/qydysky/part/file"
        funcCtrl "github.com/qydysky/part/funcCtrl"
        pio "github.com/qydysky/part/io"
@@ -138,7 +138,11 @@ func (t *m4s_link_item) getNo() (int, error) {
        return strconv.Atoi(base[:len(base)-4])
 }
 
-func (link *m4s_link_item) download(reqPool *pool.Buf[reqf.Req], reqConfig reqf.Rval) error {
+var (
+       AEFDCTO perrors.Action = `ActionErrFmp4DownloadCareTO`
+)
+
+func (link *m4s_link_item) download(reqPool *pool.Buf[reqf.Req], reqConfig reqf.Rval) (err error) {
        link.status = 1 // 设置切片状态为正在下载
        link.err = nil
        link.tryDownCount += 1
@@ -148,16 +152,7 @@ func (link *m4s_link_item) download(reqPool *pool.Buf[reqf.Req], reqConfig reqf.
        defer reqPool.Put(r)
        reqConfig.Url = link.Url
 
-       // fmt.Println(`T: `, `下载`, link.Base)
-       // defer t.log.L(`T: `, `下载完成`, link.Base, link.status, link.err)
-
        if e := r.Reqf(reqConfig); e != nil && !errors.Is(e, io.EOF) {
-               // t.log.L(`T: `, `下载错误`, link.Base, e)
-               // if !reqf.IsTimeout(e) {
-               //      // 发生非超时错误
-               //      link.err = e
-               //      link.tryDownCount = 3 // 设置切片状态为下载失败
-               // }
                link.status = 3 // 设置切片状态为下载失败
                link.err = e
                return e
@@ -166,8 +161,11 @@ func (link *m4s_link_item) download(reqPool *pool.Buf[reqf.Req], reqConfig reqf.
                link.err = e
                return e
        } else {
+               if int64(reqConfig.Timeout) < r.UsedTime.Milliseconds()+3000 {
+                       err = perrors.New(fmt.Sprintf("fmp4切片下载超时s(%d)或许应该大于%d", reqConfig.Timeout/1000, (r.UsedTime.Milliseconds()+4000)/1000), AEFDCTO)
+               }
                link.status = 2 // 设置切片状态为下载完成
-               return nil
+               return
        }
 }
 
@@ -478,7 +476,7 @@ func (t *M4SStream) fetchParseM3U8(lastM4s *m4s_link_item, fmp4ListUpdateTo floa
 
                if err := r.Reqf(rval); err != nil {
                        v.DisableAuto()
-                       t.log.L("W: ", fmt.Sprintf("服务器 %s 发生故障 %s", F.ParseHost(v.Url), pe.ErrorFormat(err, pe.ErrSimplifyFunc)))
+                       t.log.L("W: ", fmt.Sprintf("服务器 %s 发生故障 %s", F.ParseHost(v.Url), perrors.ErrorFormat(err, perrors.ErrActionInLineFunc)))
                        if t.common.ValidLive() == nil {
                                e = errors.New("全部流服务器发生故障")
                                break
@@ -982,7 +980,7 @@ func (t *M4SStream) saveStreamM4s() (e error) {
                fmp4Decoder      = NewFmp4Decoder()
                keyframe         = slice.New[byte]()
                lastM4s          *m4s_link_item
-               to               = 3
+               to               = 5
                fmp4ListUpdateTo = 5.0
                fmp4Count        = 0
                startT           = time.Now()
@@ -1117,16 +1115,22 @@ func (t *M4SStream) saveStreamM4s() (e error) {
                                go func(link *m4s_link_item) {
                                        defer done()
 
-                                       if e := link.download(t.reqPool, reqf.Rval{
+                                       e := link.download(t.reqPool, reqf.Rval{
                                                Timeout:     to * 1000,
                                                WriteLoopTO: (to + 2) * 1000,
                                                Proxy:       t.common.Proxy,
                                                Header: map[string]string{
                                                        `Connection`: `close`,
                                                },
-                                       }); e != nil {
+                                       })
+                                       if perrors.Catch(e, AEFDCTO) {
+                                               t.log.L(`W: `, e.Error())
+                                       } else if e != nil {
                                                downErr.Store(true)
-                                               t.log.L(`W: `, `切片下载失败`, link.Base, e)
+                                               if reqf.IsTimeout(e) {
+                                                       t.log.L(`W: `, fmt.Sprintf("fmp4切片下载超时s或许应该大于%d", to))
+                                               }
+                                               t.log.L(`W: `, `切片下载失败`, link.Base, perrors.ErrorFormat(e, perrors.ErrActionInLineFunc))
                                        }
                                }(download_seq[i])
                        }
index 2b34c5419ca4c1b6110735447f3d23e8612d9934..c9770e015670b6368815f1b0017093d1c2798f54 100644 (file)
@@ -82,7 +82,8 @@
     "flv断流续接": true,
     "flv音视频时间戳容差ms-help": "默认100,小于默认无效,调大可以允许较差的流,但可能会音画不同步",
     "flv音视频时间戳容差ms": 100,
-    "fmp4切片下载超时s": 3,
+    "fmp4切片下载超时s-help": "默认5,小于默认无效,调大可以允许等待更长的时间,但可能会导致实时回放延迟等异常",
+    "fmp4切片下载超时s": 5,
     "fmp4获取更多服务器": true,
     "fmp4跳过解码出错的帧-help": "fmp4跳过解码出错的帧、但可能导致关键帧时间上的跳越",
     "fmp4跳过解码出错的帧": false,
diff --git a/go.mod b/go.mod
index 65a030046207a2c3df36e05d9c1c4edb07a4dbe3..20c6ebb429e7a95cacdfe8dda0277c8a38841873 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.23
 require (
        github.com/gotk3/gotk3 v0.6.4
        github.com/mdp/qrterminal/v3 v3.2.0
-       github.com/qydysky/part v0.28.20250114181028
+       github.com/qydysky/part v0.28.20250120190624
        github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
        github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
        golang.org/x/text v0.21.0
diff --git a/go.sum b/go.sum
index e4febbde49db565151d28d4e8414954d5503e78c..474c27e8d0140b24e8188b83e140e4bf5bb8fd1d 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -48,8 +48,8 @@ github.com/qydysky/biliApi v0.0.0-20240725184407-15076dddb6fb h1:dtSpNF9hLQa09TU
 github.com/qydysky/biliApi v0.0.0-20240725184407-15076dddb6fb/go.mod h1:om024vfxALQ5vxsbaGoMm8IS0esLYBnEOpJI8FsGoDg=
 github.com/qydysky/brotli v0.0.0-20240828134800-e9913a6e7ed9 h1:k451T+bpsLr+Dq9Ujo+Qtx0iomRA1XXS5ttlEojvfuQ=
 github.com/qydysky/brotli v0.0.0-20240828134800-e9913a6e7ed9/go.mod h1:cI8/gy/wjy2Eb+p2IUj2ZuDnC8R5Vrx3O0VMPvMvphA=
-github.com/qydysky/part v0.28.20250114181028 h1:YWsQkOcwHtL7KkHMl2l+NP4ZdO0gCZ7Ft0qh8Z5bbZ8=
-github.com/qydysky/part v0.28.20250114181028/go.mod h1:RAb3G05OaqCSRWFJz9FnONB6iqF/Dk4R+Z5c/H7mWSg=
+github.com/qydysky/part v0.28.20250120190624 h1:KyxUMxO0k5/loU1TP9usKJpN8YDGPgrIC6Yc37OeGws=
+github.com/qydysky/part v0.28.20250120190624/go.mod h1:RAb3G05OaqCSRWFJz9FnONB6iqF/Dk4R+Z5c/H7mWSg=
 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
 github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=