Files
monibuca/plugin/mp4/pkg/video.go
cto-new[bot] de348725b7 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>
2025-10-21 09:38:00 +08:00

81 lines
2.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}