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/rtsp/avpacket_queue.go

86 lines
2.5 KiB
Go

// Copyright 2020, 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 rtsp
import (
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/naza/pkg/circularqueue"
"github.com/q191201771/naza/pkg/nazalog"
)
// 处理音频和视频的时间戳:
// 1. 让音频和视频的时间戳都从0开始改变原时间戳
// 2. 让音频和视频的时间戳交替递增输出(不改变原时间戳)
// 注意,本模块默认音频和视频都存在,如果只有音频或只有视频,则不要使用该模块
const maxQueueSize = 128
type OnAVPacket func(pkt base.AVPacket)
type AVPacketQueue struct {
onAVPacket OnAVPacket
audioBaseTS int64 // audio base timestamp
videoBaseTS int64 // video base timestamp
audioQueue *circularqueue.CircularQueue // TODO chef: 特化成AVPacket类型
videoQueue *circularqueue.CircularQueue
}
func NewAVPacketQueue(onAVPacket OnAVPacket) *AVPacketQueue {
return &AVPacketQueue{
onAVPacket: onAVPacket,
audioBaseTS: -1,
videoBaseTS: -1,
audioQueue: circularqueue.New(maxQueueSize),
videoQueue: circularqueue.New(maxQueueSize),
}
}
// 注意,调用方保证,音频相较于音频,视频相较于视频,时间戳是线性递增的。
func (a *AVPacketQueue) Insert(pkt base.AVPacket) {
switch pkt.PayloadType {
case base.RTPPacketTypeAVC:
if a.videoBaseTS == -1 {
a.videoBaseTS = int64(pkt.Timestamp)
}
pkt.Timestamp -= uint32(a.videoBaseTS)
if a.videoQueue.Full() {
_, _ = a.videoQueue.PopFront()
nazalog.Warnf("video queue full, drop front packet.")
}
_ = a.videoQueue.PushBack(pkt)
case base.RTPPacketTypeAAC:
if a.audioBaseTS == -1 {
a.audioBaseTS = int64(pkt.Timestamp)
}
pkt.Timestamp -= uint32(a.audioBaseTS)
if a.audioQueue.Full() {
_, _ = a.audioQueue.PopFront()
nazalog.Warnf("audio queue full, drop front packet. a=%d, v=%d", a.audioQueue.Size(), a.videoQueue.Size())
}
_ = a.audioQueue.PushBack(pkt)
} //switch loop
for !a.audioQueue.Empty() && !a.videoQueue.Empty() {
apkt, _ := a.audioQueue.Front()
vpkt, _ := a.videoQueue.Front()
aapkt := apkt.(base.AVPacket)
vvpkt := vpkt.(base.AVPacket)
if aapkt.Timestamp < vvpkt.Timestamp {
_, _ = a.audioQueue.PopFront()
a.onAVPacket(aapkt)
} else {
_, _ = a.videoQueue.PopFront()
a.onAVPacket(vvpkt)
}
}
}