p "github.com/qydysky/part"
)
+
/*
- 整数 字节转换区
- 32 4字节
- 16 2字节
+整数 字节转换区
+32 4字节
+16 2字节
*/
func Itob32(num int32) []byte {
var buffer bytes.Buffer
err := binary.Write(&buffer, binary.BigEndian, num)
- if err != nil {p.Logf().E(err)}
+ if err != nil {
+ p.Logf().E(err)
+ }
return buffer.Bytes()
}
func Itob16(num int16) []byte {
var buffer bytes.Buffer
err := binary.Write(&buffer, binary.BigEndian, num)
- if err != nil {p.Logf().E(err)}
+ if err != nil {
+ p.Logf().E(err)
+ }
return buffer.Bytes()
}
func btoi32(b []byte) int32 {
var buffer int32
err := binary.Read(bytes.NewReader(b), binary.BigEndian, &buffer)
- if err != nil {p.Logf().E(err)}
+ if err != nil {
+ p.Logf().E(err)
+ }
return buffer
}
func btoi16(b []byte) int16 {
var buffer int16
err := binary.Read(bytes.NewReader(b), binary.BigEndian, &buffer)
- if err != nil {p.Logf().E(err)}
+ if err != nil {
+ p.Logf().E(err)
+ }
return buffer
}
func Btoi32(b []byte, offset int) int32 {
- return btoi32(b[offset:offset+4])
+ return btoi32(b[offset : offset+4])
}
func Btoi16(b []byte, offset int) int16 {
- return btoi16(b[offset:offset+2])
-}
\ No newline at end of file
+ return btoi16(b[offset : offset+2])
+}
--- /dev/null
+package reply
+
+import (
+ "bytes"
+ "errors"
+
+ F "github.com/qydysky/bili_danmu/F"
+)
+
+type fmp4KeyFrame struct {
+ videoTime int
+ audioTime int
+ data []byte
+}
+
+func Seach_stream_fmp4(buf []byte) (keyframes []fmp4KeyFrame, last_avilable_offset int, err error) {
+ var (
+ cu int
+ keyframe fmp4KeyFrame
+ )
+
+ for cu < len(buf) {
+ //moof
+ moofI := cu + bytes.Index(buf[cu:], []byte("moof")) - 4
+ if moofI == -1 {
+ err = errors.New("未找到moof包")
+ break
+ }
+ moofE := moofI + int(F.Btoi32(buf, moofI))
+ if moofE > len(buf) {
+ break
+ }
+ cu = moofI
+
+ var (
+ iskeyFrame bool
+ videoTime int
+ audioTime int
+ )
+
+ for trafCount := 0; trafCount < 2 && cu < moofE; trafCount += 1 {
+
+ //traf
+ trafI := cu + bytes.Index(buf[cu:], []byte("traf")) - 4
+ if trafI == -1 {
+ err = errors.New("未找到traf包")
+ break
+ }
+ cu = trafI
+ trafE := trafI + int(F.Btoi32(buf, trafI))
+ if trafE > moofE {
+ err = errors.New("traf包破损")
+ break
+ }
+
+ //tfdt
+ tfdtI := cu + bytes.Index(buf[cu:], []byte("tfdt")) - 4
+ if tfdtI == -1 {
+ err = errors.New("未找到tfdt包")
+ break
+ }
+ cu = tfdtI
+ tfdtE := tfdtI + int(F.Btoi32(buf, tfdtI))
+ if tfdtE > trafE {
+ err = errors.New("tfdt包破损")
+ break
+ }
+
+ //trun
+ trunI := cu + bytes.Index(buf[cu:], []byte("trun")) - 4
+ if trunI == -1 {
+ err = errors.New("未找到trun包")
+ break
+ }
+ cu = trunI
+ trunE := trunI + int(F.Btoi32(buf, trunI))
+ if trunE > trafE {
+ err = errors.New("trun包破损")
+ break
+ }
+
+ timeStamp := int(F.Btoi32(buf, tfdtI+16))
+ if trafCount == 0 {
+ videoTime = timeStamp
+ } else if trafCount == 1 {
+ audioTime = timeStamp
+ }
+
+ if !iskeyFrame && buf[trunI+20] == byte(0x02) {
+ iskeyFrame = true
+ }
+ }
+
+ if err != nil {
+ break
+ }
+
+ if iskeyFrame {
+ last_avilable_offset = moofI - 1
+ if len(keyframe.data) != 0 {
+ keyframes = append(keyframes, keyframe)
+ }
+ keyframe = fmp4KeyFrame{
+ videoTime: videoTime,
+ audioTime: audioTime,
+ }
+ }
+
+ //mdat
+ mdatI := cu + bytes.Index(buf[cu:], []byte("mdat")) - 4
+ if moofI == -1 {
+ err = errors.New("未找到mdat包")
+ break
+ }
+ cu = mdatI
+ mdatE := mdatI + int(F.Btoi32(buf, mdatI))
+ if mdatE > len(buf) {
+ err = errors.New("mdat包破损")
+ break
+ }
+
+ keyframe.data = append(keyframe.data, buf[moofI:mdatE]...)
+ cu = mdatE
+ }
+
+ return
+}
defer out.Close()
}
+ //
+ var (
+ buf []byte
+ lastVideoTime int
+ lastAudioTime int
+ diffVideoTime int
+ diffAudioTime int
+ diffSumVideoTime int
+ diffSumAudioTime int
+ )
+
// 下载循环
for download_seq := []*m4s_link_item{}; ; {
// 传递已下载切片
{
for _, v := range download_seq {
- if strings.Contains(v.Base, `h`) {
- t.first_buf = v.data
- }
-
if v.status == 2 {
download_seq = download_seq[1:]
- t.bootBufPush(v.data)
- t.Stream_msg.Push_tag(`data`, v.data)
- if t.config.save_as_mp4 {
- out.Write(v.data)
+ buf = append(buf, v.data...)
+
+ if strings.Contains(v.Base, `h`) {
+ 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)
+ 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: `, `时间戳失去同步`)
+ }
+ }
+ }
+
+ if last_avilable_offset > 0 {
+ buf = buf[last_avilable_offset:]
}
} else {
break
-20210515230141
+20221031054700
\ No newline at end of file
package bili_danmu
import (
+ _ "embed"
"flag"
"fmt"
"net/url"
ws "github.com/qydysky/part/websocket"
)
+//go:embed VERSION
+var version string
+
func init() {
go func() { //日期变化
var old = time.Now().Hour()
var stop = sys.Sys().PreventSleep()
defer stop.Done()
+ danmulog.L(`I: `, "version: ", version)
+
//ctrl+c退出
interrupt := make(chan os.Signal, 2)
go func() {