/*
整数 字节转换区
+64 8字节
32 4字节
16 2字节
*/
+func Itob64(num int64) []byte {
+ var buffer bytes.Buffer
+ err := binary.Write(&buffer, binary.BigEndian, num)
+ if err != nil {
+ p.Logf().E(err)
+ }
+ return buffer.Bytes()
+}
+
func Itob32(num int32) []byte {
var buffer bytes.Buffer
err := binary.Write(&buffer, binary.BigEndian, num)
return buffer.Bytes()
}
+func btoi64(b []byte) int64 {
+ var buffer int64
+ err := binary.Read(bytes.NewReader(b), binary.BigEndian, &buffer)
+ if err != nil {
+ p.Logf().E(err)
+ }
+ return buffer
+}
+
func btoi32(b []byte) int32 {
var buffer int32
err := binary.Read(bytes.NewReader(b), binary.BigEndian, &buffer)
return buffer
}
+func Btoi64(b []byte, offset int) int64 {
+ for len(b) < 8 {
+ b = append([]byte{0x00}, b...)
+ }
+ return btoi64(b[offset : offset+8])
+}
+
func Btoi32(b []byte, offset int) int32 {
+ for len(b) < 4 {
+ b = append([]byte{0x00}, b...)
+ }
return btoi32(b[offset : offset+4])
}
func Btoi16(b []byte, offset int) int16 {
+ for len(b) < 2 {
+ b = append([]byte{0x00}, b...)
+ }
return btoi16(b[offset : offset+2])
}
F "github.com/qydysky/bili_danmu/F"
)
-type fmp4KeyFrame struct {
- videoTime int
- audioTime int
- data []byte
+type trak struct {
+ timescale int
+ trackID int
+ handlerType byte
}
-func Seach_stream_fmp4(buf []byte) (keyframes []fmp4KeyFrame, last_avilable_offset int, err error) {
+type Fmp4Decoder struct {
+ traks map[int]trak
+}
+
+func (t *Fmp4Decoder) Init_fmp4(buf []byte) error {
+ var cu int
+ for cu < len(buf) {
+ //moov
+ moovI := bytes.Index(buf[cu:], []byte("moov"))
+ if moovI == -1 {
+ break
+ }
+ moovI = cu + moovI - 4
+ cu = moovI
+ moovE := moovI + int(F.Btoi32(buf, moovI))
+ if moovE > len(buf) {
+ return errors.New("moov包破损")
+ }
+
+ for cu < moovE {
+ //trak
+ trakI := bytes.Index(buf[cu:], []byte("trak"))
+ if trakI == -1 {
+ break
+ }
+ trakI = cu + trakI - 4
+ cu = trakI
+ trakE := trakI + int(F.Btoi32(buf, trakI))
+ if trakE > moovE {
+ return errors.New("trak包破损")
+ }
+
+ //tkhd
+ tkhdI := bytes.Index(buf[cu:], []byte("tkhd"))
+ if tkhdI == -1 {
+ return errors.New("未找到tkhd包")
+ }
+ tkhdI = cu + tkhdI - 4
+ cu = tkhdI
+ tkhdE := tkhdI + int(F.Btoi32(buf, tkhdI))
+ if tkhdE > trakE {
+ return errors.New("tkhd包破损")
+ }
+
+ //mdia
+ mdiaI := bytes.Index(buf[cu:], []byte("mdia"))
+ if mdiaI == -1 {
+ return errors.New("未找到mdia包")
+ }
+ mdiaI = cu + mdiaI - 4
+ cu = mdiaI
+ mdiaE := mdiaI + int(F.Btoi32(buf, mdiaI))
+ if mdiaE > trakE {
+ return errors.New("mdia包破损")
+ }
+
+ //mdhd
+ mdhdI := bytes.Index(buf[cu:], []byte("mdhd"))
+ if mdhdI == -1 {
+ return errors.New("未找到mdhd包")
+ }
+ mdhdI = cu + mdhdI - 4
+ cu = mdhdI
+ mdhdE := mdhdI + int(F.Btoi32(buf, mdhdI))
+ if mdhdE > mdiaE {
+ return errors.New("mdhd包破损")
+ }
+
+ //hdlr
+ hdlrI := bytes.Index(buf[cu:], []byte("hdlr"))
+ if hdlrI == -1 {
+ return errors.New("未找到hdlr包")
+ }
+ hdlrI = cu + hdlrI - 4
+ cu = hdlrI
+ hdlrE := hdlrI + int(F.Btoi32(buf, hdlrI))
+ if hdlrE > mdiaE {
+ return errors.New("hdlr包破损")
+ }
+
+ tackId := int(F.Btoi32(buf, tkhdI+20))
+ if t.traks == nil {
+ t.traks = make(map[int]trak)
+ }
+ t.traks[tackId] = trak{
+ trackID: tackId,
+ timescale: int(F.Btoi32(buf, mdhdI+20)),
+ handlerType: buf[hdlrI+16],
+ }
+ }
+ }
+ if len(t.traks) == 0 {
+ return errors.New("未找到trak包")
+ }
+ return nil
+}
+
+func (t *Fmp4Decoder) Seach_stream_fmp4(buf []byte) (keyframes [][]byte, last_avilable_offset int, err error) {
+ if len(t.traks) == 0 {
+ err = errors.New("未初始化traks")
+ return
+ }
+
var (
cu int
- keyframe fmp4KeyFrame
+ keyframe []byte
)
for cu < len(buf) {
//moof
- moofI := cu + bytes.Index(buf[cu:], []byte("moof")) - 4
+ moofI := bytes.Index(buf[cu:], []byte("moof"))
if moofI == -1 {
- err = errors.New("未找到moof包")
break
}
+ moofI = cu + moofI - 4
+ cu = moofI
moofE := moofI + int(F.Btoi32(buf, moofI))
if moofE > len(buf) {
break
}
- cu = moofI
var (
- iskeyFrame bool
- videoTime int
- audioTime int
+ iskeyFrame bool
+ videoTime float64
+ audioTime float64
+ audioTimeIndex int
+ audioTimeSize int
+ audioTimeScale int
)
- for trafCount := 0; trafCount < 2 && cu < moofE; trafCount += 1 {
-
+ for cu < moofE {
//traf
- trafI := cu + bytes.Index(buf[cu:], []byte("traf")) - 4
+ trafI := bytes.Index(buf[cu:], []byte("traf"))
if trafI == -1 {
- err = errors.New("未找到traf包")
break
}
+ trafI = cu + trafI - 4
cu = trafI
trafE := trafI + int(F.Btoi32(buf, trafI))
if trafE > moofE {
- err = errors.New("traf包破损")
+ break
+ }
+
+ //tfhd
+ tfhdI := bytes.Index(buf[cu:], []byte("tfhd"))
+ if tfhdI == -1 {
+ err = errors.New("未找到tfhd包")
+ break
+ }
+ tfhdI = cu + tfhdI - 4
+ cu = tfhdI
+ tfhdE := tfhdI + int(F.Btoi32(buf, tfhdI))
+ if tfhdE > trafE {
+ err = errors.New("tfhd包破损")
break
}
//tfdt
- tfdtI := cu + bytes.Index(buf[cu:], []byte("tfdt")) - 4
+ tfdtI := bytes.Index(buf[cu:], []byte("tfdt"))
if tfdtI == -1 {
err = errors.New("未找到tfdt包")
break
}
+ tfdtI = cu + tfdtI - 4
cu = tfdtI
tfdtE := tfdtI + int(F.Btoi32(buf, tfdtI))
if tfdtE > trafE {
}
//trun
- trunI := cu + bytes.Index(buf[cu:], []byte("trun")) - 4
+ trunI := bytes.Index(buf[cu:], []byte("trun"))
if trunI == -1 {
err = errors.New("未找到trun包")
break
}
+ trunI = cu + trunI - 4
cu = trunI
trunE := trunI + int(F.Btoi32(buf, trunI))
if trunE > trafE {
break
}
- timeStamp := int(F.Btoi32(buf, tfdtI+16))
- if trafCount == 0 {
- videoTime = timeStamp
- } else if trafCount == 1 {
- audioTime = timeStamp
+ var (
+ timeStamp int
+ timeStampIndex int
+ timeSize int
+ )
+ switch buf[tfdtI+8] {
+ case 0:
+ timeSize = 4
+ timeStampIndex = tfdtI + 16
+ timeStamp = int(F.Btoi32(buf, tfdtI+16))
+ case 1:
+ timeSize = 8
+ timeStampIndex = tfdtI + 12
+ timeStamp = int(F.Btoi64(buf, tfdtI+12))
+ }
+
+ track, ok := t.traks[int(F.Btoi32(buf, tfhdI+12))]
+ if !ok {
+ err = errors.New("找不到trak")
+ // log.Default().Println(`cant find trak`, int(F.Btoi32(buf, tfhdI+12)))
+ continue
+ }
+
+ switch track.handlerType {
+ case 'v':
+ videoTime = float64(timeStamp) / float64(track.timescale)
+ case 's':
+ audioTimeIndex = timeStampIndex
+ audioTimeSize = timeSize
+ audioTimeScale = track.timescale
+ audioTime = float64(timeStamp) / float64(track.timescale)
}
if !iskeyFrame && buf[trunI+20] == byte(0x02) {
break
}
+ //change audio timeStamp
+ if audioTime != videoTime {
+ // err = errors.New("重新设置音频时间戳")
+ switch audioTimeSize {
+ case 4:
+ // log.Default().Println("set audio to:", int32(videoTime*float64(audioTimeScale)))
+ date := F.Itob32(int32(videoTime * float64(audioTimeScale)))
+ for i := 0; i < audioTimeSize; i += 1 {
+ buf[audioTimeIndex+i] = date[i]
+ }
+ case 8:
+ // log.Default().Println("set audio to:", int64(videoTime*float64(audioTimeScale)))
+ date := F.Itob64(int64(videoTime * float64(audioTimeScale)))
+ for i := 0; i < audioTimeSize; i += 1 {
+ buf[audioTimeIndex+i] = date[i]
+ }
+ }
+ }
+
if iskeyFrame {
last_avilable_offset = moofI - 1
- if len(keyframe.data) != 0 {
+ if len(keyframe) != 0 {
keyframes = append(keyframes, keyframe)
}
- keyframe = fmp4KeyFrame{
- videoTime: videoTime,
- audioTime: audioTime,
- }
+ keyframe = []byte{}
}
//mdat
- mdatI := cu + bytes.Index(buf[cu:], []byte("mdat")) - 4
+ mdatI := bytes.Index(buf[cu:], []byte("mdat"))
if moofI == -1 {
err = errors.New("未找到mdat包")
break
}
+ mdatI = cu + mdatI - 4
cu = mdatI
mdatE := mdatI + int(F.Btoi32(buf, mdatI))
if mdatE > len(buf) {
break
}
- keyframe.data = append(keyframe.data, buf[moofI:mdatE]...)
- cu = mdatE
+ keyframe = append(keyframe, buf[moofI:mdatE]...)
}
return
//
var (
- buf []byte
- lastVideoTime int
- lastAudioTime int
- diffVideoTime int
- diffAudioTime int
- diffSumVideoTime int
- diffSumAudioTime int
+ buf []byte
+ fmp4Decoder = &Fmp4Decoder{}
)
// 下载循环
buf = append(buf, v.data...)
if strings.Contains(v.Base, `h`) {
+ if e := fmp4Decoder.Init_fmp4(v.data); e != nil {
+ t.log.L(`E: `, e)
+ } else {
+ for _, trak := range fmp4Decoder.traks {
+ t.log.L(`T: `, "找到trak:", string(trak.handlerType), trak.trackID, trak.timescale)
+ }
+ }
t.first_buf = v.data
if t.config.save_as_mp4 {
out.Write(v.data)
continue
}
- fmp4KeyFrames, last_avilable_offset, e := Seach_stream_fmp4(buf)
+ fmp4KeyFrames, last_avilable_offset, e := fmp4Decoder.Seach_stream_fmp4(buf)
if e != nil {
t.log.L(`E: `, e)
}
for _, fmp4KeyFrame := range fmp4KeyFrames {
- { // 视频时间戳
- if lastVideoTime != 0 {
- if diffVideoTime != 0 {
- diffSumVideoTime = fmp4KeyFrame.videoTime - lastVideoTime - diffVideoTime
- }
- diffVideoTime = fmp4KeyFrame.videoTime - lastVideoTime
- }
- lastVideoTime = fmp4KeyFrame.videoTime
- }
- { // 音频时间戳
- if lastAudioTime != 0 {
- if diffAudioTime != 0 {
- diffSumAudioTime = fmp4KeyFrame.audioTime - lastAudioTime - diffAudioTime
- }
- diffAudioTime = fmp4KeyFrame.audioTime - lastAudioTime
- }
- lastAudioTime = fmp4KeyFrame.audioTime
- }
-
- if diffAudioTime != 0 && diffVideoTime != 0 {
- if math.Abs(float64(diffSumVideoTime)) < 5000 && math.Abs(float64(diffSumAudioTime)) < 5000 {
- t.bootBufPush(fmp4KeyFrame.data)
- t.Stream_msg.Push_tag(`data`, fmp4KeyFrame.data)
- if t.config.save_as_mp4 {
- out.Write(fmp4KeyFrame.data)
- }
- } else {
- t.log.L(`W: `, `时间戳失去同步`)
- }
+ t.bootBufPush(fmp4KeyFrame)
+ t.Stream_msg.Push_tag(`data`, fmp4KeyFrame)
+ if t.config.save_as_mp4 {
+ out.Write(fmp4KeyFrame)
}
}