feat(codec): Add unified AV1 raw format and protocol mux/demux support (#354)

* cherry-pick 95191a3: AV1 raw format support and protocol mux/demux integration

* feat(rtp/av1): 完善 AV1 RTP 封装分片及关键帧检测

- Implements RTP packetization for AV1 with OBU fragmentation per RFC9304
- Adds accurate detection of AV1 keyframes using OBU inspection
- Updates AV1 RTP demuxing to reconstruct fragmented OBUs
- Ensures keyframe (IDR) flag is set correctly throughout mux/demux pipeline

---------

Co-authored-by: engine-labs-app[bot] <140088366+engine-labs-app[bot]@users.noreply.github.com>
This commit is contained in:
cto-new[bot]
2025-10-20 19:24:47 +08:00
committed by langhuihui
parent d2bd4b2c7a
commit de348725b7
5 changed files with 239 additions and 37 deletions
+13 -14
View File
@@ -51,7 +51,7 @@ type (
AudioData = gomem.Memory
OBUs AudioData
OBUs = util.ReuseArray[gomem.Memory]
AVFrame struct {
DataFrame
@@ -148,6 +148,13 @@ func (b *BaseSample) GetNalus() *Nalus {
return b.Raw.(*Nalus)
}
func (b *BaseSample) GetOBUs() *OBUs {
if b.Raw == nil {
b.Raw = &OBUs{}
}
return b.Raw.(*OBUs)
}
func (b *BaseSample) GetAudioData() *AudioData {
if b.Raw == nil {
b.Raw = &AudioData{}
@@ -203,21 +210,21 @@ func (df *DataFrame) Ready() {
df.Unlock()
}
func (obus *OBUs) ParseAVCC(reader *gomem.MemoryReader) error {
func (b *BaseSample) ParseAV1OBUs(reader *gomem.MemoryReader) error {
var obuHeader av1.OBUHeader
startLen := reader.Length
for reader.Length > 0 {
offset := reader.Size - reader.Length
b, err := reader.ReadByte()
b0, err := reader.ReadByte()
if err != nil {
return err
}
err = obuHeader.Unmarshal([]byte{b})
err = obuHeader.Unmarshal([]byte{b0})
if err != nil {
return err
}
// if log.Trace {
// vt.Trace("obu", zap.Any("type", obuHeader.Type), zap.Bool("iframe", vt.Value.IFrame))
// vt.Trace("obu", zap.Any("type", obuHeader.Type), zap.Bool("iframe", vt.Value.IFrame))
// }
obuSize, _, _ := reader.LEB128Unmarshal()
end := reader.Size - reader.Length
@@ -227,15 +234,7 @@ func (obus *OBUs) ParseAVCC(reader *gomem.MemoryReader) error {
if err != nil {
return err
}
(*AudioData)(obus).PushOne(obu)
b.GetNalus().GetNextPointer().PushOne(obu)
}
return nil
}
func (obus *OBUs) Reset() {
((*gomem.Memory)(obus)).Reset()
}
func (obus *OBUs) Count() int {
return (*gomem.Memory)(obus).Count()
}
+41
View File
@@ -129,3 +129,44 @@ func (r *H26xFrame) GetSize() (ret int) {
func (h *H26xFrame) String() string {
return fmt.Sprintf("H26xFrame{FourCC: %s, Timestamp: %s, CTS: %s}", h.FourCC, h.Timestamp, h.CTS)
}
var _ pkg.IAVFrame = (*AV1Frame)(nil)
type AV1Frame struct {
pkg.Sample
}
func (a *AV1Frame) CheckCodecChange() (err error) {
if a.ICodecCtx == nil {
return pkg.ErrUnsupportCodec
}
return nil
}
func (a *AV1Frame) GetSize() (ret int) {
if obus, ok := a.Raw.(*pkg.OBUs); ok {
for obu := range obus.RangePoint {
ret += obu.Size
}
}
return
}
func (a *AV1Frame) Demux() error {
a.Raw = &a.Memory
return nil
}
func (a *AV1Frame) Mux(from *pkg.Sample) (err error) {
a.InitRecycleIndexes(0)
obus := from.Raw.(*pkg.OBUs)
for obu := range obus.RangePoint {
a.Push(obu.Buffers...)
}
a.ICodecCtx = from.GetBase()
return
}
func (a *AV1Frame) String() string {
return fmt.Sprintf("AV1Frame{FourCC: %s, Timestamp: %s, CTS: %s}", a.FourCC, a.Timestamp, a.CTS)
}