]> 127.0.0.1 Git - bili_danmu/.git/commitdiff
fix fmp4 decode
authorqydysky <32743305+qydysky@users.noreply.github.com>
Tue, 10 Jan 2023 13:40:48 +0000 (21:40 +0800)
committerqydysky <32743305+qydysky@users.noreply.github.com>
Tue, 10 Jan 2023 13:40:48 +0000 (21:40 +0800)
Reply/fmp4Decode.go
Reply/fmp4Decode_test.go
Reply/stream.go
demo/go.mod
demo/go.sum
go.mod
go.sum

index 3d53c24d30883a62255c345520e416b0197bf8fe..752b7df68290f08a30dd524f183154f54777f5ce 100644 (file)
@@ -63,9 +63,17 @@ type Fmp4Decoder struct {
 func (t *Fmp4Decoder) Init_fmp4(buf []byte) (b []byte, err error) {
        var ftypI, ftypE, moovI, moovE int
 
-       err = deal(buf,
+       ies, e := decode(buf, "ftyp")
+       if len(ies) == 0 {
+               err = errors.New("未找到box")
+       }
+       if e != nil {
+               return
+       }
+
+       err = deal(ies,
                []string{"ftyp", "moov"},
-               func(m []*ie) bool {
+               func(m []ie) bool {
                        ftypI = m[0].i
                        ftypE = m[0].e
                        moovI = m[1].i
@@ -77,9 +85,9 @@ func (t *Fmp4Decoder) Init_fmp4(buf []byte) (b []byte, err error) {
                return nil, err
        }
 
-       err = deal(buf,
+       err = deal(ies,
                []string{"tkhd", "mdia", "mdhd", "hdlr"},
-               func(m []*ie) bool {
+               func(m []ie) bool {
                        tackId := int(F.Btoi(buf, m[0].i+20, 4))
                        if t.traks == nil {
                                t.traks = make(map[int]trak)
@@ -111,9 +119,11 @@ func (t *Fmp4Decoder) Seach_stream_fmp4(buf []byte, keyframes *bufB) (cu int, er
 
        t.buf.reset()
        var (
-               haveKeyframe      bool
-               bufModified       = t.buf.getModifiedTime()
-               maxSequenceNumber int
+               haveKeyframe bool
+               bufModified  = t.buf.getModifiedTime()
+               // maxSequenceNumber int //有时并不是单调增加
+               maxVT float64
+               maxAT float64
 
                //get timeStamp
                get_timeStamp = func(tfdt int) (ts timeStamp) {
@@ -139,119 +149,188 @@ func (t *Fmp4Decoder) Seach_stream_fmp4(buf []byte, keyframes *bufB) (cu int, er
                        }
                        return
                }
+
+               //is t error?
+               check_set_maxT = func(ts timeStamp, equal func(ts timeStamp) error, larger func(ts timeStamp) error) (err error) {
+                       switch ts.handlerType {
+                       case 'v':
+                               if maxVT == 0 {
+                                       maxVT = ts.getT()
+                               } else if maxVT == ts.getT() && equal != nil {
+                                       err = equal(ts)
+                               } else if maxVT > ts.getT() && larger != nil {
+                                       err = larger(ts)
+                               } else {
+                                       maxVT = ts.getT()
+                               }
+                       case 'a':
+                               if maxAT == 0 {
+                                       maxAT = ts.getT()
+                               } else if maxAT == ts.getT() && equal != nil {
+                                       err = equal(ts)
+                               } else if maxAT > ts.getT() && larger != nil {
+                                       err = larger(ts)
+                               } else {
+                                       maxAT = ts.getT()
+                               }
+                       default:
+                       }
+                       return
+               }
        )
 
-       err = deal(buf,
-               []string{"moof", "mfhd",
-                       "traf", "tfhd", "tfdt", "trun",
-                       "traf", "tfhd", "tfdt", "trun",
-                       "mdat"},
-               func(m []*ie) bool {
-                       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, "frame", keyframeMoof, t.buf.size(), m[0].i, m[10].n, m[10].e)
-
-                       //is sn error?
-                       if maxSequenceNumber == 0 {
-                               maxSequenceNumber = moofSN
-                       } else if moofSN == maxSequenceNumber {
-                               return false
-                       } else if moofSN != maxSequenceNumber+1 {
-                               t.buf.reset()
-                               haveKeyframe = false
-                               cu = m[0].i
+       ies, e := decode(buf, "moof")
+       if len(ies) == 0 {
+               err = errors.New("未找到box")
+       }
+       if e != nil {
+               return
+       }
+
+       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{
+                       func(m []ie) bool {
+                               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 nil != 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")
+                                       }) {
+                                               return false
+                                       }
+                               }
+
+                               // fmt.Println(ts.getT(), "frame0", keyframeMoof, t.buf.size(), m[0].i, m[6].n, m[6].e)
+
+                               //deal frame
+                               if keyframeMoof {
+                                       if t.buf.hadModified(bufModified) && !t.buf.isEmpty() {
+                                               keyframes.append(t.buf.getPureBuf())
+                                               cu = m[0].i
+                                               t.buf.reset()
+                                       }
+                                       haveKeyframe = true
+                               } else if !haveKeyframe {
+                                       cu = m[6].e
+                               }
+                               if haveKeyframe {
+                                       t.buf.append(buf[m[0].i:m[6].e])
+                               }
                                return false
-                       } else {
-                               maxSequenceNumber = moofSN
-                       }
-                       {
-                               ts, handlerType := get_track_type(m[3].i, m[4].i)
-                               switch handlerType {
-                               case 'v':
-                                       video = ts
-                               case 's':
-                                       audio = ts
+                       },
+                       func(m []ie) bool {
+                               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)
+                                       switch handlerType {
+                                       case 'v':
+                                               video = ts
+                                       case 's':
+                                               audio = ts
+                                       }
+                                       if nil != 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")
+                                       }) {
+                                               return false
+                                       }
                                }
-                       }
-                       {
-                               ts, handlerType := get_track_type(m[7].i, m[8].i)
-                               switch handlerType {
-                               case 'v':
-                                       video = ts
-                               case 's':
-                                       audio = ts
+                               {
+                                       ts, handlerType := get_track_type(m[7].i, m[8].i)
+                                       switch handlerType {
+                                       case 'v':
+                                               video = ts
+                                       case 's':
+                                               audio = ts
+                                       }
+                                       if nil != 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")
+                                       }) {
+                                               return false
+                                       }
                                }
-                       }
 
-                       //deal frame
-                       if keyframeMoof {
                                //sync audio timeStamp
                                if audio.getT() != video.getT() {
                                        date := F.Itob64(int64(video.getT() * float64(audio.timescale)))
                                        copy(audio.data, date)
                                }
-                               if t.buf.hadModified(bufModified) && !t.buf.isEmpty() {
-                                       keyframes.append(t.buf.getPureBuf())
-                                       cu = m[0].i
-                                       t.buf.reset()
-                               }
-                               haveKeyframe = true
-                       } else if !haveKeyframe {
-                               cu = m[10].e
-                       }
-                       if haveKeyframe {
-                               t.buf.append(buf[m[0].i:m[10].e])
-                       }
-                       return false
-               })
-
-       if len(buf) > 1024*1024*20 {
-               err = errors.New("buf超过20M")
-       }
 
+                               //deal frame
+                               if keyframeMoof {
+                                       if t.buf.hadModified(bufModified) && !t.buf.isEmpty() {
+                                               keyframes.append(t.buf.getPureBuf())
+                                               cu = m[0].i
+                                               t.buf.reset()
+                                       }
+                                       haveKeyframe = true
+                               } else if !haveKeyframe {
+                                       cu = m[10].e
+                               }
+                               if haveKeyframe {
+                                       t.buf.append(buf[m[0].i:m[10].e])
+                               }
+                               return false
+                       }})
        return
 }
 
-func deal(buf []byte, boxName []string, f func([]*ie) (breakloop bool)) (err error) {
+func deal(ies []ie, boxNames []string, fs func([]ie) (breakloop bool)) (err error) {
+       return deals(ies, [][]string{boxNames}, []func([]ie) (breakloop bool){fs})
+}
 
-       m, e := decode(buf, boxName[0])
-       if len(m) == 0 {
-               return errors.New("未找到box")
-       }
-       if e != nil {
-               err = e
+func deals(ies []ie, boxNames [][]string, fs []func([]ie) (breakloop bool)) (err error) {
+       if len(boxNames) != len(fs) {
+               panic("boxNames与fs数量不相等")
        }
-
-       var matchCount = 0
-       for cu := 0; cu < len(m); cu++ {
-               if m[cu].n == boxName[matchCount] {
-                       matchCount += 1
-                       if matchCount == len(boxName) {
-                               var ies []*ie
-
-                               for k, v := range boxName {
-                                       ies = append(ies, &ie{
-                                               n: v,
-                                               i: m[cu-(matchCount-1)+k].i,
-                                               e: m[cu-(matchCount-1)+k].e,
-                                       })
-                               }
-
-                               if f(ies) {
-                                       break
+       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 fs[i](ies[cu-len(boxNames[i])+1 : cu+1]) {
+                                               boxNames = append(boxNames[:i], boxNames[i+1:]...)
+                                               fs = append(fs[:i], fs[i+1:]...)
+                                               matchCounts = append(matchCounts[:i], matchCounts[i+1:]...)
+                                               i -= 1
+                                       }
                                }
-                               matchCount = 0
+                       } else {
+                               matchCounts[i] = 0
                        }
-               } else {
-                       matchCount = 0
                }
        }
-
        return
 }
 
index 73dfe13262d9c4615e08bc571efe458e14e6605c..6b8878342b9d0de5fb06a7eba5082817f03f8dd0 100644 (file)
@@ -7,15 +7,28 @@ import (
        F "github.com/qydysky/bili_danmu/F"
 )
 
+//go:embed 32320131.m4s
 var buf []byte
 
 func Test_deal(t *testing.T) {
-       err := deal(buf,
+       ies, _ := decode(buf, "moof")
+       err := deal(ies,
+               []string{"moof", "mfhd",
+                       "traf", "tfhd", "tfdt", "trun",
+                       "mdat"},
+               func(m []ie) bool {
+                       moofSN := int(F.Btoi(buf, m[1].i+12, 4))
+                       keyframeMoof := buf[m[5].i+20] == byte(0x02)
+                       t.Log(moofSN, "frame", keyframeMoof, m[0].i, m[6].n, m[6].e)
+                       return false
+               })
+       t.Log("err", err)
+       err = deal(ies,
                []string{"moof", "mfhd",
                        "traf", "tfhd", "tfdt", "trun",
                        "traf", "tfhd", "tfdt", "trun",
                        "mdat"},
-               func(m []*ie) bool {
+               func(m []ie) bool {
                        moofSN := int(F.Btoi(buf, m[1].i+12, 4))
                        keyframeMoof := buf[m[5].i+20] == byte(0x02) || buf[m[9].i+20] == byte(0x02)
                        t.Log(moofSN, "frame", keyframeMoof, m[0].i, m[10].n, m[10].e)
index d70eca376b42b9aed3bb4d6624ad41ea31fea4c3..50a820c6707f379cbe9f6a91036118014d552bda 100644 (file)
@@ -745,7 +745,9 @@ func (t *M4SStream) saveStreamM4s() (e error) {
                        }
 
                        // 等待队列下载完成
-                       download_limit.PlanDone()
+                       download_limit.PlanDone(func() {
+                               time.Sleep(time.Millisecond * 10)
+                       })
                }
 
                // 传递已下载切片
@@ -814,7 +816,7 @@ func (t *M4SStream) saveStreamM4s() (e error) {
                        }
 
                        // no, _ := v.getNo()
-                       // fmt.Println(no, "fmp4KeyFrames", len(fmp4KeyFrames), last_avilable_offset, err)
+                       // fmt.Println(no, "fmp4KeyFrames", fmp4KeyFrames.size(), last_avilable_offset, err)
 
                        if !fmp4KeyFrames.isEmpty() {
                                fmp4KeyFramesBuf = fmp4KeyFrames.getCopyBuf()
@@ -1017,6 +1019,7 @@ func (t *M4SStream) Stop() {
 func (t *M4SStream) Pusher(w http.ResponseWriter, r *http.Request) {
        switch t.stream_type {
        case `m3u8`:
+               t.pusherM4s(w, r)
        case `mp4`:
                t.pusherM4s(w, r)
        case `flv`:
@@ -1104,7 +1107,7 @@ func (t *M4SStream) pusherFlv(w http.ResponseWriter, r *http.Request) {
 
        cancel := make(chan struct{})
 
-       //hls切片
+       //flv
        t.Stream_msg.Pull_tag(map[string]func(interface{}) bool{
                `data`: func(data interface{}) bool {
                        if b, ok := data.([]byte); ok {
index c44aaabd79122b6e30794d060d1800780cec705d..7e834ce44d46f4615cb3cd79059c1f2179cd41f9 100644 (file)
@@ -15,7 +15,7 @@ require (
        github.com/mdp/qrterminal/v3 v3.0.0 // indirect
        github.com/miekg/dns v1.1.50 // indirect
        github.com/mitchellh/mapstructure v1.5.0 // indirect
-       github.com/qydysky/part v0.20.0 // indirect
+       github.com/qydysky/part v0.20.1 // indirect
        github.com/shirou/gopsutil v3.21.11+incompatible // indirect
        github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
        github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
index b16321b03c0ae75a3319e60f4b8f8e20ee685ab0..61d450e42e59f477358f0e7ac4e072b724bdb13c 100644 (file)
@@ -132,6 +132,8 @@ github.com/qydysky/part v0.19.2 h1:peR1UBrBgnjB63nv5F100oJ72hRoJnn8cuZPXDiGZOM=
 github.com/qydysky/part v0.19.2/go.mod h1:BG0tulTKW58jSkC0EZ0MrxDHe+gkPULfGNzksiGCayw=
 github.com/qydysky/part v0.20.0 h1:JkAdTrGwXjbL8FJuiinKK8Vrd2HU/rcRD+Bdx4RpGGw=
 github.com/qydysky/part v0.20.0/go.mod h1:BG0tulTKW58jSkC0EZ0MrxDHe+gkPULfGNzksiGCayw=
+github.com/qydysky/part v0.20.1 h1:C0VDY/OZHEVRD1SeudG67t/7/0qUMlfJcy8CQQKVZ9A=
+github.com/qydysky/part v0.20.1/go.mod h1:BG0tulTKW58jSkC0EZ0MrxDHe+gkPULfGNzksiGCayw=
 github.com/shirou/gopsutil v3.20.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 github.com/shirou/gopsutil v3.21.5+incompatible h1:OloQyEerMi7JUrXiNzy8wQ5XN+baemxSl12QgIzt0jc=
 github.com/shirou/gopsutil v3.21.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
diff --git a/go.mod b/go.mod
index e05a0c8e2dce13c57458b925668040c9d03331d6..024ae1ada84c660fb7e141084197c6c9783fbbdf 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
        github.com/gofrs/uuid v4.3.0+incompatible
        github.com/gotk3/gotk3 v0.6.1
        github.com/mdp/qrterminal/v3 v3.0.0
-       github.com/qydysky/part v0.20.0
+       github.com/qydysky/part v0.20.1
        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.3.8
diff --git a/go.sum b/go.sum
index 401226617b0bf5e160f9df24ffe62da2f8fd40f6..9df4c1b141d2f93ad7748fbee0c32b7ad234ecbc 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -38,6 +38,8 @@ github.com/qydysky/part v0.10.17 h1:xcMgJaEvPlOPAEfOniTZZM/pDiafWW3FA5ZQXNPthpI=
 github.com/qydysky/part v0.10.17/go.mod h1:B3GD/j5jmvwfKtnzDWqRYFqnwOXEyoUg/jShFk1yQSM=
 github.com/qydysky/part v0.20.0 h1:JkAdTrGwXjbL8FJuiinKK8Vrd2HU/rcRD+Bdx4RpGGw=
 github.com/qydysky/part v0.20.0/go.mod h1:BG0tulTKW58jSkC0EZ0MrxDHe+gkPULfGNzksiGCayw=
+github.com/qydysky/part v0.20.1 h1:C0VDY/OZHEVRD1SeudG67t/7/0qUMlfJcy8CQQKVZ9A=
+github.com/qydysky/part v0.20.1/go.mod h1:BG0tulTKW58jSkC0EZ0MrxDHe+gkPULfGNzksiGCayw=
 github.com/shirou/gopsutil v3.20.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
 github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=