mirror of
https://github.com/BililiveRecorder/BililiveRecorder.git
synced 2024-11-15 19:22:19 +08:00
Add setting for amount of flv keyframe indexes
This commit is contained in:
parent
44977e688e
commit
df1d82c872
|
@ -34,7 +34,8 @@ namespace BililiveRecorder.Cli.Configure
|
|||
TimingStreamConnect,
|
||||
TimingDanmakuRetry,
|
||||
TimingWatchdogTimeout,
|
||||
RecordDanmakuFlushInterval
|
||||
RecordDanmakuFlushInterval,
|
||||
FlvMetadataKeyframeIndexCount
|
||||
}
|
||||
public enum RoomConfigProperties
|
||||
{
|
||||
|
@ -81,6 +82,7 @@ namespace BililiveRecorder.Cli.Configure
|
|||
GlobalConfig.Add(GlobalConfigProperties.TimingDanmakuRetry, new ConfigInstruction<GlobalConfig, uint>(config => config.HasTimingDanmakuRetry = false, (config, value) => config.TimingDanmakuRetry = value) { Name = "TimingDanmakuRetry", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.TimingWatchdogTimeout, new ConfigInstruction<GlobalConfig, uint>(config => config.HasTimingWatchdogTimeout = false, (config, value) => config.TimingWatchdogTimeout = value) { Name = "TimingWatchdogTimeout", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.RecordDanmakuFlushInterval, new ConfigInstruction<GlobalConfig, uint>(config => config.HasRecordDanmakuFlushInterval = false, (config, value) => config.RecordDanmakuFlushInterval = value) { Name = "RecordDanmakuFlushInterval", CanBeOptional = true });
|
||||
GlobalConfig.Add(GlobalConfigProperties.FlvMetadataKeyframeIndexCount, new ConfigInstruction<GlobalConfig, uint>(config => config.HasFlvMetadataKeyframeIndexCount = false, (config, value) => config.FlvMetadataKeyframeIndexCount = value) { Name = "FlvMetadataKeyframeIndexCount", CanBeOptional = true });
|
||||
|
||||
RoomConfig.Add(RoomConfigProperties.RoomId, new ConfigInstruction<RoomConfig, int>(config => config.HasRoomId = false, (config, value) => config.RoomId = value) { Name = "RoomId", CanBeOptional = false });
|
||||
RoomConfig.Add(RoomConfigProperties.AutoRecord, new ConfigInstruction<RoomConfig, bool>(config => config.HasAutoRecord = false, (config, value) => config.AutoRecord = value) { Name = "AutoRecord", CanBeOptional = false });
|
||||
|
|
|
@ -166,6 +166,11 @@ namespace BililiveRecorder.Core.Config.V2
|
|||
/// </summary>
|
||||
public uint RecordDanmakuFlushInterval => this.GetPropertyValue<uint>();
|
||||
|
||||
/// <summary>
|
||||
/// FLV文件关键帧索引数量
|
||||
/// </summary>
|
||||
public uint FlvMetadataKeyframeIndexCount => this.GetPropertyValue<uint>();
|
||||
|
||||
}
|
||||
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
|
@ -347,6 +352,14 @@ namespace BililiveRecorder.Core.Config.V2
|
|||
[JsonProperty(nameof(RecordDanmakuFlushInterval)), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Optional<uint> OptionalRecordDanmakuFlushInterval { get => this.GetPropertyValueOptional<uint>(nameof(this.RecordDanmakuFlushInterval)); set => this.SetPropertyValueOptional(value, nameof(this.RecordDanmakuFlushInterval)); }
|
||||
|
||||
/// <summary>
|
||||
/// FLV文件关键帧索引数量
|
||||
/// </summary>
|
||||
public uint FlvMetadataKeyframeIndexCount { get => this.GetPropertyValue<uint>(); set => this.SetPropertyValue(value); }
|
||||
public bool HasFlvMetadataKeyframeIndexCount { get => this.GetPropertyHasValue(nameof(this.FlvMetadataKeyframeIndexCount)); set => this.SetPropertyHasValue<uint>(value, nameof(this.FlvMetadataKeyframeIndexCount)); }
|
||||
[JsonProperty(nameof(FlvMetadataKeyframeIndexCount)), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public Optional<uint> OptionalFlvMetadataKeyframeIndexCount { get => this.GetPropertyValueOptional<uint>(nameof(this.FlvMetadataKeyframeIndexCount)); set => this.SetPropertyValueOptional(value, nameof(this.FlvMetadataKeyframeIndexCount)); }
|
||||
|
||||
}
|
||||
|
||||
public sealed partial class DefaultConfig
|
||||
|
@ -398,6 +411,8 @@ namespace BililiveRecorder.Core.Config.V2
|
|||
|
||||
public uint RecordDanmakuFlushInterval => 20;
|
||||
|
||||
public uint FlvMetadataKeyframeIndexCount => 6300;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,12 +15,12 @@ namespace BililiveRecorder.Core.Recording
|
|||
this.serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
||||
}
|
||||
|
||||
public IFlvProcessingContextWriter CreateWriter(IFlvWriterTargetProvider targetProvider) =>
|
||||
public IFlvProcessingContextWriter CreateWriter(IFlvWriterTargetProvider targetProvider, uint maxKeyframeCount) =>
|
||||
new FlvProcessingContextWriter(
|
||||
tagWriter: new FlvTagFileWriter(targetProvider: targetProvider,
|
||||
memoryStreamProvider: this.serviceProvider.GetRequiredService<IMemoryStreamProvider>(),
|
||||
logger: this.serviceProvider.GetService<ILogger>()),
|
||||
allowMissingHeader: false,
|
||||
disableKeyframes: false);
|
||||
maxKeyframeCount: maxKeyframeCount);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,6 @@ namespace BililiveRecorder.Core.Recording
|
|||
{
|
||||
public interface IFlvProcessingContextWriterFactory
|
||||
{
|
||||
IFlvProcessingContextWriter CreateWriter(IFlvWriterTargetProvider targetProvider);
|
||||
IFlvProcessingContextWriter CreateWriter(IFlvWriterTargetProvider targetProvider, uint maxKeyframeCount);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ namespace BililiveRecorder.Core.Recording
|
|||
|
||||
this.reader = this.tagGroupReaderFactory.CreateTagGroupReader(this.flvTagReaderFactory.CreateFlvTagReader(pipe.Reader));
|
||||
|
||||
this.writer = this.writerFactory.CreateWriter(this.targetProvider);
|
||||
this.writer = this.writerFactory.CreateWriter(this.targetProvider, this.room.RoomConfig.FlvMetadataKeyframeIndexCount);
|
||||
this.writer.BeforeScriptTagWrite = this.Writer_BeforeScriptTagWrite;
|
||||
this.writer.FileClosed += (sender, e) =>
|
||||
{
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace BililiveRecorder.Flv.Writer
|
|||
private readonly SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);
|
||||
private readonly IFlvTagWriter tagWriter;
|
||||
private readonly bool allowMissingHeader;
|
||||
private readonly bool disableKeyframes;
|
||||
private readonly uint maxKeyframeCount;
|
||||
private bool disposedValue;
|
||||
|
||||
private WriterState state = WriterState.EmptyFileOrNotOpen;
|
||||
|
@ -30,11 +30,11 @@ namespace BililiveRecorder.Flv.Writer
|
|||
public Action<ScriptTagBody>? BeforeScriptTagWrite { get; set; }
|
||||
public Action<ScriptTagBody>? BeforeScriptTagRewrite { get; set; }
|
||||
|
||||
public FlvProcessingContextWriter(IFlvTagWriter tagWriter, bool allowMissingHeader, bool disableKeyframes)
|
||||
public FlvProcessingContextWriter(IFlvTagWriter tagWriter, bool allowMissingHeader, uint maxKeyframeCount)
|
||||
{
|
||||
this.tagWriter = tagWriter ?? throw new ArgumentNullException(nameof(tagWriter));
|
||||
this.allowMissingHeader = allowMissingHeader;
|
||||
this.disableKeyframes = disableKeyframes;
|
||||
this.maxKeyframeCount = maxKeyframeCount;
|
||||
}
|
||||
|
||||
public async Task WriteAsync(FlvProcessingContext context)
|
||||
|
@ -192,9 +192,9 @@ namespace BililiveRecorder.Flv.Writer
|
|||
{
|
||||
value["duration"] = (ScriptDataNumber)0;
|
||||
|
||||
if (!this.disableKeyframes)
|
||||
if (this.maxKeyframeCount > 0)
|
||||
{
|
||||
var kfv = new KeyframesScriptDataValue();
|
||||
var kfv = new KeyframesScriptDataValue(this.maxKeyframeCount);
|
||||
value["keyframes"] = kfv;
|
||||
this.keyframesScriptDataValue = kfv;
|
||||
}
|
||||
|
|
|
@ -14,14 +14,15 @@ namespace BililiveRecorder.Flv.Writer
|
|||
internal class KeyframesScriptDataValue : IScriptDataValue
|
||||
{
|
||||
/*
|
||||
* 以默认 6300 组数据计算
|
||||
* 最少能保存大约 6300 * 2 second = 3.5 hour 的关键帧索引
|
||||
* 如果以 5 秒计算则 6300 * 5 second = 8.75 hour
|
||||
*
|
||||
* 每组数据的大小为 18 bytes
|
||||
* 6300 * 18 B ~= 49.2 KiB
|
||||
*/
|
||||
|
||||
private const int MaxDataCount = 6300;
|
||||
private const double MinInterval = 1900;
|
||||
|
||||
private const string Keyframes = "keyframes";
|
||||
private const string Times = "times";
|
||||
private const string FilePositions = "filepositions";
|
||||
private const string Spacer = "spacer";
|
||||
|
@ -34,15 +35,24 @@ namespace BililiveRecorder.Flv.Writer
|
|||
|
||||
public ScriptDataType Type => ScriptDataType.Object;
|
||||
|
||||
private readonly uint maxKeyframeCount;
|
||||
private readonly List<Data> KeyframesData = new();
|
||||
|
||||
public KeyframesScriptDataValue(uint maxKeyframeCount)
|
||||
{
|
||||
this.maxKeyframeCount = maxKeyframeCount;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AddData(double time_in_ms, double filePosition)
|
||||
{
|
||||
var keyframesData = this.KeyframesData;
|
||||
if (keyframesData.Count < MaxDataCount && (keyframesData.Count == 0 || ((time_in_ms - keyframesData[keyframesData.Count - 1].Time) > MinInterval)))
|
||||
if (keyframesData.Count < this.maxKeyframeCount)
|
||||
{
|
||||
keyframesData.Add(new Data(time: time_in_ms / 1000d, filePosition: filePosition));
|
||||
if (keyframesData.Count == 0 || ((time_in_ms - keyframesData[keyframesData.Count - 1].Time) > MinInterval))
|
||||
{
|
||||
keyframesData.Add(new Data(time: time_in_ms / 1000d, filePosition: filePosition));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +106,7 @@ namespace BililiveRecorder.Flv.Writer
|
|||
WriteKey(stream, SpacerBytes);
|
||||
|
||||
// array
|
||||
var count = 2u * (uint)(MaxDataCount - keyframesData.Count);
|
||||
var count = 2u * (uint)(this.maxKeyframeCount - keyframesData.Count);
|
||||
WriteStrictArray(stream, count);
|
||||
|
||||
// value
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace BililiveRecorder.ToolBox.Tool.Analyze
|
|||
|
||||
// Pipeline
|
||||
using var grouping = new TagGroupReader(tagReader);
|
||||
using var writer = new FlvProcessingContextWriter(tagWriter: tagWriter, allowMissingHeader: true, disableKeyframes: true);
|
||||
using var writer = new FlvProcessingContextWriter(tagWriter: tagWriter, allowMissingHeader: true, maxKeyframeCount: 0);
|
||||
var statsRule = new StatsRule();
|
||||
var pipeline = new ProcessingPipelineBuilder(new ServiceCollection().BuildServiceProvider()).Add(statsRule).AddDefault().AddRemoveFillerData().Build();
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ namespace BililiveRecorder.ToolBox.Tool.Fix
|
|||
|
||||
// Pipeline
|
||||
using var grouping = new TagGroupReader(tagReader);
|
||||
using var writer = new FlvProcessingContextWriter(tagWriter: tagWriter, allowMissingHeader: true, disableKeyframes: false);
|
||||
using var writer = new FlvProcessingContextWriter(tagWriter: tagWriter, allowMissingHeader: true, maxKeyframeCount: 0);
|
||||
var statsRule = new StatsRule();
|
||||
var pipeline = new ProcessingPipelineBuilder(new ServiceCollection().BuildServiceProvider()).Add(statsRule).AddDefault().AddRemoveFillerData().Build();
|
||||
|
||||
|
|
|
@ -48,6 +48,14 @@
|
|||
<ui:NumberBox Minimum="0" SmallChange="1" Text="{Binding RecordDanmakuFlushInterval,UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</c:SettingWithDefault>
|
||||
</GroupBox>
|
||||
<GroupBox Header="FLV Keyframe Index">
|
||||
<StackPanel>
|
||||
<c:SettingWithDefault IsSettingNotUsingDefault="{Binding HasFlvMetadataKeyframeIndexCount}" Header="索引数量 Index Count">
|
||||
<ui:NumberBox Minimum="0" SmallChange="1" Text="{Binding FlvMetadataKeyframeIndexCount,UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</c:SettingWithDefault>
|
||||
<TextBlock Text="一组索引的大小为 18 byte,其他信息见网站文档"/>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Header="Timing">
|
||||
<ui:SimpleStackPanel Spacing="10">
|
||||
<c:SettingWithDefault IsSettingNotUsingDefault="{Binding HasTimingStreamRetry}" Header="录制重试间隔">
|
||||
|
|
|
@ -229,6 +229,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"FlvMetadataKeyframeIndexCount": {
|
||||
"description": "FLV文件关键帧索引数量\n默认: 6300",
|
||||
"markdownDescription": "FLV文件关键帧索引数量 \n默认: `6300 `\n\n索引最少 2 秒一个,间隔小于 2 秒的关键帧会被忽略。关键帧间隔是由主播在直播软件里设置的,通常为 1 到 10 秒。 \n默认 6300 组最少能保存 6300 * 2 second = 3.5 hour 的索引。 \n如果按关键帧间隔 5 秒计算则为 8.75 hour\n\n一组关键帧索引的大小是 18 byte,默认 6300 组所占空间大约为 50 KiB。",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"HasValue": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"Value": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 4294967295,
|
||||
"default": 6300
|
||||
}
|
||||
}
|
||||
},
|
||||
"RecordMode": {
|
||||
"description": "录制模式\n默认: RecordMode.Standard",
|
||||
"markdownDescription": "录制模式 \n默认: `RecordMode.Standard `\n\n本设置项是一个 enum,键值对应如下:\n\n| 键 | 值 |\n|:--:|:--:|\n| RecordMode.Standard | 0 |\n| RecordMode.RawData | 1 |\n\n关于录制模式的说明见 [录制模式](/docs/basic/record_mode/)",
|
||||
|
|
|
@ -215,4 +215,14 @@ export const data: Array<ConfigEntry> = [
|
|||
xmlComment: "触发 <see cref=\"System.Xml.XmlWriter.Flush\"/> 的弹幕个数",
|
||||
markdown: ""
|
||||
},
|
||||
{
|
||||
name: "FlvMetadataKeyframeIndexCount",
|
||||
description: "FLV文件关键帧索引数量",
|
||||
type: "uint",
|
||||
configType: "globalOnly",
|
||||
advancedConfig: true,
|
||||
defaultValue: "6300",
|
||||
xmlComment: "FLV文件关键帧索引数量",
|
||||
markdown: "索引最少 2 秒一个,间隔小于 2 秒的关键帧会被忽略。关键帧间隔是由主播在直播软件里设置的,通常为 1 到 10 秒。 \n默认 6300 组最少能保存 6300 * 2 second = 3.5 hour 的索引。 \n如果按关键帧间隔 5 秒计算则为 8.75 hour\n\n一组关键帧索引的大小是 18 byte,默认 6300 组所占空间大约为 50 KiB。"
|
||||
},
|
||||
];
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BililiveRecorder.Flv.Grouping;
|
||||
|
@ -13,11 +12,9 @@ namespace BililiveRecorder.Flv.Tests.RuleTests
|
|||
{
|
||||
public abstract class IntegratedTestBase
|
||||
{
|
||||
|
||||
|
||||
protected static async Task RunPipeline(ITagGroupReader reader, IFlvTagWriter output, List<ProcessingComment> comments)
|
||||
{
|
||||
var writer = new FlvProcessingContextWriter(tagWriter: output, allowMissingHeader: true, disableKeyframes: true);
|
||||
var writer = new FlvProcessingContextWriter(tagWriter: output, allowMissingHeader: true, maxKeyframeCount: 0);
|
||||
var session = new Dictionary<object, object?>();
|
||||
var context = new FlvProcessingContext();
|
||||
var pipeline = new ProcessingPipelineBuilder(new ServiceCollection().BuildServiceProvider()).AddDefault().AddRemoveFillerData().Build();
|
||||
|
|
Loading…
Reference in New Issue
Block a user