// "math"
+ "github.com/dustin/go-humanize"
F "github.com/qydysky/bili_danmu/F"
)
// this fuction read []byte and return flv header and all complete keyframe if possible.
// complete keyframe means the video and audio tags between two video key frames tag
func Search_stream_tag(buf []byte) (front_buf []byte, keyframe [][]byte, last_available_offset int, err error) {
+ if len(buf) > humanize.MByte*100 {
+ err = errors.New("buf too large")
+ return
+ }
//get flv header(9byte) + FirstTagSize(4byte)
if header_offset := bytes.Index(buf, flv_header_sign); header_offset != -1 {
if header_offset+flv_header_size+previou_tag_size > len(buf) {
"errors"
"io"
+ "github.com/dustin/go-humanize"
F "github.com/qydysky/bili_danmu/F"
slice "github.com/qydysky/part/slice"
)
var ftypI, ftypE, moovI, moovE int
ies, e := decode(buf, "ftyp")
- if len(ies) == 0 {
- err = errors.New("未找到box")
- }
if e != nil {
return
}
}
func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframes *slice.Buf[byte]) (cu int, err error) {
+ if len(buf) > humanize.MByte*100 {
+ err = errors.New("buf too large")
+ return
+ }
if len(t.traks) == 0 {
err = errors.New("未初始化traks")
return
}
-
if t.buf == nil {
t.buf = slice.New[byte]()
}
)
ies, e := decode(buf, "moof")
- if len(ies) == 0 {
- err = errors.New("未找到box")
- }
if e != nil {
return
}
func decode(buf []byte, reSyncboxName string) (m []ie, err error) {
var cu int
- for cu < len(buf) {
+ for cu < len(buf)-3 {
boxName, i, e, E := searchBox(buf, &cu)
if E != nil {
+ if errors.Is(E, io.EOF) {
+ if len(m) == 0 {
+ err = errors.New("未找到box")
+ }
+ return
+ }
err = E
if reSyncI := bytes.Index(buf[cu:], []byte(reSyncboxName)); reSyncI != -1 {
cu += reSyncI - 4
package reply
import (
- // _ "embed"
+ "errors"
+ "fmt"
+ "io"
"testing"
- F "github.com/qydysky/bili_danmu/F"
+ "github.com/dustin/go-humanize"
+ file "github.com/qydysky/part/file"
+ slice "github.com/qydysky/part/slice"
)
-// go:embed 32320131.m4s
-var buf []byte
-
func Test_deal(t *testing.T) {
- 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 {
- 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)
- return false
- })
- t.Log("err", err)
+ flog := file.New("E:\\test\\0.flv.log", 0, false)
+ flog.Delete()
+ defer flog.Close()
+ f := file.New("E:\\test\\0.mp4", 0, false)
+ defer f.Close()
+
+ if f.IsDir() || !f.IsExist() {
+ t.Fatal("file not support")
+ }
+
+ buf := make([]byte, humanize.MByte)
+ buff := slice.New[byte]()
+ max := 0
+ fmp4Decoder := new(Fmp4Decoder)
+ fmp4KeyFrames := slice.New[byte]()
+
+ for c := 0; true; c++ {
+ n, e := f.Read(buf)
+ if n == 0 && errors.Is(e, io.EOF) {
+ t.Log("reach end")
+ break
+ }
+ buff.Append(buf[:n])
+ if s := buff.Size(); max < s {
+ max = s
+ }
+ if max > humanize.MByte*100 {
+ t.Log("reach max")
+ break
+ }
+
+ front_buf, e := fmp4Decoder.Init_fmp4(buff.GetCopyBuf())
+ if e != nil {
+ t.Fatal(e)
+ }
+ last_available_offset, e := fmp4Decoder.Search_stream_fmp4(buff.GetPureBuf(), fmp4KeyFrames)
+ if e != nil && e.Error() != "未初始化traks" {
+ t.Fatal(e)
+ }
+ if len(front_buf) != 0 {
+ t.Log("front_buf")
+ break
+ }
+ flog.Write([]byte(fmt.Sprintf("%d %d\n", c, len(front_buf))), true)
+ t.Log(c, len(front_buf))
+ buff.RemoveFront(last_available_offset)
+ }
+ t.Log("max", humanize.Bytes(uint64(max)))
}