mirror of https://github.com/q191201771/lal.git
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.
156 lines
4.2 KiB
Go
156 lines
4.2 KiB
Go
// Copyright 2022, 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 remux
|
|
|
|
import (
|
|
"github.com/q191201771/lal/pkg/base"
|
|
"github.com/q191201771/lal/pkg/h2645"
|
|
)
|
|
|
|
// TODO(chef): 该文件处于开发阶段,请不要直接使用
|
|
// TODO(chef): 支持音频 202206
|
|
|
|
// Rtmp2AvPacketRemuxer
|
|
//
|
|
// 用途:
|
|
// - 将rtmp流中的视频转换成ffmpeg可解码的格式
|
|
type Rtmp2AvPacketRemuxer struct {
|
|
option Rtmp2AvPacketRemuxerOption
|
|
onAvPacket func(pkt base.AvPacket, arg interface{})
|
|
|
|
spspps []byte // annexb格式
|
|
}
|
|
|
|
type Rtmp2AvPacketRemuxerOption struct {
|
|
// TODO(chef): impl me 202206
|
|
TryInPlaceFlag bool // 尝试在原有内存上直接修改
|
|
}
|
|
|
|
var defaultRtmp2AvPacketRemuxerOption = Rtmp2AvPacketRemuxerOption{
|
|
TryInPlaceFlag: false,
|
|
}
|
|
|
|
func NewRtmp2AvPacketRemuxer() *Rtmp2AvPacketRemuxer {
|
|
return &Rtmp2AvPacketRemuxer{
|
|
option: defaultRtmp2AvPacketRemuxerOption,
|
|
onAvPacket: defaultOnAvPacket,
|
|
}
|
|
}
|
|
|
|
func (r *Rtmp2AvPacketRemuxer) WithOption(modOption func(option *Rtmp2AvPacketRemuxerOption)) *Rtmp2AvPacketRemuxer {
|
|
modOption(&r.option)
|
|
return r
|
|
}
|
|
|
|
// WithOnAvPacket
|
|
//
|
|
// @param onAvPacket: pkt 内存由内部新申请,回调后内部不再使用
|
|
func (r *Rtmp2AvPacketRemuxer) WithOnAvPacket(onAvPacket func(pkt base.AvPacket, arg interface{})) *Rtmp2AvPacketRemuxer {
|
|
r.onAvPacket = onAvPacket
|
|
return r
|
|
}
|
|
|
|
func (r *Rtmp2AvPacketRemuxer) FeedRtmpMsg(msg base.RtmpMsg, arg interface{}) error {
|
|
switch msg.Header.MsgTypeId {
|
|
case base.RtmpTypeIdVideo:
|
|
return r.feedVideo(msg, arg)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
func (r *Rtmp2AvPacketRemuxer) feedVideo(msg base.RtmpMsg, arg interface{}) error {
|
|
if len(msg.Payload) <= 5 {
|
|
return nil
|
|
}
|
|
|
|
isH264 := msg.VideoCodecId() == base.RtmpCodecIdAvc
|
|
|
|
var err error
|
|
if msg.IsVideoKeySeqHeader() {
|
|
r.spspps, err = h2645.SeqHeader2Annexb(isH264, msg.Payload)
|
|
return err
|
|
}
|
|
|
|
var out []byte
|
|
var vps, sps, pps []byte
|
|
err = h2645.IterateNaluAvcc(msg.Payload[5:], func(nal []byte) {
|
|
nalType := h2645.ParseNaluType(isH264, nal[0])
|
|
|
|
if isH264 {
|
|
if nalType == h2645.H264NaluTypeSps {
|
|
sps = nal
|
|
} else if nalType == h2645.H264NaluTypePps {
|
|
pps = nal
|
|
if len(sps) != 0 && len(pps) != 0 {
|
|
r.spspps = r.spspps[0:0]
|
|
r.spspps = append(r.spspps, h2645.NaluStartCode4...)
|
|
r.spspps = append(r.spspps, sps...)
|
|
r.spspps = append(r.spspps, h2645.NaluStartCode4...)
|
|
r.spspps = append(r.spspps, pps...)
|
|
}
|
|
} else if nalType == h2645.H264NaluTypeIdrSlice {
|
|
out = append(out, r.spspps...)
|
|
out = append(out, h2645.NaluStartCode4...)
|
|
out = append(out, nal...)
|
|
} else {
|
|
out = append(out, h2645.NaluStartCode4...)
|
|
out = append(out, nal...)
|
|
}
|
|
} else {
|
|
if nalType == h2645.H265NaluTypeVps {
|
|
vps = nal
|
|
} else if nalType == h2645.H265NaluTypeSps {
|
|
sps = nal
|
|
} else if nalType == h2645.H265NaluTypePps {
|
|
pps = nal
|
|
if len(vps) != 0 && len(sps) != 0 && len(pps) != 0 {
|
|
r.spspps = r.spspps[0:0]
|
|
r.spspps = append(r.spspps, h2645.NaluStartCode4...)
|
|
r.spspps = append(r.spspps, vps...)
|
|
r.spspps = append(r.spspps, h2645.NaluStartCode4...)
|
|
r.spspps = append(r.spspps, sps...)
|
|
r.spspps = append(r.spspps, h2645.NaluStartCode4...)
|
|
r.spspps = append(r.spspps, pps...)
|
|
}
|
|
} else if h2645.H265IsIrapNalu(nalType) {
|
|
out = append(out, r.spspps...)
|
|
out = append(out, h2645.NaluStartCode4...)
|
|
out = append(out, nal...)
|
|
} else {
|
|
out = append(out, h2645.NaluStartCode4...)
|
|
out = append(out, nal...)
|
|
}
|
|
}
|
|
})
|
|
|
|
if len(out) > 0 {
|
|
pkt := base.AvPacket{
|
|
Timestamp: int64(msg.Header.TimestampAbs),
|
|
Pts: int64(msg.Pts()),
|
|
Payload: out,
|
|
}
|
|
if isH264 {
|
|
pkt.PayloadType = base.AvPacketPtAvc
|
|
} else {
|
|
pkt.PayloadType = base.AvPacketPtHevc
|
|
}
|
|
r.onAvPacket(pkt, arg)
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
func defaultOnAvPacket(pkt base.AvPacket, arg interface{}) {
|
|
// noop
|
|
}
|