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/httpflv/flv_file_pump.go

150 lines
3.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 httpflv
import (
"time"
"github.com/q191201771/naza/pkg/mock"
)
var Clock = mock.NewStdClock()
// FlvFilePumpOption
//
// 读取flv文件将tag按时间戳间隔缓慢类似于ffmpeg的-re返回
//
type FlvFilePumpOption struct {
IsRecursive bool // 如果为true则循环返回文件内容类似于ffmpeg的-stream_loop -1
}
var defaultFlvFilePumpOption = FlvFilePumpOption{
IsRecursive: false,
}
type FlvFilePump struct {
option FlvFilePumpOption
}
type ModFlvFilePumpOption func(option *FlvFilePumpOption)
func NewFlvFilePump(modOptions ...ModFlvFilePumpOption) *FlvFilePump {
option := defaultFlvFilePumpOption
for _, fn := range modOptions {
fn(&option)
}
return &FlvFilePump{option: option}
}
type OnPumpFlvTag func(tag Tag) bool
// Pump
//
// @param onFlvTag 如果回调中返回false则停止Pump
//
func (f *FlvFilePump) Pump(filename string, onFlvTag OnPumpFlvTag) error {
// 一次性将文件所有内容读入内存,后续不再读取文件
tags, err := ReadAllTagsFromFlvFile(filename)
if err != nil {
return err
}
return f.PumpWithTags(tags, onFlvTag)
}
// PumpWithTags @return error 暂时只做预留目前只会返回nil
//
func (f *FlvFilePump) PumpWithTags(tags []Tag, onFlvTag OnPumpFlvTag) error {
var totalBaseTs uint32 // 整体的基础时间戳。每轮最后更新
var hasReadThisBaseTs bool
var thisBaseTs uint32 // 每一轮的第一个tag时间戳
var prevTagTs uint32 // 上一个tag的时间戳
var hasReadTotalFirstTag bool
var totalFirstTagTs uint32 // 第一轮的第一个tag的时间戳
var totalFirstTagTick int64 // 第一轮的第一个tag的物理时间
const addTsBetweenRound = 1
// 循环一次,代表遍历文件一次
for roundIndex := 0; ; roundIndex++ {
Log.Debugf("new round. index=%d", roundIndex)
hasReadThisBaseTs = false
// 遍历所有tag数据
for _, tag := range tags {
// metadata只在第一轮发送一次
if tag.IsMetadata() {
if totalBaseTs == 0 {
tag.Header.Timestamp = 0
if !onFlvTag(tag) {
return nil
}
}
continue
}
// 修改时间戳
// 使得不同轮依然线性增长
if !hasReadThisBaseTs {
// 本轮第一个tag
thisBaseTs = tag.Header.Timestamp
hasReadThisBaseTs = true
tag.Header.Timestamp = totalBaseTs
} else {
tag.Header.Timestamp = totalBaseTs + tag.Header.Timestamp - thisBaseTs
}
// 修改时间戳
// 如果时间戳比前一个tag的还小可能发生了跳跃我们直接设置为上一包的值+1然后不sleep直接发送
if tag.Header.Timestamp < prevTagTs {
tag.Header.Timestamp = prevTagTs + 1
}
if hasReadTotalFirstTag {
// 当前时间戳与第一轮的第一个tag的时间戳差值
diffTs := tag.Header.Timestamp - totalFirstTagTs
// 当前物理时间与第一轮的第一个tag的物理时间差值
diffTick := Clock.Now().UnixNano()/1000000 - totalFirstTagTick
// 如果还没到物理时间差值就sleep
if diffTick < int64(diffTs) {
Clock.Sleep(time.Duration(int64(diffTs)-diffTick) * time.Millisecond)
}
} else {
// 第一轮的第一个tag记录下来
totalFirstTagTick = Clock.Now().UnixNano() / 1000000
totalFirstTagTs = tag.Header.Timestamp
hasReadTotalFirstTag = true
}
if !onFlvTag(tag) {
return nil
}
prevTagTs = tag.Header.Timestamp
}
totalBaseTs = prevTagTs + addTsBetweenRound
if !f.option.IsRecursive {
break
}
}
return nil
}