You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lal/pkg/rtprtcp/rtp_packer_payload_avc_hevc.go

214 lines
4.7 KiB
Go

// Copyright 2021, Chef. All rights reserved.
// https://github.com/q191201771/lal
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package rtprtcp
import (
"github.com/q191201771/lal/pkg/avc"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/lal/pkg/hevc"
)
type RtpPackerPayloadAvcHevcType int
const (
RtpPackerPayloadAvcHevcTypeNalu RtpPackerPayloadAvcHevcType = 1
RtpPackerPayloadAvcHevcTypeAvcc = 2
RtpPackerPayloadAvcHevcTypeAnnexb = 3
)
type RtpPackerPayloadAvcHevcOption struct {
Typ RtpPackerPayloadAvcHevcType
}
var defaultRtpPackerPayloadAvcHevcOption = RtpPackerPayloadAvcHevcOption{
Typ: RtpPackerPayloadAvcHevcTypeNalu,
}
type RtpPackerPayloadAvcHevc struct {
payloadType base.AvPacketPt
option RtpPackerPayloadAvcHevcOption
}
type ModRtpPackerPayloadAvcHevcOption func(option *RtpPackerPayloadAvcHevcOption)
func NewRtpPackerPayloadAvc(modOptions ...ModRtpPackerPayloadAvcHevcOption) *RtpPackerPayloadAvcHevc {
return NewRtpPackerPayloadAvcHevc(base.AvPacketPtAvc, modOptions...)
}
func NewRtpPackerPayloadHevc(modOptions ...ModRtpPackerPayloadAvcHevcOption) *RtpPackerPayloadAvcHevc {
return NewRtpPackerPayloadAvcHevc(base.AvPacketPtHevc, modOptions...)
}
func NewRtpPackerPayloadAvcHevc(payloadType base.AvPacketPt, modOptions ...ModRtpPackerPayloadAvcHevcOption) *RtpPackerPayloadAvcHevc {
option := defaultRtpPackerPayloadAvcHevcOption
for _, fn := range modOptions {
fn(&option)
}
return &RtpPackerPayloadAvcHevc{
payloadType: payloadType,
option: option,
}
}
// Pack @param in: AVCC格式
//
// @return out: 内存块为独立新申请;函数返回后,内部不再持有该内存块
func (r *RtpPackerPayloadAvcHevc) Pack(in []byte, maxSize int) (out [][]byte) {
if in == nil || maxSize <= 0 {
return
}
var splitFn func([]byte) ([][]byte, error)
switch r.option.Typ {
case RtpPackerPayloadAvcHevcTypeAvcc:
splitFn = avc.SplitNaluAvcc
case RtpPackerPayloadAvcHevcTypeAnnexb:
splitFn = avc.SplitNaluAnnexb
default:
// RtpPackerPayloadAvcHevcTypeNalu
return r.PackNal(in, maxSize)
}
nals, err := splitFn(in)
if err != nil {
return
}
for _, nal := range nals {
if r.payloadType == base.AvPacketPtAvc {
if avc.ParseNaluType(nal[0]) == avc.NaluTypeAud {
continue
}
} else {
if hevc.ParseNaluType(nal[0]) == hevc.NaluTypeAud {
continue
}
}
out = append(out, r.PackNal(nal, maxSize)...)
}
return
}
func (r *RtpPackerPayloadAvcHevc) PackNal(nal []byte, maxSize int) (out [][]byte) {
// pack逻辑
//
// avc
//
// 输入
// nri [01, 02]
// nalType [03, 07]
//
// 输出
// nri [01, 02]
// 28 [03, 07] 28是avc fua的nal type
// start [10]
// end [11]
// nalType [13, 17]
//
// hevc
//
// 输入
// nalType [01, 06]
//
// 输出
// 49 [01, 06] 49是hevc fua的nal type
// 1 [10, 17]
// start [20]
// end [21]
// nalType [22, 27] 注意和输入的nalType的所在type字节的位位置不同
//
// single
if len(nal) <= maxSize {
item := make([]byte, len(nal))
copy(item, nal)
out = append(out, item)
return
}
// FU-A
// var
var pktLen int // rtp payload大小
var bpos int
isFirstFlag := true
// const after set
var headerSize int
var sepos int // start-end标志所在位置
var nalType uint8
var nri uint8 // only avc
epos := len(nal)
if r.payloadType == base.AvPacketPtAvc {
// 注意跳过输入的nal type那个字节使用FU-A自己的两个字节的头避免重复
bpos = 1
sepos = 1
headerSize = 2
nalType = nal[0] & 0x1F
nri = nal[0] & 0x60
} else {
bpos = 2
sepos = 2
headerSize = 3
nalType = (nal[0] >> 1) & 0x3F
}
for {
if epos-bpos > maxSize-headerSize {
// 前面的包
pktLen = maxSize
item := make([]byte, pktLen)
if r.payloadType == base.AvPacketPtAvc {
item[0] = NaluTypeAvcFua | nri
item[1] = nalType
} else {
item[0] = NaluTypeHevcFua << 1
item[1] = 1 // ffmpeg, rtpenc_h264_hevc.c, func nal_send
item[2] = nalType
}
// 当前帧切割后的首个RTP包
if isFirstFlag {
item[sepos] |= 0x80 // start
isFirstFlag = false
}
//
copy(item[headerSize:], nal[bpos:bpos+maxSize-headerSize])
out = append(out, item)
bpos += maxSize - headerSize
continue
}
// 最后一包
pktLen = epos - bpos + headerSize
item := make([]byte, pktLen)
if r.payloadType == base.AvPacketPtAvc {
item[0] = NaluTypeAvcFua | nri
item[1] = nalType | 0x40 // end
} else {
item[0] = NaluTypeHevcFua << 1
item[1] = 1
item[2] = nalType | 0x40
}
copy(item[headerSize:], nal[bpos:])
out = append(out, item)
break
}
return
}