diff --git a/src/JT1078.Flv.Test/FlvEncoderTest.cs b/src/JT1078.Flv.Test/FlvEncoderTest.cs
index 8a8b707..42d085a 100644
--- a/src/JT1078.Flv.Test/FlvEncoderTest.cs
+++ b/src/JT1078.Flv.Test/FlvEncoderTest.cs
@@ -17,7 +17,7 @@ namespace JT1078.Flv.Test
public class FlvEncoderTest
{
[Fact]
- public void FlvEncoder_Test_1()
+ public void 测试第一帧的数据()
{
JT1078Package Package = null;
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_1.txt"));
@@ -42,11 +42,14 @@ namespace JT1078.Flv.Test
{
File.Delete(filepath);
}
- File.WriteAllBytes(filepath, contents);
+ FileStream fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
+ fileStream.Write(FlvEncoder.VideoFlvHeaderBuffer);
+ fileStream.Write(contents);
+ fileStream.Close();
}
[Fact]
- public void FlvEncoder_Test_2()
+ public void 测试前几帧的数据()
{
FileStream fileStream=null;
try
@@ -78,6 +81,7 @@ namespace JT1078.Flv.Test
File.Delete(filepath);
}
fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
+ fileStream.Write(FlvEncoder.VideoFlvHeaderBuffer);
var totalPage = (h264NALULs.Count + 10 - 1) / 10;
for(var i=0;i< totalPage; i++)
{
@@ -100,7 +104,7 @@ namespace JT1078.Flv.Test
}
[Fact]
- public void FlvEncoder_Test_3()
+ public void 测试可以播放的Flv1()
{
FileStream fileStream = null;
Flv.H264.H264Decoder decoder = new Flv.H264.H264Decoder();
@@ -134,6 +138,7 @@ namespace JT1078.Flv.Test
}
fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
+ fileStream.Write(FlvEncoder.VideoFlvHeaderBuffer);
var totalPage = (h264NALULs.Count + 10 - 1) / 10;
for (var i = 0; i < totalPage; i++)
{
@@ -156,7 +161,7 @@ namespace JT1078.Flv.Test
}
[Fact]
- public void FlvEncoder_Test_4()
+ public void 测试可以播放的Flv2()
{
FileStream fileStream = null;
Flv.H264.H264Decoder decoder = new Flv.H264.H264Decoder();
@@ -189,7 +194,8 @@ namespace JT1078.Flv.Test
}
}
- fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
+ fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
+ fileStream.Write(FlvEncoder.VideoFlvHeaderBuffer);
var totalPage = (h264NALULs.Count + 10 - 1) / 10;
for (var i = 0; i < totalPage; i++)
{
@@ -212,7 +218,7 @@ namespace JT1078.Flv.Test
}
[Fact]
- public void FlvEncoder_Test_5()
+ public void 测试主次码流切换()
{
FileStream fileStream = null;
Flv.H264.H264Decoder decoder = new Flv.H264.H264Decoder();
diff --git a/src/JT1078.Flv/FlvEncoder.cs b/src/JT1078.Flv/FlvEncoder.cs
index b800dcb..1a9aa24 100644
--- a/src/JT1078.Flv/FlvEncoder.cs
+++ b/src/JT1078.Flv/FlvEncoder.cs
@@ -19,6 +19,9 @@ namespace JT1078.Flv
{
public class FlvEncoder
{
+ ///
+ /// Flv固定头部数据
+ ///
public static readonly byte[] VideoFlvHeaderBuffer;
private static readonly Flv.H264.H264Decoder H264Decoder;
private static readonly ConcurrentDictionary VideoSPSDict;
@@ -42,7 +45,7 @@ namespace JT1078.Flv
{
logger = loggerFactory.CreateLogger("FlvEncoder");
}
- public byte[] CreateScriptTagFrame(int width, int height, double frameRate = 25d)
+ internal byte[] CreateScriptTagFrame(int width, int height, double frameRate = 25d)
{
byte[] buffer = FlvArrayPool.Rent(1024);
try
@@ -90,7 +93,7 @@ namespace JT1078.Flv
FlvArrayPool.Return(buffer);
}
}
- public byte[] CreateVideoTag0Frame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo)
+ internal byte[] CreateVideoTag0Frame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo)
{
byte[] buffer = FlvArrayPool.Rent(2048);
try
@@ -125,7 +128,7 @@ namespace JT1078.Flv
FlvArrayPool.Return(buffer);
}
}
- public byte[] CreateSecondVideoTag0Frame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo)
+ internal byte[] CreateSecondVideoTag0Frame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo)
{
byte[] buffer = FlvArrayPool.Rent(2048);
try
@@ -160,7 +163,7 @@ namespace JT1078.Flv
FlvArrayPool.Return(buffer);
}
}
- public byte[] CreateVideoTagOtherFrame(FlvFrameInfo flvFrameInfo, H264NALU nALU, H264NALU sei)
+ internal byte[] CreateVideoTagOtherFrame(FlvFrameInfo flvFrameInfo, H264NALU nALU, H264NALU sei)
{
byte[] buffer = FlvArrayPool.Rent(65535);
try
@@ -334,7 +337,7 @@ namespace JT1078.Flv
FlvArrayPool.Return(buffer);
}
}
- public (byte[] Buffer, uint PreviousTagSize) CreateFirstFlvKeyFrame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo)
+ internal (byte[] Buffer, uint PreviousTagSize) CreateFirstFlvKeyFrame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo)
{
byte[] buffer = FlvArrayPool.Rent(65535);
try
@@ -358,7 +361,7 @@ namespace JT1078.Flv
FlvArrayPool.Return(buffer);
}
}
- public (byte[] Buffer,uint PreviousTagSize) CreateSecondFlvKeyFrame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo, FlvFrameInfo flvFrameInfo)
+ internal (byte[] Buffer,uint PreviousTagSize) CreateSecondFlvKeyFrame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo, FlvFrameInfo flvFrameInfo)
{
byte[] buffer = FlvArrayPool.Rent(65535);
try
@@ -384,17 +387,29 @@ namespace JT1078.Flv
FlvArrayPool.Return(buffer);
}
}
+ ///
+ ///
+ ///
+ /// 完整的1078包
+ /// 默认65535
+ ///
public byte[] CreateFlvFrame(JT1078Package package,int minimumLength = 65535)
{
var nalus = H264Decoder.ParseNALU(package);
if (nalus == null || nalus.Count <= 0) return default;
return CreateFlvFrame(nalus, minimumLength);
}
- public byte[] GetFirstFlvFrame(string key,byte[] bufferFlvFrame)
+ ///
+ ///
+ ///
+ /// 设备号+通道号(1111111_1)
+ /// 当前接收到的flv数据
+ ///
+ public byte[] GetFirstFlvFrame(string key,byte[] currentBufferFlvFrame)
{
if (FirstFlvFrameCache.TryGetValue(key, out var firstBuffer))
{
- var length = firstBuffer.Buffer.Length + bufferFlvFrame.Length + VideoFlvHeaderBuffer.Length;
+ var length = firstBuffer.Buffer.Length + currentBufferFlvFrame.Length + VideoFlvHeaderBuffer.Length;
byte[] buffer = FlvArrayPool.Rent(length);
try
{
@@ -406,16 +421,16 @@ namespace JT1078.Flv
BinaryPrimitives.WriteUInt32BigEndian(firstBuffer.Buffer, 0);
firstBuffer.Buffer.CopyTo(tmp.Slice(VideoFlvHeaderBuffer.Length));
//新用户进来需要替换为上一包的PreviousTagSize
- BinaryPrimitives.WriteUInt32BigEndian(bufferFlvFrame, firstBuffer.PreviousTagSize);
- bufferFlvFrame.CopyTo(tmp.Slice(VideoFlvHeaderBuffer.Length + firstBuffer.Buffer.Length));
+ BinaryPrimitives.WriteUInt32BigEndian(currentBufferFlvFrame, firstBuffer.PreviousTagSize);
+ currentBufferFlvFrame.CopyTo(tmp.Slice(VideoFlvHeaderBuffer.Length + firstBuffer.Buffer.Length));
return tmp.Slice(0, length).ToArray();
}
else
{
firstBuffer.Buffer.CopyTo(tmp.Slice(VideoFlvHeaderBuffer.Length));
//新用户进来需要替换为首包的PreviousTagSize
- BinaryPrimitives.WriteUInt32BigEndian(bufferFlvFrame, firstBuffer.PreviousTagSize);
- bufferFlvFrame.CopyTo(tmp.Slice(VideoFlvHeaderBuffer.Length + firstBuffer.Buffer.Length));
+ BinaryPrimitives.WriteUInt32BigEndian(currentBufferFlvFrame, firstBuffer.PreviousTagSize);
+ currentBufferFlvFrame.CopyTo(tmp.Slice(VideoFlvHeaderBuffer.Length + firstBuffer.Buffer.Length));
return tmp.Slice(0, length).ToArray();
}
}
@@ -428,7 +443,7 @@ namespace JT1078.Flv
}
}
- public class FlvFrameInfo
+ internal class FlvFrameInfo
{
public uint PreviousTagSize { get; set; }
public ulong Timestamp { get; set; }
diff --git a/src/JT1078.Flv/JT1078.Flv.csproj b/src/JT1078.Flv/JT1078.Flv.csproj
index bf6e962..0d3ae5f 100644
--- a/src/JT1078.Flv/JT1078.Flv.csproj
+++ b/src/JT1078.Flv/JT1078.Flv.csproj
@@ -14,12 +14,20 @@
https://github.com/SmallChi/JT1078/blob/master/LICENSE
https://github.com/SmallChi/JT1078/blob/master/LICENSE
false
- 1.0.0-preview1
+ 1.0.0-preview2
false
true
LICENSE
+
+ JT1078.Flv.xml
+
+
+
+ JT1078.Flv.xml
+
+
diff --git a/src/JT1078.Flv/JT1078.Flv.xml b/src/JT1078.Flv/JT1078.Flv.xml
new file mode 100644
index 0000000..5ebe50b
--- /dev/null
+++ b/src/JT1078.Flv/JT1078.Flv.xml
@@ -0,0 +1,203 @@
+
+
+
+ JT1078.Flv
+
+
+
+
+
+
+
+
+
+ 00010000
+
+
+
+
+ 00100000
+
+
+
+
+ 00110000
+
+
+
+
+ 01000000
+
+
+
+
+ 01010000
+
+
+
+
+
+ ref:"www.codeproject.com/tips/447938/high-performance-csharp-byte-array-to-hex-string-t"
+
+
+
+
+ 16进制字符串转16进制数组
+
+
+
+
+
+
+
+ Flv固定头部数据
+
+
+
+
+
+
+ 完整的1078包
+ 默认65535
+
+
+
+
+
+
+ 设备号+通道号(1111111_1)
+ 当前接收到的flv数据
+
+
+
+
+ Tag Data部分大小
+ 3个字节
+
+
+
+
+ Tag时间戳
+ 3个字节
+
+
+
+
+ stream id 总是0
+ 3个字节
+
+
+
+
+ 根据tag类型
+
+
+
+
+ 根据tag类型
+
+
+
+
+
+
+
+
+
+
+
+
+ Expunge any "Emulation Prevention" bytes from a "Raw Byte Sequence Payload"
+
+ 防止竞争插入0x03
+
+
+
+
+
+
+ 终端设备SIM卡号
+ BCD[6]
+
+
+
+
+ 逻辑通道号
+
+
+
+
+ 数据类型
+
+
+
+
+ 该帧与上一个关键帧之间的时间间隔,单位毫秒(ms),
+ 当数据类型为非视频帧时,则没有该字段
+
+
+
+
+ 该帧与上一个帧之间的时间间隔,单位毫秒(ms),
+ 当数据类型为非视频帧时,则没有该字段
+
+
+
+
+ 时间戳
+ 标识此RTP数据包当前帧的相对时间,单位毫秒(ms)。
+ 当数据类型为01000时,则没有该字段
+
+
+
+
+ 数据体
+
+
+
+
+ Exp-Golomb指数哥伦布编码
+
+
+
+
+ Advance the ExpGolomb decoder past a scaling list.The scaling
+ list is optionally transmitted as part of a sequence parameter
+ set and is not relevant to transmuxing.
+ @param count { number}
+ the number of entries in this scaling list
+ @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
+
+
+
+
+
+ AMF3数据类型
+
+
+
+
+ 元素个数
+
+
+
+
+
+
+
+
+
+
+ 高4位
+ 1: keyframe(for AVC, a seekable frame) —— 即H.264的IDR帧;
+ 2: inter frame(for AVC, a non- seekable frame) —— H.264的普通I帧;
+
+
+
+
+ 第四位
+ 当 CodecID 为 7 时,VideoData 为 AVCVIDEOPACKE,也即 H.264媒体数据
+
+
+
+