mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-12-24 13:48:04 +08:00
183 lines
4.3 KiB
Go
183 lines
4.3 KiB
Go
package pkg
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"time"
|
|
|
|
"github.com/deepch/vdk/codec/h264parser"
|
|
"github.com/deepch/vdk/codec/h265parser"
|
|
|
|
"m7s.live/v5/pkg/codec"
|
|
"m7s.live/v5/pkg/util"
|
|
)
|
|
|
|
var _ IAVFrame = (*AnnexB)(nil)
|
|
|
|
type AnnexB struct {
|
|
Hevc bool
|
|
PTS time.Duration
|
|
DTS time.Duration
|
|
util.RecyclableMemory
|
|
}
|
|
|
|
func (a *AnnexB) Dump(t byte, w io.Writer) {
|
|
m := a.GetAllocator().Borrow(4 + a.Size)
|
|
binary.BigEndian.PutUint32(m, uint32(a.Size))
|
|
a.CopyTo(m[4:])
|
|
w.Write(m)
|
|
}
|
|
|
|
// DecodeConfig implements pkg.IAVFrame.
|
|
func (a *AnnexB) ConvertCtx(ctx codec.ICodecCtx) (codec.ICodecCtx, IAVFrame, error) {
|
|
return ctx.GetBase(), nil, nil
|
|
}
|
|
|
|
// GetSize implements pkg.IAVFrame.
|
|
func (a *AnnexB) GetSize() int {
|
|
return a.Size
|
|
}
|
|
|
|
func (a *AnnexB) GetTimestamp() time.Duration {
|
|
return a.DTS * time.Millisecond / 90
|
|
}
|
|
|
|
func (a *AnnexB) GetCTS() time.Duration {
|
|
return (a.PTS - a.DTS) * time.Millisecond / 90
|
|
}
|
|
|
|
// Parse implements pkg.IAVFrame.
|
|
func (a *AnnexB) Parse(t *AVTrack) (err error) {
|
|
if a.Hevc {
|
|
if t.ICodecCtx == nil {
|
|
t.ICodecCtx = &codec.H265Ctx{}
|
|
}
|
|
} else {
|
|
if t.ICodecCtx == nil {
|
|
t.ICodecCtx = &codec.H264Ctx{}
|
|
}
|
|
}
|
|
if t.Value.Raw, err = a.Demux(t.ICodecCtx); err != nil {
|
|
return
|
|
}
|
|
for _, nalu := range t.Value.Raw.(Nalus) {
|
|
if a.Hevc {
|
|
ctx := t.ICodecCtx.(*codec.H265Ctx)
|
|
switch codec.ParseH265NALUType(nalu.Buffers[0][0]) {
|
|
case h265parser.NAL_UNIT_VPS:
|
|
ctx.RecordInfo.VPS = [][]byte{nalu.ToBytes()}
|
|
case h265parser.NAL_UNIT_SPS:
|
|
ctx.RecordInfo.SPS = [][]byte{nalu.ToBytes()}
|
|
case h265parser.NAL_UNIT_PPS:
|
|
ctx.RecordInfo.PPS = [][]byte{nalu.ToBytes()}
|
|
ctx.CodecData, err = h265parser.NewCodecDataFromVPSAndSPSAndPPS(ctx.VPS(), ctx.SPS(), ctx.PPS())
|
|
case h265parser.NAL_UNIT_CODED_SLICE_BLA_W_LP,
|
|
h265parser.NAL_UNIT_CODED_SLICE_BLA_W_RADL,
|
|
h265parser.NAL_UNIT_CODED_SLICE_BLA_N_LP,
|
|
h265parser.NAL_UNIT_CODED_SLICE_IDR_W_RADL,
|
|
h265parser.NAL_UNIT_CODED_SLICE_IDR_N_LP,
|
|
h265parser.NAL_UNIT_CODED_SLICE_CRA:
|
|
t.Value.IDR = true
|
|
}
|
|
} else {
|
|
ctx := t.ICodecCtx.(*codec.H264Ctx)
|
|
switch codec.ParseH264NALUType(nalu.Buffers[0][0]) {
|
|
case codec.NALU_SPS:
|
|
ctx.RecordInfo.SPS = [][]byte{nalu.ToBytes()}
|
|
if len(ctx.RecordInfo.PPS) > 0 {
|
|
ctx.CodecData, err = h264parser.NewCodecDataFromSPSAndPPS(ctx.SPS(), ctx.PPS())
|
|
}
|
|
case codec.NALU_PPS:
|
|
ctx.RecordInfo.PPS = [][]byte{nalu.ToBytes()}
|
|
if len(ctx.RecordInfo.SPS) > 0 {
|
|
ctx.CodecData, err = h264parser.NewCodecDataFromSPSAndPPS(ctx.SPS(), ctx.PPS())
|
|
}
|
|
case codec.NALU_IDR_Picture:
|
|
t.Value.IDR = true
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// String implements pkg.IAVFrame.
|
|
func (a *AnnexB) String() string {
|
|
return fmt.Sprintf("%d %d", a.DTS, a.Memory.Size)
|
|
}
|
|
|
|
// Demux implements pkg.IAVFrame.
|
|
func (a *AnnexB) Demux(codecCtx codec.ICodecCtx) (ret any, err error) {
|
|
var nalus Nalus
|
|
var lastFourBytes [4]byte
|
|
var b byte
|
|
var shallow util.Memory
|
|
shallow.Append(a.Buffers...)
|
|
reader := shallow.NewReader()
|
|
|
|
gotNalu := func() {
|
|
var nalu util.Memory
|
|
for buf := range reader.ClipFront {
|
|
nalu.AppendOne(buf)
|
|
}
|
|
nalus = append(nalus, nalu)
|
|
|
|
}
|
|
|
|
for {
|
|
b, err = reader.ReadByte()
|
|
if err == nil {
|
|
copy(lastFourBytes[:], lastFourBytes[1:])
|
|
lastFourBytes[3] = b
|
|
var startCode = 0
|
|
if lastFourBytes == codec.NALU_Delimiter2 {
|
|
startCode = 4
|
|
} else if [3]byte(lastFourBytes[1:]) == codec.NALU_Delimiter1 {
|
|
startCode = 3
|
|
}
|
|
if startCode > 0 && reader.Offset() >= 3 {
|
|
if reader.Offset() == 3 {
|
|
startCode = 3
|
|
}
|
|
reader.Unread(startCode)
|
|
if reader.Offset() > 0 {
|
|
gotNalu()
|
|
}
|
|
reader.Skip(startCode)
|
|
for range reader.ClipFront {
|
|
}
|
|
}
|
|
} else if err == io.EOF {
|
|
if reader.Offset() > 0 {
|
|
gotNalu()
|
|
}
|
|
err = nil
|
|
break
|
|
}
|
|
}
|
|
ret = nalus
|
|
return
|
|
}
|
|
|
|
func (a *AnnexB) Mux(codecCtx codec.ICodecCtx, frame *AVFrame) {
|
|
a.DTS = frame.Timestamp * 90 / time.Millisecond
|
|
a.PTS = a.DTS + frame.CTS*90/time.Millisecond
|
|
a.InitRecycleIndexes(0)
|
|
delimiter2 := codec.NALU_Delimiter2[:]
|
|
a.AppendOne(delimiter2)
|
|
if frame.IDR {
|
|
switch ctx := codecCtx.(type) {
|
|
case *codec.H264Ctx:
|
|
a.Append(ctx.SPS(), delimiter2, ctx.PPS(), delimiter2)
|
|
case *codec.H265Ctx:
|
|
a.Append(ctx.SPS(), delimiter2, ctx.PPS(), delimiter2, ctx.VPS(), delimiter2)
|
|
}
|
|
}
|
|
for i, nalu := range frame.Raw.(Nalus) {
|
|
if i > 0 {
|
|
a.AppendOne(codec.NALU_Delimiter1[:])
|
|
}
|
|
a.Append(nalu.Buffers...)
|
|
}
|
|
}
|