diff --git a/BililiveRecorder.Core/BililiveRecorder.Core.csproj b/BililiveRecorder.Core/BililiveRecorder.Core.csproj
index 0adb136..9123447 100644
--- a/BililiveRecorder.Core/BililiveRecorder.Core.csproj
+++ b/BililiveRecorder.Core/BililiveRecorder.Core.csproj
@@ -10,6 +10,7 @@
+
diff --git a/BililiveRecorder.Core/RecordedRoom.cs b/BililiveRecorder.Core/RecordedRoom.cs
index f24e545..a5e672b 100644
--- a/BililiveRecorder.Core/RecordedRoom.cs
+++ b/BililiveRecorder.Core/RecordedRoom.cs
@@ -24,8 +24,8 @@ namespace BililiveRecorder.Core
public bool IsMonitoring => StreamMonitor.receiver.IsConnected;
public bool IsRecording => flvStream != null;
- public FlvStreamProcessor Processor; // FlvProcessor
- public ObservableCollection Clips { get; private set; } = new ObservableCollection();
+ public IFlvStreamProcessor Processor; // FlvProcessor
+ public ObservableCollection Clips { get; private set; } = new ObservableCollection();
internal StreamMonitor StreamMonitor { get; }
private Settings _settings { get; }
diff --git a/BililiveRecorder.FlvProcessor/BililiveRecorder.FlvProcessor.csproj b/BililiveRecorder.FlvProcessor/BililiveRecorder.FlvProcessor.csproj
index 0c0eeaa..588bbfe 100644
--- a/BililiveRecorder.FlvProcessor/BililiveRecorder.FlvProcessor.csproj
+++ b/BililiveRecorder.FlvProcessor/BililiveRecorder.FlvProcessor.csproj
@@ -10,6 +10,7 @@
+
diff --git a/BililiveRecorder.FlvProcessor/Events.cs b/BililiveRecorder.FlvProcessor/Events.cs
index de663d4..79a065a 100644
--- a/BililiveRecorder.FlvProcessor/Events.cs
+++ b/BililiveRecorder.FlvProcessor/Events.cs
@@ -1,26 +1,21 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace BililiveRecorder.FlvProcessor
+namespace BililiveRecorder.FlvProcessor
{
public delegate void TagProcessedEvent(object sender, TagProcessedArgs e);
public class TagProcessedArgs
{
- public FlvTag Tag;
+ public IFlvTag Tag;
}
-
-
+
public delegate void ClipFinalizedEvent(object sender, ClipFinalizedArgs e);
public class ClipFinalizedArgs
{
- public FlvClipProcessor ClipProcessor;
+ public IFlvClipProcessor ClipProcessor;
}
public delegate void StreamFinalizedEvent(object sender, StreamFinalizedArgs e);
public class StreamFinalizedArgs
{
- public FlvStreamProcessor StreamProcessor;
+ public IFlvStreamProcessor StreamProcessor;
}
}
diff --git a/BililiveRecorder.FlvProcessor/FlvClipProcessor.cs b/BililiveRecorder.FlvProcessor/FlvClipProcessor.cs
index c121c27..b61e293 100644
--- a/BililiveRecorder.FlvProcessor/FlvClipProcessor.cs
+++ b/BililiveRecorder.FlvProcessor/FlvClipProcessor.cs
@@ -2,22 +2,21 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Text;
namespace BililiveRecorder.FlvProcessor
{
- public class FlvClipProcessor
+ public class FlvClipProcessor : IFlvClipProcessor
{
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
- public readonly FlvMetadata Header;
- public readonly List HTags;
- public readonly List Tags;
- private int target = -1;
+ public IFlvMetadata Header { get; }
+ public List HTags { get; }
+ public List Tags { get; }
+ private readonly int target = -1;
- public Func GetFileName;
+ public Func GetFileName { get; set; }
- public FlvClipProcessor(FlvMetadata header, List head, List past, uint future)
+ public FlvClipProcessor(IFlvMetadata header, List head, List past, uint future)
{
Header = header;
HTags = head;
@@ -27,7 +26,7 @@ namespace BililiveRecorder.FlvProcessor
Tags.Count, Tags[0].TimeStamp, Tags[Tags.Count - 1].TimeStamp, (Tags[Tags.Count - 1].TimeStamp - Tags[0].TimeStamp) / 1000d);
}
- public void AddTag(FlvTag tag)
+ public void AddTag(IFlvTag tag)
{
Tags.Add(tag);
if (tag.TimeStamp >= target)
diff --git a/BililiveRecorder.FlvProcessor/FlvMetadata.cs b/BililiveRecorder.FlvProcessor/FlvMetadata.cs
index 2b754b0..7a83141 100644
--- a/BililiveRecorder.FlvProcessor/FlvMetadata.cs
+++ b/BililiveRecorder.FlvProcessor/FlvMetadata.cs
@@ -6,23 +6,29 @@ using System.Text;
namespace BililiveRecorder.FlvProcessor
{
- public class FlvMetadata
+ public class FlvMetadata : IFlvMetadata
{
- public IDictionary Meta = new Dictionary();
+ public IDictionary Meta { get; set; } = new Dictionary();
- public static FlvMetadata Parse(byte[] data)
+ public FlvMetadata()
{
- var m = new FlvMetadata
+ Meta["duration"] = 0.0;
+ Meta["lasttimestamp"] = 0.0;
+ }
+
+ public FlvMetadata(byte[] data)
+ {
+ Meta = _Decode(data);
+
+ if (!Meta.ContainsKey("duration"))
{
- Meta = _Decode(data)
- };
+ Meta["duration"] = 0.0;
+ }
- if (!m.Meta.ContainsKey("duration"))
- m.Meta["duration"] = 0.0;
- if (!m.Meta.ContainsKey("lasttimestamp"))
- m.Meta["lasttimestamp"] = 0.0;
-
- return m;
+ if (!Meta.ContainsKey("lasttimestamp"))
+ {
+ Meta["lasttimestamp"] = 0.0;
+ }
}
public byte[] ToBytes()
diff --git a/BililiveRecorder.FlvProcessor/FlvStreamProcessor.cs b/BililiveRecorder.FlvProcessor/FlvStreamProcessor.cs
index c843898..63fea39 100644
--- a/BililiveRecorder.FlvProcessor/FlvStreamProcessor.cs
+++ b/BililiveRecorder.FlvProcessor/FlvStreamProcessor.cs
@@ -1,18 +1,15 @@
using NLog;
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Net;
-using System.Text;
namespace BililiveRecorder.FlvProcessor
{
// TODO: 重构 Tag 解析流程
// TODO: 添加测试
// 注:下载时会按照 4 11 N bytes 下载
- public class FlvStreamProcessor : IDisposable
+ public class FlvStreamProcessor : IFlvStreamProcessor
{
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
@@ -35,22 +32,22 @@ namespace BililiveRecorder.FlvProcessor
// 0x00, // the "0th" tag has a length of 0
};
- public FlvMetadata Metadata = null;
+ public IFlvMetadata Metadata { get; set; } = null;
public event TagProcessedEvent TagProcessed;
public event StreamFinalizedEvent StreamFinalized;
- public Func GetFileName;
+ public Func GetFileName { get; set; }
- public uint Clip_Past = 90;
- public uint Clip_Future = 30;
+ public uint Clip_Past { get; set; } = 90;
+ public uint Clip_Future { get; set; } = 30;
private readonly bool _noClip = false;
private bool _headerParsed = false;
- private readonly List HTags = new List();
- private readonly List Tags = new List();
+ private readonly List HTags = new List();
+ private readonly List Tags = new List();
private readonly MemoryStream _buffer = new MemoryStream();
private readonly MemoryStream _data = new MemoryStream();
- private FlvTag currentTag = null;
- private object _writelock = new object();
+ private IFlvTag currentTag = null;
+ private readonly object _writelock = new object();
private bool Finallized = false;
private readonly FileStream _fs;
@@ -85,7 +82,9 @@ namespace BililiveRecorder.FlvProcessor
public void AddBytes(byte[] data)
{
lock (_writelock)
+ {
_AddBytes(data);
+ }
}
private void _AddBytes(byte[] data)
@@ -104,10 +103,15 @@ namespace BililiveRecorder.FlvProcessor
}
var r = new bool[FLV_HEADER_BYTES.Length];
for (int i = 0; i < FLV_HEADER_BYTES.Length; i++)
+ {
r[i] = data[i] == FLV_HEADER_BYTES[i];
+ }
+
bool succ = r.All(x => x);
if (!succ)
+ {
throw new NotSupportedException("Not FLV Stream or Not Supported"); // TODO: custom Exception.
+ }
_headerParsed = true;
_AddBytes(data.Skip(FLV_HEADER_BYTES.Length).ToArray());
@@ -140,7 +144,7 @@ namespace BililiveRecorder.FlvProcessor
}
}
- private void _TagCreated(FlvTag tag)
+ private void _TagCreated(IFlvTag tag)
{
if (Metadata == null)
{
@@ -149,7 +153,7 @@ namespace BililiveRecorder.FlvProcessor
_fs?.Write(FLV_HEADER_BYTES, 0, FLV_HEADER_BYTES.Length);
_fs?.Write(new byte[] { 0, 0, 0, 0, }, 0, 4);
- Metadata = FlvMetadata.Parse(tag.Data);
+ Metadata = new FlvMetadata(tag.Data);
// TODO: 添加录播姬标记、录制信息
@@ -202,7 +206,10 @@ namespace BililiveRecorder.FlvProcessor
{
tag.TimeStamp -= BaseTimeStamp; // 修复时间戳
if (tag.TimeStamp < 0)
+ {
tag.TimeStamp = 0;
+ }
+
MaxTimeStamp = Math.Max(MaxTimeStamp, tag.TimeStamp);
}
else
@@ -221,7 +228,9 @@ namespace BililiveRecorder.FlvProcessor
LasttimeRemovedTimestamp = MaxTimeStamp;
int max_remove_index = Tags.FindLastIndex(x => x.IsVideoKeyframe && ((MaxTimeStamp - x.TimeStamp) > (Clip_Past * SEC_TO_MS)));
if (max_remove_index > 0)
+ {
Tags.RemoveRange(0, max_remove_index);
+ }
// Tags.RemoveRange(0, max_remove_index + 1 - 1);
// 给将来的备注:这里是故意 + 1 - 1 的,因为要保留选中的那个关键帧, + 1 就把关键帧删除了
}
@@ -242,7 +251,7 @@ namespace BililiveRecorder.FlvProcessor
_buffer.Write(data, 0, data.Length);
long dataLen = _buffer.Position;
_buffer.Position = 0;
- FlvTag tag = new FlvTag();
+ IFlvTag tag = new FlvTag();
// Previous Tag Size
_buffer.Read(b, 0, 4);
@@ -272,7 +281,7 @@ namespace BililiveRecorder.FlvProcessor
_AddBytes(rest);
}
- public FlvClipProcessor Clip()
+ public IFlvClipProcessor Clip()
{
// 如果禁用 clip 功能 或者 已经结束处理了
if (_noClip || Finallized)
@@ -284,7 +293,7 @@ namespace BililiveRecorder.FlvProcessor
lock (_writelock)
{
logger.Info("剪辑处理中,将会保存过去 {0} 秒和将来 {1} 秒的直播流", (Tags[Tags.Count - 1].TimeStamp - Tags[0].TimeStamp) / 1000d, Clip_Future);
- return new FlvClipProcessor(Metadata, HTags, new List(Tags.ToArray()), Clip_Future);
+ return new FlvClipProcessor(Metadata, HTags, new List(Tags.ToArray()), Clip_Future);
}
}
}
@@ -292,6 +301,7 @@ namespace BililiveRecorder.FlvProcessor
public void FinallizeFile()
{
if (!Finallized)
+ {
lock (_writelock)
{
try
@@ -322,6 +332,7 @@ namespace BililiveRecorder.FlvProcessor
StreamFinalized?.Invoke(this, new StreamFinalizedArgs() { StreamProcessor = this });
}
}
+ }
}
#region IDisposable Support
diff --git a/BililiveRecorder.FlvProcessor/FlvTag.cs b/BililiveRecorder.FlvProcessor/FlvTag.cs
index 01b2144..cd5f183 100644
--- a/BililiveRecorder.FlvProcessor/FlvTag.cs
+++ b/BililiveRecorder.FlvProcessor/FlvTag.cs
@@ -1,22 +1,19 @@
using System;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Text;
namespace BililiveRecorder.FlvProcessor
{
- public class FlvTag
+ public class FlvTag : IFlvTag
{
- public TagType TagType = 0;
- public int TagSize = 0;
- public int TimeStamp = 0;
- public byte[] StreamId = new byte[3];
+ public TagType TagType { get; set; } = 0;
+ public int TagSize { get; set; } = 0;
+ public int TimeStamp { get; set; } = 0;
+ public byte[] StreamId { get; set; } = new byte[3];
public bool IsVideoKeyframe => _IsVideoKeyframe != -1 ? _IsVideoKeyframe == 1 : 1 == (_IsVideoKeyframe = _ParseIsVideoKeyframe());
private int _IsVideoKeyframe = -1;
- public byte[] Data = null;
+ public byte[] Data { get; set; } = null;
public byte[] ToBytes(bool useDataSize, int offset = 0)
{
@@ -38,9 +35,14 @@ namespace BililiveRecorder.FlvProcessor
private int _ParseIsVideoKeyframe()
{
if (TagType != TagType.VIDEO)
+ {
return 0;
+ }
+
if (Data.Length < 1)
+ {
return -1;
+ }
const byte mask = 0b00001111;
const byte compare = 0b00011111;
diff --git a/BililiveRecorder.FlvProcessor/IFlvClipProcessor.cs b/BililiveRecorder.FlvProcessor/IFlvClipProcessor.cs
new file mode 100644
index 0000000..3b24bc1
--- /dev/null
+++ b/BililiveRecorder.FlvProcessor/IFlvClipProcessor.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+
+namespace BililiveRecorder.FlvProcessor
+{
+ public interface IFlvClipProcessor
+ {
+ IFlvMetadata Header { get; }
+ List HTags { get; }
+ List Tags { get; }
+ Func GetFileName { get; set; }
+
+ void AddTag(IFlvTag tag);
+ void FinallizeFile();
+ event ClipFinalizedEvent ClipFinalized;
+
+ }
+}
diff --git a/BililiveRecorder.FlvProcessor/IFlvMetadata.cs b/BililiveRecorder.FlvProcessor/IFlvMetadata.cs
new file mode 100644
index 0000000..d790de5
--- /dev/null
+++ b/BililiveRecorder.FlvProcessor/IFlvMetadata.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+
+namespace BililiveRecorder.FlvProcessor
+{
+ public interface IFlvMetadata
+ {
+ IDictionary Meta { get; set; }
+ byte[] ToBytes();
+ }
+}
diff --git a/BililiveRecorder.FlvProcessor/IFlvStreamProcessor.cs b/BililiveRecorder.FlvProcessor/IFlvStreamProcessor.cs
new file mode 100644
index 0000000..bcec1c5
--- /dev/null
+++ b/BililiveRecorder.FlvProcessor/IFlvStreamProcessor.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace BililiveRecorder.FlvProcessor
+{
+ public interface IFlvStreamProcessor : IDisposable
+ {
+ event TagProcessedEvent TagProcessed;
+ event StreamFinalizedEvent StreamFinalized;
+
+ IFlvMetadata Metadata { get; set; }
+ Func GetFileName { get; set; }
+ uint Clip_Past { get; set; }
+ uint Clip_Future { get; set; }
+ int LasttimeRemovedTimestamp { get; }
+ int MaxTimeStamp { get; }
+ int BaseTimeStamp { get; }
+ int TagVideoCount { get; }
+ int TagAudioCount { get; }
+
+ void AddBytes(byte[] data);
+ IFlvClipProcessor Clip();
+ void FinallizeFile();
+ }
+}
diff --git a/BililiveRecorder.FlvProcessor/IFlvTag.cs b/BililiveRecorder.FlvProcessor/IFlvTag.cs
new file mode 100644
index 0000000..bec5faf
--- /dev/null
+++ b/BililiveRecorder.FlvProcessor/IFlvTag.cs
@@ -0,0 +1,17 @@
+using System.IO;
+
+namespace BililiveRecorder.FlvProcessor
+{
+ public interface IFlvTag
+ {
+ TagType TagType { get; set; }
+ int TagSize { get; set; }
+ int TimeStamp { get; set; }
+ byte[] StreamId { get; set; }
+ bool IsVideoKeyframe { get; }
+ byte[] Data { get; set; }
+
+ byte[] ToBytes(bool useDataSize, int offset = 0);
+ void WriteTo(Stream stream, int offset = 0);
+ }
+}
diff --git a/BililiveRecorder.WPF/BililiveRecorder.WPF.csproj b/BililiveRecorder.WPF/BililiveRecorder.WPF.csproj
index 94cbf1e..8e92594 100644
--- a/BililiveRecorder.WPF/BililiveRecorder.WPF.csproj
+++ b/BililiveRecorder.WPF/BililiveRecorder.WPF.csproj
@@ -75,6 +75,9 @@
false
+
+ ..\packages\Autofac.4.8.1\lib\net45\Autofac.dll
+
..\packages\WindowsAPICodePack-Core.1.1.2\lib\Microsoft.WindowsAPICodePack.dll
diff --git a/BililiveRecorder.WPF/packages.config b/BililiveRecorder.WPF/packages.config
index 2f4c6bc..3d1c844 100644
--- a/BililiveRecorder.WPF/packages.config
+++ b/BililiveRecorder.WPF/packages.config
@@ -1,5 +1,6 @@
+