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/logic/gop_cache.go

144 lines
2.9 KiB
Go

// Copyright 2019, 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 logic
import (
"github.com/q191201771/lal/pkg/rtmp"
"github.com/q191201771/naza/pkg/nazalog"
)
// 考虑以下两种场景:
// - 只有上行没有下行没有必要做rtmp chunk切片的操作
// - 有多个下行只需要做一次rtmp chunk切片
// 所以这一步做了懒处理
type LazyChunkDivider struct {
message []byte
header *rtmp.Header
chunks []byte
}
func (lcd *LazyChunkDivider) Init(message []byte, header *rtmp.Header) {
lcd.message = message
lcd.header = header
}
func (lcd *LazyChunkDivider) Get() []byte {
if lcd.chunks == nil {
lcd.chunks = rtmp.Message2Chunks(lcd.message, lcd.header)
}
return lcd.chunks
}
// 懒转换
type LazyRTMPMsg2FLVTag struct {
msg rtmp.AVMsg
tag []byte
}
func (l *LazyRTMPMsg2FLVTag) Init(msg rtmp.AVMsg) {
l.msg = msg
}
func (l *LazyRTMPMsg2FLVTag) Get() []byte {
if l.tag == nil {
l.tag = Trans.RTMPMsg2FLVTag(l.msg).Raw
}
return l.tag
}
type GOPCache struct {
t string
uniqueKey string
gopNum int
Metadata []byte
VideoSeqHeader []byte
AACSeqHeader []byte
// TODO 考虑优化成环形队列
gopList []*GOP
}
func NewGopCache(t string, uniqueKey string, gopNum int) *GOPCache {
return &GOPCache{
t: t,
uniqueKey: uniqueKey,
gopNum: gopNum,
}
}
type LazyGet func() []byte
func (gc *GOPCache) Feed(msg rtmp.AVMsg, lg LazyGet) {
switch msg.Header.MsgTypeID {
case rtmp.TypeidDataMessageAMF0:
gc.Metadata = lg()
nazalog.Debugf("cache %s metadata. [%s] size:%d", gc.t, gc.uniqueKey, len(gc.Metadata))
return
case rtmp.TypeidAudio:
if msg.IsAACSeqHeader() {
gc.AACSeqHeader = lg()
nazalog.Debugf("cache %s aac seq header. [%s] size:%d", gc.t, gc.uniqueKey, len(gc.AACSeqHeader))
return
}
case rtmp.TypeidVideo:
if msg.IsVideoKeySeqHeader() {
gc.VideoSeqHeader = lg()
nazalog.Debugf("cache %s video seq header. [%s] size:%d", gc.t, gc.uniqueKey, len(gc.VideoSeqHeader))
return
}
}
if gc.gopNum != 0 {
if msg.IsVideoKeyNalu() {
var gop GOP
gop.Feed(msg, lg())
gc.gopList = append(gc.gopList, &gop)
if len(gc.gopList) > gc.gopNum {
gc.gopList = gc.gopList[1:]
}
} else {
if len(gc.gopList) > 0 {
gc.gopList[len(gc.gopList)-1].Feed(msg, lg())
}
}
}
}
func (gc *GOPCache) GetFullGOP() []*GOP {
if len(gc.gopList) < 2 {
return nil
}
return gc.gopList[:len(gc.gopList)-2]
}
func (gc *GOPCache) GetLastGOP() *GOP {
if len(gc.gopList) < 1 {
return nil
}
return gc.gopList[len(gc.gopList)-1]
}
func (gc *GOPCache) Clear() {
gc.Metadata = nil
gc.VideoSeqHeader = nil
gc.AACSeqHeader = nil
gc.gopList = nil
}
type GOP struct {
data [][]byte
}
func (g *GOP) Feed(msg rtmp.AVMsg, b []byte) {
g.data = append(g.data, b)
}