package sei import ( "github.com/deepch/vdk/codec/h265parser" "github.com/langhuihui/gomem" "m7s.live/v5" "m7s.live/v5/pkg" "m7s.live/v5/pkg/codec" "m7s.live/v5/pkg/format" "m7s.live/v5/pkg/util" ) type Transformer struct { m7s.DefaultTransformer data chan util.Buffer } func (t *Transformer) AddSEI(tp byte, data []byte) { l := len(data) var buffer util.Buffer buffer.WriteByte(tp) for l >= 255 { buffer.WriteByte(255) l -= 255 } buffer.WriteByte(byte(l)) buffer.Write(data) buffer.WriteByte(0x80) if len(t.data) == cap(t.data) { <-t.data } t.data <- buffer } func NewTransform() m7s.ITransformer { ret := &Transformer{ data: make(chan util.Buffer, 10), } return ret } func (t *Transformer) Start() (err error) { return t.TransformJob.Subscribe() } func (t *Transformer) Run() (err error) { err = t.TransformJob.Publish(t.TransformJob.Config.Output[0].StreamPath) if err != nil { return } pub := t.TransformJob.Publisher allocator := gomem.NewScalableMemoryAllocator(1 << gomem.MinPowerOf2) defer allocator.Recycle() writer := m7s.NewPublisherWriter[*format.RawAudio, *format.H26xFrame](pub, allocator) return m7s.PlayBlock(t.TransformJob.Subscriber, func(audio *format.RawAudio) (err error) { writer.AudioFrame.ICodecCtx = audio.ICodecCtx *writer.AudioFrame.BaseSample = *audio.BaseSample audio.CopyTo(writer.AudioFrame.NextN(audio.Size)) err = writer.NextAudio() return }, func(video *format.H26xFrame) (err error) { writer.VideoFrame.ICodecCtx = video.ICodecCtx *writer.VideoFrame.BaseSample = *video.BaseSample nalus := writer.VideoFrame.GetNalus() var seis [][]byte continueLoop := true for continueLoop { select { case seiFrame := <-t.data: seis = append(seis, seiFrame) default: continueLoop = false } } seiCount := len(seis) writer.VideoFrame.InitRecycleIndexes(video.Raw.Count()) for nalu := range video.Raw.(*pkg.Nalus).RangePoint { p := nalus.GetNextPointer() mem := writer.VideoFrame.NextN(nalu.Size) nalu.CopyTo(mem) if seiCount > 0 { switch video.ICodecCtx.FourCC() { case codec.FourCC_H264: switch codec.ParseH264NALUType(mem[0]) { case codec.NALU_IDR_Picture, codec.NALU_Non_IDR_Picture: for _, sei := range seis { p.Push(append([]byte{byte(codec.NALU_SEI)}, sei...)) } } case codec.FourCC_H265: if naluType := codec.ParseH265NALUType(mem[0]); naluType < 21 { for _, sei := range seis { p.Push(append([]byte{byte(0b10000000 | byte(h265parser.NAL_UNIT_PREFIX_SEI<<1))}, sei...)) } } } } p.PushOne(mem) } if seiCount > 0 { t.Info("insert sei", "count", seiCount) } err = writer.NextVideo() return }) } func (t *Transformer) Dispose() { close(t.data) }