mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-12-24 13:48:04 +08:00
* 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>
81 lines
2.1 KiB
Go
81 lines
2.1 KiB
Go
package mp4
|
||
|
||
import (
|
||
"fmt"
|
||
|
||
"m7s.live/v5/pkg"
|
||
"m7s.live/v5/pkg/codec"
|
||
"m7s.live/v5/pkg/util"
|
||
)
|
||
|
||
var _ pkg.IAVFrame = (*VideoFrame)(nil)
|
||
|
||
type VideoFrame struct {
|
||
pkg.Sample
|
||
}
|
||
|
||
func (v *VideoFrame) Demux() (err error) {
|
||
if v.Size == 0 {
|
||
return fmt.Errorf("no video data to demux")
|
||
}
|
||
|
||
reader := v.NewReader()
|
||
// 根据编解码器类型进行解复用
|
||
switch ctx := v.ICodecCtx.(type) {
|
||
case *codec.H264Ctx:
|
||
// 对于 H.264,解析 AVCC 格式的 NAL 单元
|
||
if err := v.ParseAVCC(&reader, int(ctx.RecordInfo.LengthSizeMinusOne)+1); err != nil {
|
||
return fmt.Errorf("failed to parse H.264 AVCC: %w", err)
|
||
}
|
||
case *codec.H265Ctx:
|
||
// 对于 H.265,解析 AVCC 格式的 NAL 单元
|
||
if err := v.ParseAVCC(&reader, int(ctx.RecordInfo.LengthSizeMinusOne)+1); err != nil {
|
||
return fmt.Errorf("failed to parse H.265 AVCC: %w", err)
|
||
}
|
||
case *codec.AV1Ctx:
|
||
if err := v.ParseAV1OBUs(&reader); err != nil {
|
||
return fmt.Errorf("failed to parse AV1 OBUs: %w", err)
|
||
}
|
||
default:
|
||
// 对于其他格式,尝试默认的 AVCC 解析(4字节长度前缀)
|
||
if err := v.ParseAVCC(&reader, 4); err != nil {
|
||
return fmt.Errorf("failed to parse AVCC with default settings: %w", err)
|
||
}
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
// Mux implements pkg.IAVFrame.
|
||
func (v *VideoFrame) Mux(sample *pkg.Sample) (err error) {
|
||
v.InitRecycleIndexes(0)
|
||
v.ICodecCtx = sample.GetBase()
|
||
switch rawData := sample.Raw.(type) {
|
||
case *pkg.Nalus:
|
||
var naluSizeLen int = 4
|
||
switch ctx := sample.ICodecCtx.(type) {
|
||
case *codec.AV1Ctx:
|
||
for obu := range rawData.RangePoint {
|
||
util.PutBE(v.NextN(4), obu.Size)
|
||
v.Push(obu.Buffers...)
|
||
}
|
||
return
|
||
case *codec.H264Ctx:
|
||
naluSizeLen = int(ctx.RecordInfo.LengthSizeMinusOne) + 1
|
||
case *codec.H265Ctx:
|
||
naluSizeLen = int(ctx.RecordInfo.LengthSizeMinusOne) + 1
|
||
}
|
||
for nalu := range rawData.RangePoint {
|
||
util.PutBE(v.NextN(naluSizeLen), nalu.Size)
|
||
v.Push(nalu.Buffers...)
|
||
}
|
||
}
|
||
return
|
||
}
|
||
|
||
// String implements pkg.IAVFrame.
|
||
func (v *VideoFrame) String() string {
|
||
return fmt.Sprintf("MP4Video[ts:%s, cts:%s, size:%d, keyframe:%t]",
|
||
v.Timestamp, v.CTS, v.Size, v.IDR)
|
||
}
|