mirror of
https://github.com/Monibuca/engine.git
synced 2025-10-05 16:46:58 +08:00
优化amf读取
This commit is contained in:
@@ -76,7 +76,7 @@ type AVTrack interface {
|
|||||||
CurrentFrame() *AVFrame
|
CurrentFrame() *AVFrame
|
||||||
Attach()
|
Attach()
|
||||||
Detach()
|
Detach()
|
||||||
WriteAVCC(ts uint32, frame util.BLL) //写入AVCC格式的数据
|
WriteAVCC(ts uint32, frame util.BLL) error //写入AVCC格式的数据
|
||||||
WriteRTP([]byte)
|
WriteRTP([]byte)
|
||||||
WriteRTPPack(*rtp.Packet)
|
WriteRTPPack(*rtp.Packet)
|
||||||
Flush()
|
Flush()
|
||||||
|
@@ -27,12 +27,16 @@ const (
|
|||||||
SUBSTATE_NORMAL
|
SUBSTATE_NORMAL
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AVCC 格式的序列帧
|
||||||
type VideoDeConf []byte
|
type VideoDeConf []byte
|
||||||
|
|
||||||
|
// AVCC 格式的序列帧
|
||||||
type AudioDeConf []byte
|
type AudioDeConf []byte
|
||||||
type AudioFrame struct {
|
type AudioFrame struct {
|
||||||
*AVFrame
|
*AVFrame
|
||||||
AbsTime uint32
|
AbsTime uint32
|
||||||
PTS uint32
|
PTS uint32
|
||||||
|
DTS uint32
|
||||||
}
|
}
|
||||||
type VideoFrame struct {
|
type VideoFrame struct {
|
||||||
*AVFrame
|
*AVFrame
|
||||||
@@ -168,13 +172,13 @@ func (s *Subscriber) PlayBlock(subType byte) {
|
|||||||
s.TrackPlayer.Context, s.TrackPlayer.CancelFunc = context.WithCancel(s.IO)
|
s.TrackPlayer.Context, s.TrackPlayer.CancelFunc = context.WithCancel(s.IO)
|
||||||
ctx := s.TrackPlayer.Context
|
ctx := s.TrackPlayer.Context
|
||||||
sendVideoDecConf := func() {
|
sendVideoDecConf := func() {
|
||||||
|
spesic.OnEvent(s.Video.ParamaterSets)
|
||||||
spesic.OnEvent(VideoDeConf(s.VideoReader.Track.SequenceHead))
|
spesic.OnEvent(VideoDeConf(s.VideoReader.Track.SequenceHead))
|
||||||
}
|
}
|
||||||
sendAudioDecConf := func() {
|
sendAudioDecConf := func() {
|
||||||
spesic.OnEvent(AudioDeConf(s.AudioReader.Track.SequenceHead))
|
spesic.OnEvent(AudioDeConf(s.AudioReader.Track.SequenceHead))
|
||||||
}
|
}
|
||||||
var sendVideoFrame func(*AVFrame)
|
var sendAudioFrame, sendVideoFrame func(*AVFrame)
|
||||||
var sendAudioFrame func(*AVFrame)
|
|
||||||
switch subType {
|
switch subType {
|
||||||
case SUBTYPE_RAW:
|
case SUBTYPE_RAW:
|
||||||
sendVideoFrame = func(frame *AVFrame) {
|
sendVideoFrame = func(frame *AVFrame) {
|
||||||
@@ -183,7 +187,7 @@ func (s *Subscriber) PlayBlock(subType byte) {
|
|||||||
}
|
}
|
||||||
sendAudioFrame = func(frame *AVFrame) {
|
sendAudioFrame = func(frame *AVFrame) {
|
||||||
// println("a", frame.Sequence, s.AudioReader.AbsTime)
|
// println("a", frame.Sequence, s.AudioReader.AbsTime)
|
||||||
spesic.OnEvent(AudioFrame{frame, s.AudioReader.AbsTime, frame.DTS - s.VideoReader.SkipTs*90})
|
spesic.OnEvent(AudioFrame{frame, s.AudioReader.AbsTime, s.AudioReader.AbsTime * 90, s.AudioReader.AbsTime * 90})
|
||||||
}
|
}
|
||||||
case SUBTYPE_RTP:
|
case SUBTYPE_RTP:
|
||||||
var videoSeq, audioSeq uint16
|
var videoSeq, audioSeq uint16
|
||||||
@@ -201,7 +205,7 @@ func (s *Subscriber) PlayBlock(subType byte) {
|
|||||||
audioSeq++
|
audioSeq++
|
||||||
vp := *p
|
vp := *p
|
||||||
vp.Header.SequenceNumber = audioSeq
|
vp.Header.SequenceNumber = audioSeq
|
||||||
vp.Header.Timestamp = vp.Header.Timestamp - s.VideoReader.SkipTs*90
|
vp.Header.Timestamp = vp.Header.Timestamp - s.AudioReader.SkipTs*90
|
||||||
spesic.OnEvent((AudioRTP)(vp))
|
spesic.OnEvent((AudioRTP)(vp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,10 +229,11 @@ func (s *Subscriber) PlayBlock(subType byte) {
|
|||||||
// spesic.OnEvent(FLVFrame(copyBuffers(s.Audio.Track.DecoderConfiguration.FLV)))
|
// spesic.OnEvent(FLVFrame(copyBuffers(s.Audio.Track.DecoderConfiguration.FLV)))
|
||||||
}
|
}
|
||||||
sendVideoFrame = func(frame *AVFrame) {
|
sendVideoFrame = func(frame *AVFrame) {
|
||||||
// println(frame.Sequence, frame.AbsTime, frame.DeltaTime, frame.IFrame)
|
// println(frame.Sequence, s.VideoReader.AbsTime, frame.DeltaTime, frame.IFrame)
|
||||||
sendFlvFrame(codec.FLV_TAG_TYPE_VIDEO, s.VideoReader.AbsTime, frame.AVCC.ToBuffers()...)
|
sendFlvFrame(codec.FLV_TAG_TYPE_VIDEO, s.VideoReader.AbsTime, frame.AVCC.ToBuffers()...)
|
||||||
}
|
}
|
||||||
sendAudioFrame = func(frame *AVFrame) {
|
sendAudioFrame = func(frame *AVFrame) {
|
||||||
|
// println(frame.Sequence, s.AudioReader.AbsTime, frame.DeltaTime)
|
||||||
sendFlvFrame(codec.FLV_TAG_TYPE_AUDIO, s.AudioReader.AbsTime, frame.AVCC.ToBuffers()...)
|
sendFlvFrame(codec.FLV_TAG_TYPE_AUDIO, s.AudioReader.AbsTime, frame.AVCC.ToBuffers()...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -237,32 +242,49 @@ func (s *Subscriber) PlayBlock(subType byte) {
|
|||||||
if s.Args.Has(s.Config.SubModeArgName) {
|
if s.Args.Has(s.Config.SubModeArgName) {
|
||||||
subMode, _ = strconv.Atoi(s.Args.Get(s.Config.SubModeArgName))
|
subMode, _ = strconv.Atoi(s.Args.Get(s.Config.SubModeArgName))
|
||||||
}
|
}
|
||||||
|
var videoFrame, audioFrame *AVFrame
|
||||||
for ctx.Err() == nil {
|
for ctx.Err() == nil {
|
||||||
hasVideo, hasAudio := s.VideoReader.Track != nil && s.Config.SubVideo, s.AudioReader.Track != nil && s.Config.SubAudio
|
hasVideo, hasAudio := s.VideoReader.Track != nil && s.Config.SubVideo, s.AudioReader.Track != nil && s.Config.SubAudio
|
||||||
if hasVideo {
|
if hasVideo {
|
||||||
|
if videoFrame != nil {
|
||||||
|
sendVideoFrame(videoFrame)
|
||||||
|
videoFrame = nil
|
||||||
|
}
|
||||||
for ctx.Err() == nil {
|
for ctx.Err() == nil {
|
||||||
s.VideoReader.Read(ctx, subMode)
|
s.VideoReader.Read(ctx, subMode)
|
||||||
frame := s.VideoReader.Frame
|
frame := s.VideoReader.Frame
|
||||||
// println("video", frame.Sequence, frame.AbsTime)
|
// println("video", frame.Sequence, frame.AbsTime)
|
||||||
if frame == nil {
|
if frame == nil || ctx.Err() != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if audioFrame != nil {
|
||||||
|
if frame.AbsTime > audioFrame.AbsTime {
|
||||||
|
sendAudioFrame(audioFrame)
|
||||||
|
audioFrame = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
if frame.IFrame && s.VideoReader.DecConfChanged() {
|
if frame.IFrame && s.VideoReader.DecConfChanged() {
|
||||||
s.VideoReader.ConfSeq = s.VideoReader.Track.SequenceHeadSeq
|
s.VideoReader.ConfSeq = s.VideoReader.Track.SequenceHeadSeq
|
||||||
// println(s.Video.confSeq, s.Video.Track.SPSInfo.Width, s.Video.Track.SPSInfo.Height)
|
// println(s.Video.confSeq, s.Video.Track.SPSInfo.Width, s.Video.Track.SPSInfo.Height)
|
||||||
sendVideoDecConf()
|
sendVideoDecConf()
|
||||||
}
|
}
|
||||||
if !s.Config.IFrameOnly || frame.IFrame {
|
if !s.Config.IFrameOnly || frame.IFrame {
|
||||||
sendVideoFrame(frame)
|
|
||||||
}
|
|
||||||
if frame.AbsTime > lastPlayAbsTime {
|
if frame.AbsTime > lastPlayAbsTime {
|
||||||
lastPlayAbsTime = frame.AbsTime
|
lastPlayAbsTime = frame.AbsTime
|
||||||
|
videoFrame = frame
|
||||||
break
|
break
|
||||||
|
} else {
|
||||||
|
sendVideoFrame(frame)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 正常模式下或者纯音频模式下,音频开始播放
|
// 正常模式下或者纯音频模式下,音频开始播放
|
||||||
if hasAudio {
|
if hasAudio {
|
||||||
|
if audioFrame != nil {
|
||||||
|
sendAudioFrame(audioFrame)
|
||||||
|
audioFrame = nil
|
||||||
|
}
|
||||||
for ctx.Err() == nil {
|
for ctx.Err() == nil {
|
||||||
switch s.AudioReader.State {
|
switch s.AudioReader.State {
|
||||||
case track.READSTATE_INIT:
|
case track.READSTATE_INIT:
|
||||||
@@ -277,17 +299,25 @@ func (s *Subscriber) PlayBlock(subType byte) {
|
|||||||
s.AudioReader.Read(ctx, subMode)
|
s.AudioReader.Read(ctx, subMode)
|
||||||
frame := s.AudioReader.Frame
|
frame := s.AudioReader.Frame
|
||||||
// println("audio", frame.Sequence, frame.AbsTime)
|
// println("audio", frame.Sequence, frame.AbsTime)
|
||||||
if frame == nil {
|
if frame == nil || ctx.Err() != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if videoFrame != nil {
|
||||||
|
if frame.AbsTime > videoFrame.AbsTime {
|
||||||
|
sendVideoFrame(videoFrame)
|
||||||
|
videoFrame = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
if s.AudioReader.DecConfChanged() {
|
if s.AudioReader.DecConfChanged() {
|
||||||
s.AudioReader.ConfSeq = s.AudioReader.Track.SequenceHeadSeq
|
s.AudioReader.ConfSeq = s.AudioReader.Track.SequenceHeadSeq
|
||||||
sendAudioDecConf()
|
sendAudioDecConf()
|
||||||
}
|
}
|
||||||
sendAudioFrame(frame)
|
|
||||||
if frame.AbsTime > lastPlayAbsTime {
|
if frame.AbsTime > lastPlayAbsTime {
|
||||||
lastPlayAbsTime = frame.AbsTime
|
lastPlayAbsTime = frame.AbsTime
|
||||||
|
audioFrame = frame
|
||||||
break
|
break
|
||||||
|
} else {
|
||||||
|
sendAudioFrame(frame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package track
|
package track
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -100,10 +101,10 @@ func (aac *AAC) WriteAVCCSequenceHead(sh []byte) {
|
|||||||
aac.WriteSequenceHead(append([]byte{0xAF, 0x00}, sh...))
|
aac.WriteSequenceHead(append([]byte{0xAF, 0x00}, sh...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aac *AAC) WriteAVCC(ts uint32, frame util.BLL) {
|
func (aac *AAC) WriteAVCC(ts uint32, frame util.BLL) error {
|
||||||
if l := frame.ByteLength; l < 4 {
|
if l := frame.ByteLength; l < 4 {
|
||||||
aac.Stream.Error("AVCC data too short", zap.Int("len", l))
|
aac.Stream.Error("AVCC data too short", zap.Int("len", l))
|
||||||
return
|
return io.ErrShortWrite
|
||||||
}
|
}
|
||||||
if frame.GetByte(1) == 0 {
|
if frame.GetByte(1) == 0 {
|
||||||
aac.WriteSequenceHead(frame.ToBytes())
|
aac.WriteSequenceHead(frame.ToBytes())
|
||||||
@@ -114,6 +115,7 @@ func (aac *AAC) WriteAVCC(ts uint32, frame util.BLL) {
|
|||||||
aac.AppendAuBytes(au...)
|
aac.AppendAuBytes(au...)
|
||||||
aac.Audio.WriteAVCC(ts, frame)
|
aac.Audio.WriteAVCC(ts, frame)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aac *AAC) CompleteRTP(value *AVFrame) {
|
func (aac *AAC) CompleteRTP(value *AVFrame) {
|
||||||
|
@@ -93,7 +93,7 @@ func (av *Media) SnapForJson() {
|
|||||||
av.RawPart = av.RawPart[:0]
|
av.RawPart = av.RawPart[:0]
|
||||||
}
|
}
|
||||||
av.RawSize = v.AUList.ByteLength
|
av.RawSize = v.AUList.ByteLength
|
||||||
r := v.AUList.Next.Value.NewReader()
|
r := v.AUList.NewReader()
|
||||||
for b, err := r.ReadByte(); err == nil && len(av.RawPart) < 10; b, err = r.ReadByte() {
|
for b, err := r.ReadByte(); err == nil && len(av.RawPart) < 10; b, err = r.ReadByte() {
|
||||||
av.RawPart = append(av.RawPart, int(b))
|
av.RawPart = append(av.RawPart, int(b))
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package track
|
package track
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@@ -36,17 +37,18 @@ type G711 struct {
|
|||||||
Audio
|
Audio
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g711 *G711) WriteAVCC(ts uint32, frame util.BLL) {
|
func (g711 *G711) WriteAVCC(ts uint32, frame util.BLL) error {
|
||||||
if l := frame.ByteLength; l < 2 {
|
if l := frame.ByteLength; l < 2 {
|
||||||
g711.Stream.Error("AVCC data too short", zap.Int("len", l))
|
g711.Stream.Error("AVCC data too short", zap.Int("len", l))
|
||||||
return
|
return io.ErrShortWrite
|
||||||
}
|
}
|
||||||
g711.Value.AUList.Push(g711.BytesPool.GetShell(frame.Next.Value[1:]))
|
g711.Value.AUList.Push(g711.BytesPool.GetShell(frame.Next.Value[1:]))
|
||||||
frame.Next.Range(func(v util.BLI) bool {
|
frame.Range(func(v util.BLI) bool {
|
||||||
g711.Value.AUList.Push(g711.BytesPool.GetShell(v))
|
g711.Value.AUList.Push(g711.BytesPool.GetShell(v))
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
g711.Audio.WriteAVCC(ts, frame)
|
g711.Audio.WriteAVCC(ts, frame)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g711 *G711) WriteRTPFrame(frame *RTPFrame) {
|
func (g711 *G711) WriteRTPFrame(frame *RTPFrame) {
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package track
|
package track
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@@ -65,22 +66,23 @@ func (vt *H264) WriteSliceBytes(slice []byte) {
|
|||||||
case codec.NALU_SEI:
|
case codec.NALU_SEI:
|
||||||
vt.AppendAuBytes(slice)
|
vt.AppendAuBytes(slice)
|
||||||
case codec.NALU_Access_Unit_Delimiter:
|
case codec.NALU_Access_Unit_Delimiter:
|
||||||
|
case codec.NALU_Filler_Data:
|
||||||
default:
|
default:
|
||||||
vt.Stream.Error("H264 WriteSliceBytes naluType not support", zap.Int("naluType", int(naluType)))
|
vt.Stream.Error("H264 WriteSliceBytes naluType not support", zap.Int("naluType", int(naluType)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vt *H264) WriteAVCC(ts uint32, frame util.BLL) {
|
func (vt *H264) WriteAVCC(ts uint32, frame util.BLL) (err error) {
|
||||||
if l := frame.ByteLength; l < 6 {
|
if l := frame.ByteLength; l < 6 {
|
||||||
vt.Stream.Error("AVCC data too short", zap.Int("len", l))
|
vt.Stream.Error("AVCC data too short", zap.Int("len", l))
|
||||||
return
|
return io.ErrShortWrite
|
||||||
}
|
}
|
||||||
if frame.GetByte(1) == 0 {
|
if frame.GetByte(1) == 0 {
|
||||||
vt.SequenceHead = frame.ToBytes()
|
vt.SequenceHead = frame.ToBytes()
|
||||||
frame.Recycle()
|
frame.Recycle()
|
||||||
vt.updateSequeceHead()
|
vt.updateSequeceHead()
|
||||||
var info codec.AVCDecoderConfigurationRecord
|
var info codec.AVCDecoderConfigurationRecord
|
||||||
if _, err := info.Unmarshal(vt.SequenceHead[5:]); err == nil {
|
if _, err = info.Unmarshal(vt.SequenceHead[5:]); err == nil {
|
||||||
vt.SPSInfo, _ = codec.ParseSPS(info.SequenceParameterSetNALUnit)
|
vt.SPSInfo, _ = codec.ParseSPS(info.SequenceParameterSetNALUnit)
|
||||||
vt.nalulenSize = int(info.LengthSizeMinusOne&3 + 1)
|
vt.nalulenSize = int(info.LengthSizeMinusOne&3 + 1)
|
||||||
vt.SPS = info.SequenceParameterSetNALUnit
|
vt.SPS = info.SequenceParameterSetNALUnit
|
||||||
@@ -91,8 +93,9 @@ func (vt *H264) WriteAVCC(ts uint32, frame util.BLL) {
|
|||||||
vt.Stream.Error("H264 ParseSpsPps Error")
|
vt.Stream.Error("H264 ParseSpsPps Error")
|
||||||
vt.Stream.Close()
|
vt.Stream.Close()
|
||||||
}
|
}
|
||||||
|
return
|
||||||
} else {
|
} else {
|
||||||
vt.Video.WriteAVCC(ts, frame)
|
return vt.Video.WriteAVCC(ts, frame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package track
|
package track
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@@ -62,27 +63,25 @@ func (vt *H265) WriteSliceBytes(slice []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vt *H265) WriteAVCC(ts uint32, frame util.BLL) {
|
func (vt *H265) WriteAVCC(ts uint32, frame util.BLL) (err error) {
|
||||||
if l := frame.ByteLength; l < 6 {
|
if l := frame.ByteLength; l < 6 {
|
||||||
vt.Stream.Error("AVCC data too short", zap.Int("len", l))
|
vt.Stream.Error("AVCC data too short", zap.Int("len", l))
|
||||||
return
|
return io.ErrShortWrite
|
||||||
}
|
}
|
||||||
if frame.GetByte(1) == 0 {
|
if frame.GetByte(1) == 0 {
|
||||||
vt.SequenceHead = frame.ToBytes()
|
vt.SequenceHead = frame.ToBytes()
|
||||||
frame.Recycle()
|
frame.Recycle()
|
||||||
vt.updateSequeceHead()
|
vt.updateSequeceHead()
|
||||||
if vps, sps, pps, err := codec.ParseVpsSpsPpsFromSeqHeaderWithoutMalloc(vt.SequenceHead); err == nil {
|
if vt.VPS, vt.SPS, vt.PPS, err = codec.ParseVpsSpsPpsFromSeqHeaderWithoutMalloc(vt.SequenceHead); err == nil {
|
||||||
vt.SPSInfo, _ = codec.ParseHevcSPS(vt.SequenceHead)
|
vt.SPSInfo, _ = codec.ParseHevcSPS(vt.SequenceHead)
|
||||||
vt.nalulenSize = (int(vt.SequenceHead[26]) & 0x03) + 1
|
vt.nalulenSize = (int(vt.SequenceHead[26]) & 0x03) + 1
|
||||||
vt.VPS = vps
|
|
||||||
vt.SPS = sps
|
|
||||||
vt.PPS = pps
|
|
||||||
} else {
|
} else {
|
||||||
vt.Stream.Error("H265 ParseVpsSpsPps Error")
|
vt.Stream.Error("H265 ParseVpsSpsPps Error")
|
||||||
vt.Stream.Close()
|
vt.Stream.Close()
|
||||||
}
|
}
|
||||||
|
return
|
||||||
} else {
|
} else {
|
||||||
vt.Video.WriteAVCC(ts, frame)
|
return vt.Video.WriteAVCC(ts, frame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -101,11 +101,11 @@ func (vt *Video) WriteAnnexB(pts uint32, dts uint32, frame AnnexBFrame) {
|
|||||||
vt.Flush()
|
vt.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vt *Video) WriteAVCC(ts uint32, frame util.BLL) {
|
func (vt *Video) WriteAVCC(ts uint32, frame util.BLL) error {
|
||||||
r := frame.NewReader()
|
r := frame.NewReader()
|
||||||
b, err := r.ReadByte()
|
b, err := r.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
b = b >> 4
|
b = b >> 4
|
||||||
vt.Value.IFrame = b == 1 || b == 4
|
vt.Value.IFrame = b == 1 || b == 4
|
||||||
@@ -113,13 +113,14 @@ func (vt *Video) WriteAVCC(ts uint32, frame util.BLL) {
|
|||||||
vt.Value.WriteAVCC(ts, frame)
|
vt.Value.WriteAVCC(ts, frame)
|
||||||
cts, err := r.ReadBE(3)
|
cts, err := r.ReadBE(3)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
vt.Value.PTS = (ts + cts) * 90
|
vt.Value.PTS = (ts + cts) * 90
|
||||||
for nalulen, err := r.ReadBE(vt.nalulenSize); err == nil; nalulen, err = r.ReadBE(vt.nalulenSize) {
|
for nalulen, err := r.ReadBE(vt.nalulenSize); err == nil; nalulen, err = r.ReadBE(vt.nalulenSize) {
|
||||||
vt.AppendAuBytes(r.ReadN(int(nalulen))...)
|
vt.AppendAuBytes(r.ReadN(int(nalulen))...)
|
||||||
}
|
}
|
||||||
vt.Flush()
|
vt.Flush()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vt *Video) WriteSliceByte(b ...byte) {
|
func (vt *Video) WriteSliceByte(b ...byte) {
|
||||||
|
32
util/amf.go
32
util/amf.go
@@ -83,27 +83,29 @@ type AMF struct {
|
|||||||
Buffer
|
Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (amf *AMF) ReadShortString() string {
|
func ReadAMF[T any](amf *AMF) (result T) {
|
||||||
value, _ := amf.Unmarshal()
|
value, err := amf.Unmarshal()
|
||||||
return value.(string)
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result, _ = value.(T)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (amf *AMF) ReadNumber() float64 {
|
func (amf *AMF) ReadShortString() (result string) {
|
||||||
value, _ := amf.Unmarshal()
|
return ReadAMF[string](amf)
|
||||||
return value.(float64)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (amf *AMF) ReadObject() map[string]any {
|
func (amf *AMF) ReadNumber() (result float64) {
|
||||||
value, _ := amf.Unmarshal()
|
return ReadAMF[float64](amf)
|
||||||
if value == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return value.(map[string]any)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (amf *AMF) ReadBool() bool {
|
func (amf *AMF) ReadObject() (result map[string]any) {
|
||||||
value, _ := amf.Unmarshal()
|
return ReadAMF[map[string]any](amf)
|
||||||
return value.(bool)
|
}
|
||||||
|
|
||||||
|
func (amf *AMF) ReadBool() (result bool) {
|
||||||
|
return ReadAMF[bool](amf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (amf *AMF) readKey() (string, error) {
|
func (amf *AMF) readKey() (string, error) {
|
||||||
|
27
util/pool.go
27
util/pool.go
@@ -69,6 +69,29 @@ func (r *BLLReader) ReadN(n int) (result net.Buffers) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BLLsReader struct {
|
||||||
|
*ListItem[*BLL]
|
||||||
|
BLLReader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *BLLsReader) CanRead() bool {
|
||||||
|
return r.ListItem != nil && !r.IsRoot()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *BLLsReader) ReadByte() (b byte, err error) {
|
||||||
|
if r.BLLReader.CanRead() {
|
||||||
|
b, err = r.BLLReader.ReadByte()
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.ListItem = r.Next
|
||||||
|
if !r.CanRead() {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
r.BLLReader = *r.Value.NewReader()
|
||||||
|
return r.BLLReader.ReadByte()
|
||||||
|
}
|
||||||
type BLLs struct {
|
type BLLs struct {
|
||||||
List[*BLL]
|
List[*BLL]
|
||||||
ByteLength int
|
ByteLength int
|
||||||
@@ -121,6 +144,10 @@ func (list *BLLs) Recycle() {
|
|||||||
list.ByteLength = 0
|
list.ByteLength = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (list *BLLs) NewReader() *BLLsReader {
|
||||||
|
return &BLLsReader{list.Next, *list.Next.Value.NewReader()}
|
||||||
|
}
|
||||||
|
|
||||||
// ByteLinkList
|
// ByteLinkList
|
||||||
type BLL struct {
|
type BLL struct {
|
||||||
List[BLI]
|
List[BLI]
|
||||||
|
Reference in New Issue
Block a user