[refactor] error信息更友好

pull/114/head
q191201771 3 years ago
parent af1a6cc32e
commit 83aa44eebe

@ -9,10 +9,13 @@
package aac
import (
"errors"
"fmt"
"github.com/q191201771/naza/pkg/nazaerrors"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/naza/pkg/nazabits"
"github.com/q191201771/naza/pkg/nazalog"
)
// AudioSpecificConfig(asc)
@ -25,8 +28,6 @@ import (
// StreamMuxConfig
//
var ErrAac = errors.New("lal.aac: fxxk")
const (
AdtsHeaderLength = 7
@ -38,6 +39,8 @@ const (
minAscLength = 2
)
// AscContext
//
// <ISO_IEC_14496-3.pdf>
// <1.6.2.1 AudioSpecificConfig>, <page 33/110>
// <1.5.1.1 Audio Object type definition>, <page 23/110>
@ -47,6 +50,7 @@ const (
// audio object type [5b] 1=AAC MAIN 2=AAC LC
// samplingFrequencyIndex [4b] 3=48000 4=44100 6=24000 5=32000 11=11025
// channelConfiguration [4b] 1=center front speaker 2=left, right front speakers
//
type AscContext struct {
AudioObjectType uint8 // [5b]
SamplingFrequencyIndex uint8 // [4b]
@ -61,14 +65,15 @@ func NewAscContext(asc []byte) (*AscContext, error) {
return &ascCtx, nil
}
// Unpack
//
// @param asc: 2字节的AAC Audio Specifc Config
// 注意如果是rtmp/flv的message/tag应去除Seq Header头部的2个字节
// 函数调用结束后,内部不持有该内存块
//
func (ascCtx *AscContext) Unpack(asc []byte) error {
if len(asc) < minAscLength {
nazalog.Warnf("aac seq header length invalid. len=%d", len(asc))
return ErrAac
return nazaerrors.Wrap(base.ErrShortBuffer)
}
br := nazabits.NewBitReader(asc)
@ -78,6 +83,8 @@ func (ascCtx *AscContext) Unpack(asc []byte) error {
return nil
}
// Pack
//
// @return asc: 内存块为独立新申请;函数调用结束后,内部不持有该内存块
//
func (ascCtx *AscContext) Pack() (asc []byte) {
@ -89,6 +96,8 @@ func (ascCtx *AscContext) Pack() (asc []byte) {
return
}
// PackAdtsHeader
//
// 获取ADTS头由于ADTS头中的字段依赖包的长度而每个包的长度可能不同所以每个包的ADTS头都需要独立生成
//
// @param frameLength: raw aac frame的大小
@ -102,11 +111,13 @@ func (ascCtx *AscContext) PackAdtsHeader(frameLength int) (out []byte) {
return
}
// PackToAdtsHeader
//
// @param out: 函数调用结束后,内部不持有该内存块
//
func (ascCtx *AscContext) PackToAdtsHeader(out []byte, frameLength int) error {
if len(out) < AdtsHeaderLength {
return ErrAac
return nazaerrors.Wrap(base.ErrShortBuffer)
}
// <ISO_IEC_14496-3.pdf>
@ -163,8 +174,7 @@ func (ascCtx *AscContext) GetSamplingFrequency() (int, error) {
case AscSamplingFrequencyIndex44100:
return 44100, nil
}
nazalog.Errorf("GetSamplingFrequency failed. ascCtx=%+v", ascCtx)
return -1, ErrAac
return -1, fmt.Errorf("%w. index=%d", base.ErrSamplingFrequencyIndex, ascCtx.SamplingFrequencyIndex)
}
type AdtsHeaderContext struct {
@ -181,11 +191,13 @@ func NewAdtsHeaderContext(adtsHeader []byte) (*AdtsHeaderContext, error) {
return &ctx, nil
}
// Unpack
//
// @param adtsHeader: 函数调用结束后,内部不持有该内存块
//
func (ctx *AdtsHeaderContext) Unpack(adtsHeader []byte) error {
if len(adtsHeader) < AdtsHeaderLength {
return ErrAac
return nazaerrors.Wrap(base.ErrShortBuffer)
}
br := nazabits.NewBitReader(adtsHeader)
@ -200,6 +212,8 @@ func (ctx *AdtsHeaderContext) Unpack(adtsHeader []byte) error {
return nil
}
// MakeAscWithAdtsHeader
//
// @param adtsHeader: 函数调用结束后,内部不持有该内存块
//
// @return asc: 内存块为独立新申请;函数调用结束后,内部不持有该内存块

@ -9,8 +9,11 @@
package aac_test
import (
"errors"
"testing"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/lal/pkg/aac"
"github.com/q191201771/naza/pkg/nazalog"
@ -58,10 +61,10 @@ func TestAscContext(t *testing.T) {
// error case
_, err = aac.NewAscContext(nil)
assert.Equal(t, aac.ErrAac, err)
assert.Equal(t, true, errors.Is(err, base.ErrShortBuffer))
// error case
_, err = aac.MakeAscWithAdtsHeader(nil)
assert.Equal(t, aac.ErrAac, err)
assert.Equal(t, true, errors.Is(err, base.ErrShortBuffer))
}
func TestMakeAudioDataSeqHeader(t *testing.T) {
@ -78,10 +81,10 @@ func TestMakeAudioDataSeqHeader(t *testing.T) {
// error case
_, err = aac.MakeAudioDataSeqHeaderWithAsc(nil)
assert.Equal(t, aac.ErrAac, err)
assert.Equal(t, true, errors.Is(err, base.ErrShortBuffer))
// error case
_, err = aac.MakeAudioDataSeqHeaderWithAdtsHeader(nil)
assert.Equal(t, aac.ErrAac, err)
assert.Equal(t, true, errors.Is(err, base.ErrShortBuffer))
}
func TestSequenceHeaderContext(t *testing.T) {

@ -8,10 +8,17 @@
package aac
import "github.com/q191201771/naza/pkg/nazabits"
import (
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/naza/pkg/nazaerrors"
"github.com/q191201771/naza/pkg/nazabits"
)
// TODO(chef) 这个文件的部分内容可以考虑放到package base中
// SequenceHeaderContext
//
// <spec-video_file_format_spec_v10.pdf>, <Audio tags, AUDIODATA>, <page 10/48>
// ----------------------------------------------------------------------------
// soundFormat [4b] 10=AAC
@ -19,6 +26,7 @@ import "github.com/q191201771/naza/pkg/nazabits"
// soundSize [1b] 0=snd8Bit, 1=snd16Bit
// soundType [1b] 0=sndMono, 1=sndStereo. AAC always 1
// aacPackageType [8b] 0=seq header, 1=AAC raw
//
type SequenceHeaderContext struct {
SoundFormat uint8 // [4b]
SoundRate uint8 // [2b]
@ -27,6 +35,8 @@ type SequenceHeaderContext struct {
AacPacketType uint8 // [8b]
}
// Unpack
//
// @param b: rtmp/flv的message/tag的payload的前2个字节
// 函数调用结束后,内部不持有该内存块
//
@ -39,13 +49,15 @@ func (shCtx *SequenceHeaderContext) Unpack(b []byte) {
shCtx.AacPacketType, _ = br.ReadBits8(8)
}
// MakeAudioDataSeqHeaderWithAsc
//
// @param asc: 函数调用结束后,内部不持有该内存块
//
// @return out: 内存块为独立新申请;函数调用结束后,内部不持有该内存块
//
func MakeAudioDataSeqHeaderWithAsc(asc []byte) (out []byte, err error) {
if len(asc) < minAscLength {
return nil, ErrAac
return nil, nazaerrors.Wrap(base.ErrShortBuffer)
}
// 注意前两个字节是SequenceHeaderContext后面跟着asc
@ -56,6 +68,8 @@ func MakeAudioDataSeqHeaderWithAsc(asc []byte) (out []byte, err error) {
return
}
// MakeAudioDataSeqHeaderWithAdtsHeader
//
// @param adtsHeader: 函数调用结束后,内部不持有该内存块
//
// @return out: 内存块为独立新申请;函数调用结束后,内部不持有该内存块

@ -9,9 +9,12 @@
package avc
import (
"errors"
"io"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/naza/pkg/nazaerrors"
"github.com/q191201771/naza/pkg/bele"
"github.com/q191201771/naza/pkg/nazabits"
)
@ -26,8 +29,6 @@ import (
// nalu with length prefix.
// e.g. rtmp, flv
var ErrAvc = errors.New("lal.avc: fxxk")
var (
NaluStartCode3 = []byte{0x0, 0x0, 0x1}
NaluStartCode4 = []byte{0x0, 0x0, 0x0, 0x1}
@ -36,8 +37,11 @@ var (
AudNalu = []byte{0x00, 0x00, 0x00, 0x01, 0x09, 0xf0}
)
// NaluTypeMapping
//
// H.264-AVC-ISO_IEC_14496-15.pdf
// Table 1 - NAL unit types in elementary streams
//
var NaluTypeMapping = map[uint8]string{
1: "SLICE",
5: "IDR",
@ -86,8 +90,11 @@ type Context struct {
Height uint32
}
// DecoderConfigurationRecord
//
// H.264-AVC-ISO_IEC_14496-15.pdf
// 5.2.4 Decoder configuration information
//
type DecoderConfigurationRecord struct {
ConfigurationVersion uint8
AvcProfileIndication uint8
@ -100,9 +107,12 @@ type DecoderConfigurationRecord struct {
PpsLength uint16
}
// Sps
//
// ISO-14496-10.pdf
// 7.3.2.1 Sequence parameter set RBSP syntax
// 7.4.2.1 Sequence parameter set RBSP semantics
//
type Sps struct {
ProfileIdc uint8
ConstraintSet0Flag uint8
@ -147,7 +157,7 @@ func ParseNaluType(v uint8) uint8 {
func ParseSliceType(nalu []byte) (uint8, error) {
if len(nalu) < 2 {
return 0, ErrAvc
return 0, nazaerrors.Wrap(base.ErrShortBuffer)
}
br := nazabits.NewBitReader(nalu[1:])
@ -164,7 +174,7 @@ func ParseSliceType(nalu []byte) (uint8, error) {
// range: [0, 9]
if sliceType > 9 {
return 0, ErrAvc
return 0, nazaerrors.Wrap(base.ErrAvc)
}
if sliceType > 4 {
@ -201,11 +211,13 @@ func ParseSliceTypeReadable(nalu []byte) (string, error) {
}
ret, ok := SliceTypeMapping[t]
if !ok {
return "unknown", ErrAvc
return "unknown", nazaerrors.Wrap(base.ErrAvc)
}
return ret, nil
}
// SpsPpsSeqHeader2Annexb
//
// AVCC Seq Header -> Annexb
//
// @param payload: rtmp message的payload部分或者flv tag的payload部分
@ -216,7 +228,7 @@ func ParseSliceTypeReadable(nalu []byte) (string, error) {
func SpsPpsSeqHeader2Annexb(payload []byte) ([]byte, error) {
sps, pps, err := ParseSpsPpsFromSeqHeaderWithoutMalloc(payload)
if err != nil {
return nil, ErrAvc
return nil, nazaerrors.Wrap(base.ErrAvc)
}
var ret []byte
ret = append(ret, NaluStartCode4...)
@ -226,6 +238,8 @@ func SpsPpsSeqHeader2Annexb(payload []byte) ([]byte, error) {
return ret, nil
}
// ParseSpsPpsFromSeqHeader
//
// 见func ParseSpsPpsFromSeqHeaderWithoutMalloc
//
// @return sps, pps: 内存块为内部独立新申请
@ -240,6 +254,8 @@ func ParseSpsPpsFromSeqHeader(payload []byte) (sps, pps []byte, err error) {
return
}
// ParseSpsPpsFromSeqHeaderWithoutMalloc
//
// 从AVCC格式的Seq Header中得到SPS和PPS内存块
//
// @param payload: rtmp message的payload部分或者flv tag的payload部分
@ -248,53 +264,51 @@ func ParseSpsPpsFromSeqHeader(payload []byte) (sps, pps []byte, err error) {
// @return sps, pps: 复用传入参数`payload`的内存块
//
func ParseSpsPpsFromSeqHeaderWithoutMalloc(payload []byte) (sps, pps []byte, err error) {
if len(payload) < 5 {
return nil, nil, ErrAvc
if len(payload) < 13 {
return nil, nil, nazaerrors.Wrap(base.ErrShortBuffer)
}
if payload[0] != 0x17 || payload[1] != 0x00 || payload[2] != 0 || payload[3] != 0 || payload[4] != 0 {
return nil, nil, ErrAvc
}
if len(payload) < 13 {
return nil, nil, ErrAvc
return nil, nil, nazaerrors.Wrap(base.ErrAvc)
}
index := 10
numOfSps := int(payload[index] & 0x1F)
index++
if numOfSps != 1 {
return nil, nil, ErrAvc
return nil, nil, nazaerrors.Wrap(base.ErrAvc)
}
spsLength := int(bele.BeUint16(payload[index:]))
index += 2
if len(payload) < 13+spsLength {
return nil, nil, ErrAvc
return nil, nil, nazaerrors.Wrap(base.ErrShortBuffer)
}
sps = payload[index : index+spsLength]
index += spsLength
if len(payload) < 16+spsLength {
return nil, nil, ErrAvc
return nil, nil, nazaerrors.Wrap(base.ErrShortBuffer)
}
numOfPps := int(payload[index] & 0x1F)
index++
if numOfPps != 1 {
return nil, nil, ErrAvc
return nil, nil, nazaerrors.Wrap(base.ErrAvc)
}
ppsLength := int(bele.BeUint16(payload[index:]))
index += 2
if len(payload) < 16+spsLength+ppsLength {
return nil, nil, ErrAvc
return nil, nil, nazaerrors.Wrap(base.ErrShortBuffer)
}
pps = payload[index : index+ppsLength]
return
}
// BuildSeqHeaderFromSpsPps
//
// @return 内存块为内部独立新申请
//
func BuildSeqHeaderFromSpsPps(sps, pps []byte) ([]byte, error) {
@ -340,6 +354,8 @@ func BuildSeqHeaderFromSpsPps(sps, pps []byte) ([]byte, error) {
return sh, nil
}
// CaptureAvcc2Annexb
//
// AVCC -> Annexb
//
// @param payload: rtmp message的payload部分或者flv tag的payload部分
@ -369,6 +385,8 @@ func CaptureAvcc2Annexb(w io.Writer, payload []byte) error {
return nil
}
// IterateNaluStartCode
//
// 遍历直到找到第一个nalu start code的位置
//
// @param start: 从`nalu`的start位置开始查找
@ -398,6 +416,8 @@ func IterateNaluStartCode(nalu []byte, start int) (pos, length int) {
return -1, -1
}
// SplitNaluAnnexb
//
// 遍历Annexb格式去掉start code获取nal包正常情况下可能为1个或多个异常情况下可能一个也没有
//
// 具体见单元测试
@ -409,6 +429,8 @@ func SplitNaluAnnexb(nals []byte) (nalList [][]byte, err error) {
return
}
// SplitNaluAvcc
//
// 遍历AVCC格式去掉4字节长度获取nal包正常情况下可能返回1个或多个异常情况下可能一个也没有
//
// 具体见单元测试
@ -423,12 +445,12 @@ func SplitNaluAvcc(nals []byte) (nalList [][]byte, err error) {
func IterateNaluAnnexb(nals []byte, handler func(nal []byte)) error {
if nals == nil {
return ErrAvc
return nazaerrors.Wrap(base.ErrShortBuffer)
}
prePos, preLength := IterateNaluStartCode(nals, 0)
if prePos == -1 {
handler(nals)
return ErrAvc
return nazaerrors.Wrap(base.ErrAvc)
}
for {
@ -439,13 +461,13 @@ func IterateNaluAnnexb(nals []byte, handler func(nal []byte)) error {
handler(nals[start:])
return nil
} else {
return ErrAvc
return nazaerrors.Wrap(base.ErrAvc)
}
}
if start < pos {
handler(nals[start:pos])
} else {
return ErrAvc
return nazaerrors.Wrap(base.ErrAvc)
}
prePos = pos
@ -455,17 +477,17 @@ func IterateNaluAnnexb(nals []byte, handler func(nal []byte)) error {
func IterateNaluAvcc(nals []byte, handler func(nal []byte)) error {
if nals == nil {
return ErrAvc
return nazaerrors.Wrap(base.ErrShortBuffer)
}
pos := 0
for {
if len(nals[pos:]) < 4 {
return ErrAvc
return nazaerrors.Wrap(base.ErrShortBuffer)
}
length := int(bele.BeUint32(nals[pos:]))
pos += 4
if pos == len(nals) {
return ErrAvc
return nazaerrors.Wrap(base.ErrShortBuffer)
}
epos := pos + length
if epos < len(nals) {
@ -478,7 +500,7 @@ func IterateNaluAvcc(nals []byte, handler func(nal []byte)) error {
return nil
} else {
handler(nals[pos:])
return ErrAvc
return nazaerrors.Wrap(base.ErrShortBuffer)
}
}
}

@ -10,9 +10,11 @@ package avc_test
import (
"bytes"
"fmt"
"errors"
"testing"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/naza/pkg/nazabits"
"github.com/q191201771/naza/pkg/nazaerrors"
@ -155,12 +157,12 @@ func TestCorner(t *testing.T) {
sps, pps, err := avc.ParseSpsPpsFromSeqHeader([]byte{0})
assert.Equal(t, nil, sps)
assert.Equal(t, nil, pps)
assert.Equal(t, avc.ErrAvc, err)
assert.Equal(t, true, errors.Is(err, base.ErrShortBuffer))
b := &bytes.Buffer{}
err = avc.CaptureAvcc2Annexb(b, []byte{0x17, 0x0, 0x1})
assert.Equal(t, nil, b.Bytes())
assert.Equal(t, avc.ErrAvc, err)
assert.Equal(t, true, errors.Is(err, base.ErrAvc))
}
func TestParsePps_Case2(t *testing.T) {
@ -240,28 +242,28 @@ func TestIterateNaluAnnexb(t *testing.T) {
nalList: [][]byte{
{0xa, 0xb},
},
err: avc.ErrAvc,
err: base.ErrAvc,
},
{
nals: []byte{0, 0, 1},
nalList: nil,
err: avc.ErrAvc,
err: base.ErrAvc,
},
{
nals: []byte{0, 0, 1, 0, 0, 1},
nalList: nil,
err: avc.ErrAvc,
err: base.ErrAvc,
},
{
nals: nil,
nalList: nil,
err: avc.ErrAvc,
err: base.ErrShortBuffer,
},
}
for _, v := range golden {
nalList, err := avc.SplitNaluAnnexb(v.nals)
assert.Equal(t, v.nalList, nalList)
assert.Equal(t, v.err, err, fmt.Sprintf("%+v", v))
assert.Equal(t, true, errors.Is(err, v.err))
}
}
@ -289,29 +291,29 @@ func TestIterateNaluAvcc(t *testing.T) {
{
nals: []byte{0, 0}, // length不全
nalList: nil,
err: avc.ErrAvc,
err: base.ErrShortBuffer,
},
{
nals: nil,
nalList: nil,
err: avc.ErrAvc,
err: base.ErrShortBuffer,
},
{
nals: []byte{0, 0, 0, 1}, // 只有length
nalList: nil,
err: avc.ErrAvc,
err: base.ErrShortBuffer,
},
{
nals: []byte{0, 0, 0, 2, 0xa}, // 包体数据不全
nalList: [][]byte{
{0xa},
},
err: avc.ErrAvc,
err: base.ErrShortBuffer,
},
}
for _, v := range golden {
nalList, err := avc.SplitNaluAvcc(v.nals)
assert.Equal(t, v.nalList, nalList)
assert.Equal(t, v.err, err)
assert.Equal(t, true, errors.Is(err, v.err))
}
}

@ -11,6 +11,8 @@ package avc
import (
"encoding/hex"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/naza/pkg/nazaerrors"
"github.com/q191201771/naza/pkg/bele"
@ -60,10 +62,10 @@ func TryParsePps(payload []byte) error {
//
func TryParseSeqHeader(payload []byte) error {
if len(payload) < 5 {
return ErrAvc
return nazaerrors.Wrap(base.ErrShortBuffer)
}
if payload[0] != 0x17 || payload[1] != 0x00 || payload[2] != 0 || payload[3] != 0 || payload[4] != 0 {
return ErrAvc
return nazaerrors.Wrap(base.ErrAvc)
}
// H.264-AVC-ISO_IEC_14496-15.pdf
@ -109,9 +111,6 @@ func parseSpsBasic(br *nazabits.BitReader, sps *Sps) error {
return nazaerrors.Wrap(err)
}
_ = t
//if t != 0x67 {
// return Context{}, ErrAvc
//}
sps.ProfileIdc, err = br.ReadBits8(8)
if err != nil {
@ -142,7 +141,7 @@ func parseSpsBasic(br *nazabits.BitReader, sps *Sps) error {
return nazaerrors.Wrap(err)
}
if sps.SpsId >= 32 {
return nazaerrors.Wrap(ErrAvc)
return nazaerrors.Wrap(base.ErrAvc)
}
return nil
}
@ -357,276 +356,3 @@ func parseSpsGamma(br *nazabits.BitReader, sps *Sps) (err error) {
return nil
}
//func parseSpsBeta(br *nazabits.BitReader, sps *Sps) error {
// var err error
//
// // 100 High profile
// if sps.ProfileIdc == 100 {
// sps.ChromaFormatIdc, err = br.ReadUeGolomb()
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// if sps.ChromaFormatIdc > 3 {
// return nazaerrors.Wrap(ErrAvc)
// }
//
// if sps.ChromaFormatIdc == 3 {
// sps.ResidualColorTransformFlag, err = br.ReadBits8(1)
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// }
//
// sps.BitDepthLuma, err = br.ReadUeGolomb()
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// sps.BitDepthLuma += 8
//
// sps.BitDepthChroma, err = br.ReadUeGolomb()
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// sps.BitDepthChroma += 8
//
// if sps.BitDepthChroma != sps.BitDepthLuma || sps.BitDepthChroma < 8 || sps.BitDepthChroma > 14 {
// return nazaerrors.Wrap(ErrAvc)
// }
//
// sps.TransFormBypass, err = br.ReadBits8(1)
// if err != nil {
// return nazaerrors.Wrap(err)
// }
//
// // seq scaling matrix present
// flag, err := br.ReadBits8(1)
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// if flag == 1 {
// nazalog.Debugf("scaling matrix present.")
// // TODO chef: 还没有正确实现只是针对特定case做了处理
// _, err = br.ReadBits32(128)
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// }
// } else {
// sps.ChromaFormatIdc = 1
// sps.BitDepthLuma = 8
// sps.BitDepthChroma = 8
// }
//
// sps.Log2MaxFrameNumMinus4, err = br.ReadUeGolomb()
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// if sps.Log2MaxFrameNumMinus4 > 12 {
// return nazaerrors.Wrap(ErrAvc)
// }
// sps.PicOrderCntType, err = br.ReadUeGolomb()
// if err != nil {
// return nazaerrors.Wrap(err)
// }
//
// if sps.PicOrderCntType == 0 {
// sps.Log2MaxPicOrderCntLsb, err = br.ReadUeGolomb()
// sps.Log2MaxPicOrderCntLsb += 4
// } else if sps.PicOrderCntType == 2 {
// // noop
// } else {
// nazalog.Debugf("not impl yet. sps.PicOrderCntType=%d", sps.PicOrderCntType)
// return nazaerrors.Wrap(ErrAvc)
// }
//
// sps.NumRefFrames, err = br.ReadUeGolomb()
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// sps.GapsInFrameNumValueAllowedFlag, err = br.ReadBits8(1)
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// sps.PicWidthInMbsMinusOne, err = br.ReadUeGolomb()
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// sps.PicHeightInMapUnitsMinusOne, err = br.ReadUeGolomb()
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// sps.FrameMbsOnlyFlag, err = br.ReadBits8(1)
// if err != nil {
// return nazaerrors.Wrap(err)
// }
//
// if sps.FrameMbsOnlyFlag == 0 {
// sps.MbAdaptiveFrameFieldFlag, err = br.ReadBits8(1)
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// }
//
// sps.Direct8X8InferenceFlag, err = br.ReadBits8(1)
// if err != nil {
// return nazaerrors.Wrap(err)
// }
//
// sps.FrameCroppingFlag, err = br.ReadBits8(1)
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// if sps.FrameCroppingFlag == 1 {
// sps.FrameCropLeftOffset, err = br.ReadUeGolomb()
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// sps.FrameCropRightOffset, err = br.ReadUeGolomb()
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// sps.FrameCropTopOffset, err = br.ReadUeGolomb()
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// sps.FrameCropBottomOffset, err = br.ReadUeGolomb()
// if err != nil {
// return nazaerrors.Wrap(err)
// }
// }
//
// // TODO parse sps vui parameters
// return nil
//}
//var defaultScaling4 = [][]uint8{
// {
// 6, 13, 20, 28, 13, 20, 28, 32,
// 20, 28, 32, 37, 28, 32, 37, 42,
// },
// {
// 10, 14, 20, 24, 14, 20, 24, 27,
// 20, 24, 27, 30, 24, 27, 30, 34,
// },
//}
//
//var defaultScaling8 = [][]uint8{
// {
// 6, 10, 13, 16, 18, 23, 25, 27,
// 10, 11, 16, 18, 23, 25, 27, 29,
// 13, 16, 18, 23, 25, 27, 29, 31,
// 16, 18, 23, 25, 27, 29, 31, 33,
// 18, 23, 25, 27, 29, 31, 33, 36,
// 23, 25, 27, 29, 31, 33, 36, 38,
// 25, 27, 29, 31, 33, 36, 38, 40,
// 27, 29, 31, 33, 36, 38, 40, 42,
// },
// {
// 9, 13, 15, 17, 19, 21, 22, 24,
// 13, 13, 17, 19, 21, 22, 24, 25,
// 15, 17, 19, 21, 22, 24, 25, 27,
// 17, 19, 21, 22, 24, 25, 27, 28,
// 19, 21, 22, 24, 25, 27, 28, 30,
// 21, 22, 24, 25, 27, 28, 30, 32,
// 22, 24, 25, 27, 28, 30, 32, 33,
// 24, 25, 27, 28, 30, 32, 33, 35,
// },
//}
//
//var ffZigzagDirect = []uint8{
// 0, 1, 8, 16, 9, 2, 3, 10,
// 17, 24, 32, 25, 18, 11, 4, 5,
// 12, 19, 26, 33, 40, 48, 41, 34,
// 27, 20, 13, 6, 7, 14, 21, 28,
// 35, 42, 49, 56, 57, 50, 43, 36,
// 29, 22, 15, 23, 30, 37, 44, 51,
// 58, 59, 52, 45, 38, 31, 39, 46,
// 53, 60, 61, 54, 47, 55, 62, 63,
//}
//
//var ffZigzagScan = []uint8{
// 0 + 0*4, 1 + 0*4, 0 + 1*4, 0 + 2*4,
// 1 + 1*4, 2 + 0*4, 3 + 0*4, 2 + 1*4,
// 1 + 2*4, 0 + 3*4, 1 + 3*4, 2 + 2*4,
// 3 + 1*4, 3 + 2*4, 2 + 3*4, 3 + 3*4,
//}
//
//func decodeScalingMatrices(reader *nazabits.BitReader) error {
// // 6 * 16
// var spsScalingMatrix4 = [][]uint8{
// {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// }
// // 6 * 64
// var spsScalingMatrix8 = [][]uint8{
// {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// }
//
// fallback := [][]uint8{defaultScaling4[0], defaultScaling4[1], defaultScaling8[0], defaultScaling8[1]}
// decodeScalingList(reader, spsScalingMatrix4[0], 16, defaultScaling4[0], fallback[0])
// decodeScalingList(reader, spsScalingMatrix4[1], 16, defaultScaling4[0], spsScalingMatrix4[0])
// decodeScalingList(reader, spsScalingMatrix4[2], 16, defaultScaling4[0], spsScalingMatrix4[1])
// decodeScalingList(reader, spsScalingMatrix4[3], 16, defaultScaling4[1], fallback[1])
// decodeScalingList(reader, spsScalingMatrix4[4], 16, defaultScaling4[1], spsScalingMatrix4[3])
// decodeScalingList(reader, spsScalingMatrix4[4], 16, defaultScaling4[1], spsScalingMatrix4[3])
//
// decodeScalingList(reader, spsScalingMatrix8[0], 64, defaultScaling8[0], fallback[2])
// decodeScalingList(reader, spsScalingMatrix8[3], 64, defaultScaling8[1], fallback[3])
//
// return nil
//}
//
//func decodeScalingList(reader *nazabits.BitReader, factors []uint8, size int, jvtList []uint8, fallbackList []uint8) error {
// var (
// i = 0
// last = 8
// next = 8
// scan []uint8
// )
// if size == 16 {
// scan = ffZigzagScan
// } else {
// scan = ffZigzagDirect
// }
// flag, err := reader.ReadBit()
// if err != nil {
// return err
// }
// return nil
// if flag == 0 {
// for n := 0; n < size; n++ {
// factors[n] = fallbackList[n]
// }
// } else {
// for i = 0; i < size; i++ {
// if next != 0 {
// v, err := reader.ReadUeGolomb()
// if err != nil {
// return err
// }
// next = (last + int(v)) & 0xff
// }
// if i == 0 && next == 0 {
// for n := 0; n < size; n++ {
// factors[n] = jvtList[n]
// }
// break
// }
// if next != 0 {
// factors[scan[i]] = uint8(next)
// last = next
// } else {
// factors[scan[i]] = uint8(last)
// }
// }
// }
// return nil
//}

@ -0,0 +1,69 @@
// 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 base
import (
"errors"
"fmt"
)
// ----- 通用的 ---------------------------------------------------------------------------------------------------------
var (
ErrShortBuffer = errors.New("lal: buffer too short")
ErrFileNotExist = errors.New("lal: file not exist")
)
// ----- pkg/aac -------------------------------------------------------------------------------------------------------
var ErrSamplingFrequencyIndex = errors.New("lal.aac: invalid sampling frequency index")
// ----- pkg/aac -------------------------------------------------------------------------------------------------------
var ErrAvc = errors.New("lal.avc: fxxk")
// ----- pkg/base ------------------------------------------------------------------------------------------------------
var (
ErrAddrEmpty = errors.New("lal.base: http server addr empty")
ErrMultiRegisterForPattern = errors.New("lal.base: http server multiple registrations for pattern")
ErrSessionNotStarted = errors.New("lal.base: session has not been started yet")
ErrInvalidUrl = errors.New("lal.base: invalid url")
)
// ----- pkg/hevc ------------------------------------------------------------------------------------------------------
var ErrHevc = errors.New("lal.hevc: fxxk")
// ----- pkg/hls -------------------------------------------------------------------------------------------------------
var ErrHls = errors.New("lal.hls: fxxk")
// ----- pkg/rtmp ------------------------------------------------------------------------------------------------------
var (
ErrAmfInvalidType = errors.New("lal.rtmp: invalid amf0 type")
ErrAmfTooShort = errors.New("lal.rtmp: too short to unmarshal amf0 data")
ErrAmfNotExist = errors.New("lal.rtmp: not exist")
ErrRtmpShortBuffer = errors.New("lal.rtmp: buffer too short")
ErrRtmpUnexpectedMsg = errors.New("lal.rtmp: unexpected msg")
)
// TODO(chef): refactor 整理其他pkg的error
func NewErrAmfInvalidType(b byte) error {
return fmt.Errorf("%w. b=%d", ErrAmfInvalidType, b)
}
func NewErrRtmpShortBuffer(need, actual int, msg string) error {
return fmt.Errorf("%w. need=%d, actual=%d, msg=%s", ErrRtmpShortBuffer, need, actual, msg)
}

@ -10,7 +10,6 @@ package base
import (
"crypto/tls"
"errors"
"net"
"net/http"
"reflect"
@ -22,11 +21,6 @@ import (
// - 考虑移入naza中
// - 考虑增加一个pattern全部未命中的mux回调
var (
ErrAddrEmpty = errors.New("lal.base: http server addr empty")
ErrMultiRegistForPattern = errors.New("lal.base: http server multiple registrations for pattern")
)
const (
NetworkTcp = "tcp"
)
@ -113,7 +107,7 @@ func (s *HttpServerManager) AddListen(addrCtx LocalAddrCtx, pattern string, hand
if reflect.ValueOf(prevHandler).Pointer() == reflect.ValueOf(handler).Pointer() {
return nil
} else {
return ErrMultiRegistForPattern
return ErrMultiRegisterForPattern
}
}
ctx.pattern2Handler[pattern] = handler

@ -9,15 +9,10 @@
package base
import (
"errors"
"io"
"strings"
)
var (
ErrSessionNotStarted = errors.New("lal.base: session has not been started yet")
)
// IsUseClosedConnectionError 当connection处于这些情况时就不需要再Close了
// TODO(chef): 临时放这
// TODO(chef): 目前暂时没有使用因为connection支持多次调用Close
@ -95,24 +90,36 @@ type IServerSessionLifecycle interface {
Dispose() error
}
// ISessionStat
//
// 调用约束对于Client类型的Session调用Start函数并返回成功后才能调用否则行为未定义
//
type ISessionStat interface {
// UpdateStat
//
// 周期性调用该函数用于计算bitrate
//
// @param intervalSec 距离上次调用的时间间隔,单位毫秒
//
UpdateStat(intervalSec uint32)
// GetStat
//
// 获取session状态
//
// @return 注意,结构体中的`Bitrate`的值由最近一次`func UpdateStat`调用计算决定,其他值为当前最新值
//
GetStat() StatSession
// IsAlive
//
// 周期性调用该函数,判断是否有读取、写入数据
// 注意,判断的依据是,距离上次调用该函数的时间间隔内,是否有读取、写入数据
// 注意,不活跃,并一定是链路或网络有问题,也可能是业务层没有写入数据
//
// @return readAlive 读取是否获取
// @return writeAlive 写入是否活跃
//
IsAlive() (readAlive, writeAlive bool)
}
@ -128,7 +135,10 @@ type ISessionUrlContext interface {
}
type IObject interface {
// UniqueKey
//
// 对象的全局唯一标识
//
UniqueKey() string
}

@ -9,22 +9,17 @@
package base
import (
"errors"
"fmt"
"net"
"net/url"
"strconv"
"strings"
"github.com/q191201771/naza/pkg/nazaerrors"
)
// 见单元测试
// TODO chef: 考虑部分内容移入naza中
var ErrUrl = errors.New("lal.url: fxxk")
const (
DefaultRtmpPort = 1935
DefaultHttpPort = 80
@ -74,7 +69,7 @@ func ParseUrl(rawUrl string, defaultPort int) (ctx UrlContext, err error) {
return ctx, err
}
if stdUrl.Scheme == "" {
return ctx, nazaerrors.Wrap(ErrUrl)
return ctx, fmt.Errorf("%w. url=%s", ErrInvalidUrl, rawUrl)
}
// 如果不存在,则设置默认的
if defaultPort == -1 {
@ -138,7 +133,7 @@ func ParseRtmpUrl(rawUrl string) (ctx UrlContext, err error) {
return
}
if ctx.Scheme != "rtmp" || ctx.Host == "" || ctx.Path == "" {
return ctx, nazaerrors.Wrap(ErrUrl)
return ctx, fmt.Errorf("%w. url=%s", ErrInvalidUrl, rawUrl)
}
// 注意使用ffmpeg推流时会把`rtmp://127.0.0.1/test110`中的test110作为appName(streamName则为空)
@ -162,7 +157,7 @@ func ParseRtspUrl(rawUrl string) (ctx UrlContext, err error) {
return
}
if ctx.Scheme != "rtsp" || ctx.Host == "" || ctx.Path == "" {
return ctx, nazaerrors.Wrap(ErrUrl)
return ctx, fmt.Errorf("%w. url=%s", ErrInvalidUrl, rawUrl)
}
return
@ -205,7 +200,7 @@ func ParseHttpUrl(rawUrl string, suffix string) (ctx UrlContext, err error) {
return
}
if (ctx.Scheme != "http" && ctx.Scheme != "https") || ctx.Host == "" || ctx.Path == "" || !strings.HasSuffix(ctx.LastItemOfPath, suffix) {
return ctx, nazaerrors.Wrap(ErrUrl, fmt.Sprintf("%+v", ctx))
return ctx, fmt.Errorf("%w. url=%s", ErrInvalidUrl, rawUrl)
}
return

@ -10,7 +10,10 @@ package hevc
import (
"bytes"
"errors"
"github.com/q191201771/naza/pkg/nazaerrors"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/naza/pkg/nazabits"
@ -29,12 +32,10 @@ import (
// |F| Type | LayerId | TID |
// +-------------+-----------------+
var ErrHevc = errors.New("lal.hevc: fxxk")
var (
NaluStartCode4 = []byte{0x0, 0x0, 0x0, 0x1}
// aud nalu
// AudNalu aud nalu
AudNalu = []byte{0x00, 0x00, 0x00, 0x01, 0x46, 0x01, 0x10}
)
@ -58,8 +59,11 @@ const (
NaluTypeSliceTrailN uint8 = 0 // 0x0
NaluTypeSliceTrailR uint8 = 1 // 0x01
// NaluTypeSliceIdr ...
//
// 19, 20, 21都是关键帧
// TODO(chef): 161718也是关键帧吗
//
NaluTypeSliceIdr uint8 = 19 // 0x13
NaluTypeSliceIdrNlp uint8 = 20 // 0x14
NaluTypeSliceCranut uint8 = 21 // 0x15
@ -103,7 +107,10 @@ func ParseNaluTypeReadable(v uint8) string {
return b
}
// ParseNaluType
//
// @param v 第一个字节
//
func ParseNaluType(v uint8) uint8 {
// 6 bit in middle
// 0*** ***0
@ -111,6 +118,8 @@ func ParseNaluType(v uint8) uint8 {
return (v & 0x7E) >> 1
}
// VpsSpsPpsSeqHeader2Annexb
//
// HVCC Seq Header -> Annexb
//
// @return 返回的内存块为内部独立新申请
@ -118,7 +127,7 @@ func ParseNaluType(v uint8) uint8 {
func VpsSpsPpsSeqHeader2Annexb(payload []byte) ([]byte, error) {
vps, sps, pps, err := ParseVpsSpsPpsFromSeqHeaderWithoutMalloc(payload)
if err != nil {
return nil, ErrHevc
return nil, err
}
var ret []byte
ret = append(ret, NaluStartCode4...)
@ -130,6 +139,8 @@ func VpsSpsPpsSeqHeader2Annexb(payload []byte) ([]byte, error) {
return ret, nil
}
// ParseVpsSpsPpsFromSeqHeader
//
// 见func ParseVpsSpsPpsFromSeqHeaderWithoutMalloc
//
// @return vps, sps, pps: 内存块为内部独立新申请
@ -145,6 +156,8 @@ func ParseVpsSpsPpsFromSeqHeader(payload []byte) (vps, sps, pps []byte, err erro
return
}
// ParseVpsSpsPpsFromSeqHeaderWithoutMalloc
//
// 从HVCC格式的Seq Header中得到VPSSPSPPS内存块
//
// @param <payload> rtmp message的payload部分或者flv tag的payload部分
@ -154,73 +167,75 @@ func ParseVpsSpsPpsFromSeqHeader(payload []byte) (vps, sps, pps []byte, err erro
//
func ParseVpsSpsPpsFromSeqHeaderWithoutMalloc(payload []byte) (vps, sps, pps []byte, err error) {
if len(payload) < 5 {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrShortBuffer)
}
if payload[0] != 0x1c || payload[1] != 0x00 || payload[2] != 0 || payload[3] != 0 || payload[4] != 0 {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
//nazalog.Debugf("%s", hex.Dump(payload))
if len(payload) < 33 {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
index := 27
if numOfArrays := payload[index]; numOfArrays != 3 && numOfArrays != 4 {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
index++
if payload[index] != NaluTypeVps&0x3f {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
if numNalus := int(bele.BeUint16(payload[index+1:])); numNalus != 1 {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
vpsLen := int(bele.BeUint16(payload[index+3:]))
if len(payload) < 33+vpsLen {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
vps = payload[index+5 : index+5+vpsLen]
index += 5 + vpsLen
if len(payload) < 38+vpsLen {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
if payload[index] != NaluTypeSps&0x3f {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
if numNalus := int(bele.BeUint16(payload[index+1:])); numNalus != 1 {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
spsLen := int(bele.BeUint16(payload[index+3:]))
if len(payload) < 38+vpsLen+spsLen {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
sps = payload[index+5 : index+5+spsLen]
index += 5 + spsLen
if len(payload) < 43+vpsLen+spsLen {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
if payload[index] != NaluTypePps&0x3f {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
if numNalus := int(bele.BeUint16(payload[index+1:])); numNalus != 1 {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
ppsLen := int(bele.BeUint16(payload[index+3:]))
if len(payload) < 43+vpsLen+spsLen+ppsLen {
return nil, nil, nil, ErrHevc
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
pps = payload[index+5 : index+5+ppsLen]
return
}
// BuildSeqHeaderFromVpsSpsPps
//
// @return 内存块为内部独立新申请
//
func BuildSeqHeaderFromVpsSpsPps(vps, sps, pps []byte) ([]byte, error) {
@ -309,7 +324,7 @@ func BuildSeqHeaderFromVpsSpsPps(vps, sps, pps []byte) ([]byte, error) {
func ParseVps(vps []byte, ctx *Context) error {
if len(vps) < 2 {
return ErrHevc
return nazaerrors.Wrap(base.ErrHevc)
}
rbsp := nal2rbsp(vps[2:])
@ -320,12 +335,12 @@ func ParseVps(vps []byte, ctx *Context) error {
// vps_reserved_three_2bits u(2)
// vps_max_layers_minus1 u(6)
if _, err := br.ReadBits16(12); err != nil {
return ErrHevc
return nazaerrors.Wrap(base.ErrHevc)
}
vpsMaxSubLayersMinus1, err := br.ReadBits8(3)
if err != nil {
return ErrHevc
return nazaerrors.Wrap(base.ErrHevc)
}
if vpsMaxSubLayersMinus1+1 > ctx.numTemporalLayers {
ctx.numTemporalLayers = vpsMaxSubLayersMinus1 + 1
@ -335,7 +350,7 @@ func ParseVps(vps []byte, ctx *Context) error {
// vps_temporal_id_nesting_flag u(1)
// vps_reserved_0xffff_16bits u(16)
if _, err := br.ReadBits32(17); err != nil {
return ErrHevc
return nazaerrors.Wrap(base.ErrHevc)
}
return parsePtl(&br, ctx, vpsMaxSubLayersMinus1)
@ -345,7 +360,7 @@ func ParseSps(sps []byte, ctx *Context) error {
var err error
if len(sps) < 2 {
return ErrHevc
return nazaerrors.Wrap(base.ErrHevc)
}
rbsp := nal2rbsp(sps[2:])

@ -9,7 +9,7 @@
package hls
import (
"errors"
"github.com/q191201771/lal/pkg/base"
)
// TODO chef:
@ -31,8 +31,6 @@ import (
// 进来的数据称为Frame帧188字节的封装称为TSPacket包TS文件称为Fragment
var ErrHls = errors.New("lal.hls: fxxk")
const (
// TODO chef 这些在配置项中提供
negMaxfraglen uint64 = 1000 * 90 // 当前包时间戳回滚了比当前fragment的首个时间戳还小强制切割新的fragment单位毫秒*90
@ -42,7 +40,7 @@ const (
func SplitFragment2TsPackets(content []byte) (ret [][]byte, err error) {
if len(content)%188 != 0 {
err = ErrHls
err = base.ErrHls
return
}
for {

@ -12,6 +12,9 @@ import (
"bytes"
"fmt"
"strconv"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/naza/pkg/nazaerrors"
)
// @param content 需写入文件的内容
@ -35,11 +38,11 @@ func writeM3u8File(content []byte, filename string, filenameBak string) error {
func updateTargetDurationInM3u8(content []byte, currDuration int) ([]byte, error) {
l := bytes.Index(content, []byte("#EXT-X-TARGETDURATION:"))
if l == -1 {
return content, ErrHls
return content, nazaerrors.Wrap(base.ErrHls)
}
r := bytes.Index(content[l:], []byte{'\n'})
if r == -1 {
return content, ErrHls
return content, nazaerrors.Wrap(base.ErrHls)
}
oldDurationStr := bytes.TrimPrefix(content[l:l+r], []byte("#EXT-X-TARGETDURATION:"))
oldDuration, err := strconv.Atoi(string(oldDurationStr))

@ -13,6 +13,8 @@ import (
"fmt"
"time"
"github.com/q191201771/naza/pkg/nazaerrors"
"github.com/q191201771/lal/pkg/mpegts"
"github.com/q191201771/lal/pkg/base"
@ -279,7 +281,7 @@ func (m *Muxer) updateFragment(ts uint64, boundary bool) error {
//
func (m *Muxer) openFragment(ts uint64, discont bool) error {
if m.opened {
return ErrHls
return nazaerrors.Wrap(base.ErrHls)
}
id := m.getFragmentId()

@ -300,7 +300,7 @@ func (s *Streamer) cacheAacSeqHeader(msg base.RtmpMsg) error {
func (s *Streamer) appendSpsPps(out []byte) ([]byte, error) {
if s.spspps == nil {
return out, ErrHls
return out, base.ErrHls
}
out = append(out, s.spspps...)

@ -8,7 +8,11 @@
package httpflv
import "os"
import (
"os"
"github.com/q191201771/lal/pkg/base"
)
// TODO chef: 结构体重命名为FileWriter文件名重命名为file_writer.go。所有写流文件的flv,hls,ts统一重构
@ -23,7 +27,7 @@ func (ffw *FlvFileWriter) Open(filename string) (err error) {
func (ffw *FlvFileWriter) WriteRaw(b []byte) (err error) {
if ffw.fp == nil {
return ErrHttpflv
return base.ErrFileNotExist
}
_, err = ffw.fp.Write(b)
return
@ -31,7 +35,7 @@ func (ffw *FlvFileWriter) WriteRaw(b []byte) (err error) {
func (ffw *FlvFileWriter) WriteFlvHeader() (err error) {
if ffw.fp == nil {
return ErrHttpflv
return base.ErrFileNotExist
}
_, err = ffw.fp.Write(FlvHeader)
return
@ -39,7 +43,7 @@ func (ffw *FlvFileWriter) WriteFlvHeader() (err error) {
func (ffw *FlvFileWriter) WriteTag(tag Tag) (err error) {
if ffw.fp == nil {
return ErrHttpflv
return base.ErrFileNotExist
}
_, err = ffw.fp.Write(tag.Raw)
return
@ -47,7 +51,7 @@ func (ffw *FlvFileWriter) WriteTag(tag Tag) (err error) {
func (ffw *FlvFileWriter) Dispose() error {
if ffw.fp == nil {
return ErrHttpflv
return base.ErrFileNotExist
}
return ffw.fp.Close()
}

@ -8,12 +8,6 @@
package httpflv
import (
"errors"
)
var ErrHttpflv = errors.New("lal.httpflv: fxxk")
const (
TagHeaderSize int = 11
PrevTagSizeFieldSize int = 4

@ -7,7 +7,3 @@
// Author: Chef (191201771@qq.com)
package httpts
import "errors"
var ErrHttpTs = errors.New("lal.httpts: fxxk")

@ -8,7 +8,11 @@
package mpegts
import "os"
import (
"os"
"github.com/q191201771/lal/pkg/base"
)
type FileWriter struct {
fp *os.File
@ -21,7 +25,7 @@ func (fw *FileWriter) Create(filename string) (err error) {
func (fw *FileWriter) Write(b []byte) (err error) {
if fw.fp == nil {
return ErrMpegts
return base.ErrFileNotExist
}
_, err = fw.fp.Write(b)
return
@ -29,7 +33,7 @@ func (fw *FileWriter) Write(b []byte) (err error) {
func (fw *FileWriter) Dispose() error {
if fw.fp == nil {
return ErrMpegts
return base.ErrFileNotExist
}
return fw.fp.Close()
}

@ -8,12 +8,8 @@
package mpegts
import "errors"
// MPEG: Moving Picture Experts Group
var ErrMpegts = errors.New("lal.mpegts: fxxk")
// 每个TS文件都以固定的PATPMT开始
var FixedFragmentHeader = []byte{
/* TS */

@ -14,19 +14,15 @@ package rtmp
import (
"bytes"
"errors"
"io"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/naza/pkg/nazaerrors"
"github.com/q191201771/naza/pkg/bele"
"github.com/q191201771/naza/pkg/nazalog"
)
var (
ErrAmfInvalidType = errors.New("lal.rtmp: invalid amf0 type")
ErrAmfTooShort = errors.New("lal.rtmp: too short to unmarshal amf0 data")
ErrAmfNotExist = errors.New("lal.rtmp: not exist")
)
const (
Amf0TypeMarkerNumber = uint8(0x00)
Amf0TypeMarkerBoolean = uint8(0x01)
@ -75,7 +71,7 @@ func (o ObjectPairArray) FindString(key string) (string, error) {
}
}
}
return "", ErrAmfNotExist
return "", base.ErrAmfNotExist
}
func (o ObjectPairArray) FindNumber(key string) (int, error) {
@ -86,7 +82,7 @@ func (o ObjectPairArray) FindNumber(key string) (int, error) {
}
}
}
return -1, ErrAmfNotExist
return -1, base.ErrAmfNotExist
}
type amf0 struct{}
@ -184,29 +180,29 @@ func (amf0) WriteObject(writer io.Writer, opa ObjectPairArray) error {
func (amf0) ReadStringWithoutType(b []byte) (string, int, error) {
if len(b) < 2 {
return "", 0, ErrAmfTooShort
return "", 0, nazaerrors.Wrap(base.ErrAmfTooShort)
}
l := int(bele.BeUint16(b))
if l > len(b)-2 {
return "", 0, ErrAmfTooShort
return "", 0, nazaerrors.Wrap(base.ErrAmfTooShort)
}
return string(b[2 : 2+l]), 2 + l, nil
}
func (amf0) ReadLongStringWithoutType(b []byte) (string, int, error) {
if len(b) < 4 {
return "", 0, ErrAmfTooShort
return "", 0, nazaerrors.Wrap(base.ErrAmfTooShort)
}
l := int(bele.BeUint32(b))
if l > len(b)-4 {
return "", 0, ErrAmfTooShort
return "", 0, nazaerrors.Wrap(base.ErrAmfTooShort)
}
return string(b[4 : 4+l]), 4 + l, nil
}
func (amf0) ReadString(b []byte) (val string, l int, err error) {
if len(b) < 1 {
return "", 0, ErrAmfTooShort
return "", 0, nazaerrors.Wrap(base.ErrAmfTooShort)
}
switch b[0] {
case Amf0TypeMarkerString:
@ -216,47 +212,47 @@ func (amf0) ReadString(b []byte) (val string, l int, err error) {
val, l, err = Amf0.ReadLongStringWithoutType(b[1:])
l++
default:
err = ErrAmfInvalidType
err = base.NewErrAmfInvalidType(b[0])
}
return
}
func (amf0) ReadNumber(b []byte) (float64, int, error) {
if len(b) < 9 {
return 0, 0, ErrAmfTooShort
return 0, 0, nazaerrors.Wrap(base.ErrAmfTooShort)
}
if b[0] != Amf0TypeMarkerNumber {
return 0, 0, ErrAmfInvalidType
return 0, 0, base.NewErrAmfInvalidType(b[0])
}
return bele.BeFloat64(b[1:]), 9, nil
}
func (amf0) ReadBoolean(b []byte) (bool, int, error) {
if len(b) < 2 {
return false, 0, ErrAmfTooShort
return false, 0, nazaerrors.Wrap(base.ErrAmfTooShort)
}
if b[0] != Amf0TypeMarkerBoolean {
return false, 0, ErrAmfInvalidType
return false, 0, base.NewErrAmfInvalidType(b[0])
}
return b[1] != 0x0, 2, nil
}
func (amf0) ReadNull(b []byte) (int, error) {
if len(b) < 1 {
return 0, ErrAmfTooShort
return 0, nazaerrors.Wrap(base.ErrAmfTooShort)
}
if b[0] != Amf0TypeMarkerNull {
return 0, ErrAmfInvalidType
return 0, base.NewErrAmfInvalidType(b[0])
}
return 1, nil
}
func (amf0) ReadObject(b []byte) (ObjectPairArray, int, error) {
if len(b) < 1 {
return nil, 0, ErrAmfTooShort
return nil, 0, nazaerrors.Wrap(base.ErrAmfTooShort)
}
if b[0] != Amf0TypeMarkerObject {
return nil, 0, ErrAmfInvalidType
return nil, 0, base.NewErrAmfInvalidType(b[0])
}
index := 1
@ -272,7 +268,7 @@ func (amf0) ReadObject(b []byte) (ObjectPairArray, int, error) {
}
index += l
if len(b)-index < 1 {
return nil, 0, ErrAmfTooShort
return nil, 0, nazaerrors.Wrap(base.ErrAmfTooShort)
}
vt := b[index]
switch vt {
@ -322,10 +318,10 @@ func (amf0) ReadObject(b []byte) (ObjectPairArray, int, error) {
func (amf0) ReadArray(b []byte) (ObjectPairArray, int, error) {
if len(b) < 5 {
return nil, 0, ErrAmfTooShort
return nil, 0, nazaerrors.Wrap(base.ErrAmfTooShort)
}
if b[0] != Amf0TypeMarkerEcmaArray {
return nil, 0, ErrAmfInvalidType
return nil, 0, base.NewErrAmfInvalidType(b[0])
}
count := int(bele.BeUint32(b[1:]))
@ -338,7 +334,7 @@ func (amf0) ReadArray(b []byte) (ObjectPairArray, int, error) {
}
index += l
if len(b)-index < 1 {
return nil, 0, ErrAmfTooShort
return nil, 0, nazaerrors.Wrap(base.ErrAmfTooShort)
}
vt := b[index]
switch vt {
@ -385,7 +381,7 @@ func (amf0) ReadArray(b []byte) (ObjectPairArray, int, error) {
func (amf0) ReadObjectOrArray(b []byte) (ObjectPairArray, int, error) {
if len(b) < 1 {
return nil, 0, ErrAmfTooShort
return nil, 0, nazaerrors.Wrap(base.ErrAmfTooShort)
}
switch b[0] {
case Amf0TypeMarkerObject:
@ -393,5 +389,5 @@ func (amf0) ReadObjectOrArray(b []byte) (ObjectPairArray, int, error) {
case Amf0TypeMarkerEcmaArray:
return Amf0.ReadArray(b)
}
return nil, 0, ErrAmfInvalidType
return nil, 0, base.NewErrAmfInvalidType(b[0])
}

@ -11,9 +11,12 @@ package rtmp_test
import (
"bytes"
"encoding/hex"
"errors"
"strings"
"testing"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/naza/pkg/nazalog"
. "github.com/q191201771/lal/pkg/rtmp"
@ -226,77 +229,77 @@ func TestAmf0Corner(t *testing.T) {
str, l, err = Amf0.ReadStringWithoutType(b)
assert.Equal(t, str, "")
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfTooShort, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = []byte{1, 1}
str, l, err = Amf0.ReadStringWithoutType(b)
assert.Equal(t, str, "")
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfTooShort, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = nil
str, l, err = Amf0.ReadLongStringWithoutType(b)
assert.Equal(t, str, "")
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfTooShort, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = []byte{1, 1, 1, 1}
str, l, err = Amf0.ReadLongStringWithoutType(b)
assert.Equal(t, str, "")
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfTooShort, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = nil
str, l, err = Amf0.ReadString(b)
assert.Equal(t, str, "")
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfTooShort, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = []byte{1}
str, l, err = Amf0.ReadString(b)
assert.Equal(t, str, "")
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfInvalidType, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfInvalidType))
b = nil
num, l, err = Amf0.ReadNumber(b)
assert.Equal(t, int(num), 0)
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfTooShort, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
str = strings.Repeat("1", 16)
b = []byte(str)
num, l, err = Amf0.ReadNumber(b)
assert.Equal(t, int(num), 0)
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfInvalidType, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfInvalidType))
b = nil
flag, l, err = Amf0.ReadBoolean(b)
assert.Equal(t, flag, false)
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfTooShort, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = []byte{0, 0}
flag, l, err = Amf0.ReadBoolean(b)
assert.Equal(t, flag, false)
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfInvalidType, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfInvalidType))
b = nil
l, err = Amf0.ReadNull(b)
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfTooShort, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = []byte{0}
l, err = Amf0.ReadNull(b)
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfInvalidType, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfInvalidType))
b = nil
objs, l, err = Amf0.ReadObject(b)
assert.Equal(t, nil, objs)
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfTooShort, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfTooShort))
b = []byte{0}
objs, l, err = Amf0.ReadObject(b)
assert.Equal(t, nil, objs)
assert.Equal(t, 0, l)
assert.Equal(t, ErrAmfInvalidType, err)
assert.Equal(t, true, errors.Is(err, base.ErrAmfInvalidType))
defer func() {
recover()

@ -18,8 +18,6 @@ import (
"github.com/q191201771/naza/pkg/nazabytes"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/naza/pkg/nazalog"
"github.com/q191201771/naza/pkg/bele"
)
@ -196,7 +194,7 @@ func (c *ChunkComposer) RunLoop(reader io.Reader, cb OnCompleteMessage) error {
for stream.msg.Len() != 0 {
// 读取sub message的头
if stream.msg.Len() < 11 {
return ErrRtmp
return base.NewErrRtmpShortBuffer(11, int(stream.msg.Len()), "parse rtmp aggregate sub message len")
}
aggregateStream.header.MsgTypeId = stream.msg.buff.Bytes()[0]
stream.msg.Skip(1)
@ -218,7 +216,7 @@ func (c *ChunkComposer) RunLoop(reader io.Reader, cb OnCompleteMessage) error {
// message包体
if stream.msg.Len() < aggregateStream.header.MsgLen {
return ErrRtmp
return base.NewErrRtmpShortBuffer(int(aggregateStream.header.MsgLen), int(stream.msg.Len()), "parse rtmp aggregate sub message body")
}
aggregateStream.msg.buff = nazabytes.NewBufferRefBytes(stream.msg.buff.Peek(int(aggregateStream.header.MsgLen)))
stream.msg.Skip(aggregateStream.header.MsgLen)
@ -230,7 +228,7 @@ func (c *ChunkComposer) RunLoop(reader io.Reader, cb OnCompleteMessage) error {
// 跳过prev size字段
if stream.msg.Len() < 4 {
return ErrRtmp
return base.NewErrRtmpShortBuffer(4, int(stream.msg.Len()), "parse rtmp aggregate prev message size")
}
stream.msg.Skip(4)
}
@ -242,9 +240,10 @@ func (c *ChunkComposer) RunLoop(reader io.Reader, cb OnCompleteMessage) error {
stream.msg.Reset()
}
}
// TODO(chef): 这里应该永远执行不到,可以删除掉
if stream.msg.Len() > stream.header.MsgLen {
nazalog.Warnf("stream msg len should not greater than len field in header. stream.msg.len=%d, header=%+v", stream.msg.Len(), stream.header)
return ErrRtmp
return base.NewErrRtmpShortBuffer(int(aggregateStream.header.MsgLen), int(stream.msg.Len()), "len of msg bigger tthan msg len of header")
}
}
}

@ -11,7 +11,6 @@ package rtmp
import (
"context"
"encoding/hex"
"errors"
"fmt"
"net"
"sync"
@ -24,8 +23,6 @@ import (
"github.com/q191201771/naza/pkg/nazalog"
)
var ErrClientSessionTimeout = errors.New("lal.rtmp: client session timeout")
// rtmp 客户端类型连接的底层实现
// package rtmp 的使用者应该优先使用基于 ClientSession 实现的 PushSession 和 PullSession
type ClientSession struct {
@ -508,7 +505,7 @@ func (s *ClientSession) doResultMessage(stream *Stream, tid int) error {
}
func (s *ClientSession) doProtocolControlMessage(stream *Stream) error {
if stream.msg.Len() < 4 {
return ErrRtmp
return base.NewErrRtmpShortBuffer(4, int(stream.msg.Len()), "ClientSession::doProtocolControlMessage")
}
val := int(bele.BeUint32(stream.msg.buff.Bytes()))

@ -8,14 +8,6 @@
package rtmp
import (
"errors"
)
var (
ErrRtmp = errors.New("lal.rtmp: fxxk")
)
const (
CsidAmf = 5
CsidAudio = 6

@ -14,6 +14,8 @@ import (
"strings"
"time"
"github.com/q191201771/naza/pkg/nazaerrors"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/naza/pkg/bele"
@ -221,8 +223,7 @@ func (s *ServerSession) doMsg(stream *Stream) error {
fallthrough
case base.RtmpTypeIdVideo:
if s.t != ServerSessionTypePub {
nazalog.Errorf("[%s] read audio/video message but server session not pub type.", s.uniqueKey)
return ErrRtmp
return nazaerrors.Wrap(base.ErrRtmpUnexpectedMsg)
}
s.avObserver.OnReadRtmpAvMsg(stream.toAvMsg())
default:
@ -240,8 +241,7 @@ func (s *ServerSession) doAck(stream *Stream) error {
func (s *ServerSession) doDataMessageAmf0(stream *Stream) error {
if s.t != ServerSessionTypePub {
nazalog.Errorf("[%s] read audio/video message but server session not pub type.", s.uniqueKey)
return ErrRtmp
return nazaerrors.Wrap(base.ErrRtmpUnexpectedMsg)
}
val, err := stream.msg.peekStringWithType()

Loading…
Cancel
Save