From: qydysky <32743305+qydysky@users.noreply.github.com> Date: Mon, 31 Oct 2022 18:57:12 +0000 (+0800) Subject: MP4自动调整音频时间戳 X-Git-Tag: v0.5.10 X-Git-Url: http://127.0.0.1:8081/?a=commitdiff_plain;h=228cb9ea9316e2c01aa2b9367f6c3ae6794f35c3;p=bili_danmu%2F.git MP4自动调整音频时间戳 --- diff --git a/F/B_I.go b/F/B_I.go index 11c02ef..8c93fa2 100644 --- a/F/B_I.go +++ b/F/B_I.go @@ -9,9 +9,19 @@ import ( /* 整数 字节转换区 +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) @@ -30,6 +40,15 @@ func Itob16(num int16) []byte { 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) @@ -48,10 +67,23 @@ func btoi16(b []byte) int16 { 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]) } diff --git a/F/B_I_test.go b/F/B_I_test.go new file mode 100644 index 0000000..bd1bc9c --- /dev/null +++ b/F/B_I_test.go @@ -0,0 +1,11 @@ +package F + +import "testing" + +func TestBtoi32(t *testing.T) { + t.Log(Btoi64([]byte{0xd6, 0xfd, 0x62, 0x50}, 0)) +} + +func TestItob32(t *testing.T) { + t.Log(Itob64(1131984000)) +} diff --git a/Reply/fmp4Decode.go b/Reply/fmp4Decode.go index ef7ed5a..919488a 100644 --- a/Reply/fmp4Decode.go +++ b/Reply/fmp4Decode.go @@ -7,58 +7,176 @@ import ( 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 { @@ -67,11 +185,12 @@ func Seach_stream_fmp4(buf []byte) (keyframes []fmp4KeyFrame, last_avilable_offs } //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 { @@ -79,11 +198,37 @@ func Seach_stream_fmp4(buf []byte) (keyframes []fmp4KeyFrame, last_avilable_offs 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) { @@ -95,23 +240,40 @@ func Seach_stream_fmp4(buf []byte) (keyframes []fmp4KeyFrame, last_avilable_offs 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) { @@ -119,8 +281,7 @@ func Seach_stream_fmp4(buf []byte) (keyframes []fmp4KeyFrame, last_avilable_offs break } - keyframe.data = append(keyframe.data, buf[moofI:mdatE]...) - cu = mdatE + keyframe = append(keyframe, buf[moofI:mdatE]...) } return diff --git a/Reply/stream.go b/Reply/stream.go index 9385789..4ecfc4a 100644 --- a/Reply/stream.go +++ b/Reply/stream.go @@ -639,13 +639,8 @@ func (t *M4SStream) saveStreamM4s() (e error) { // var ( - buf []byte - lastVideoTime int - lastAudioTime int - diffVideoTime int - diffAudioTime int - diffSumVideoTime int - diffSumAudioTime int + buf []byte + fmp4Decoder = &Fmp4Decoder{} ) // 下载循环 @@ -729,6 +724,13 @@ func (t *M4SStream) saveStreamM4s() (e error) { 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) @@ -736,41 +738,16 @@ func (t *M4SStream) saveStreamM4s() (e error) { 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) } }