diff --git a/doc/ffmpeginfo.txt b/doc/ffmpeginfo.txt
new file mode 100644
index 0000000..8a650d3
--- /dev/null
+++ b/doc/ffmpeginfo.txt
@@ -0,0 +1 @@
+ffmpeg -i demo.mp4 -c copy -f flv -vcodec h264 -acodec aac demo_flv.flv
\ No newline at end of file
diff --git a/doc/tools/FlvAnalyzer.exe b/doc/tools/FlvAnalyzer.exe
new file mode 100644
index 0000000..daf350c
Binary files /dev/null and b/doc/tools/FlvAnalyzer.exe differ
diff --git a/doc/tools/FlvAnalyzer.zip b/doc/tools/FlvAnalyzer.zip
new file mode 100644
index 0000000..954f7b7
Binary files /dev/null and b/doc/tools/FlvAnalyzer.zip differ
diff --git a/doc/video/demo.flv b/doc/video/demo.flv
new file mode 100644
index 0000000..7291275
Binary files /dev/null and b/doc/video/demo.flv differ
diff --git a/doc/video/demo.mp4 b/doc/video/demo.mp4
new file mode 100644
index 0000000..a37eb9c
Binary files /dev/null and b/doc/video/demo.mp4 differ
diff --git a/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj b/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj
new file mode 100644
index 0000000..baad934
--- /dev/null
+++ b/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj
@@ -0,0 +1,20 @@
+
+
+
+ netcoreapp3.0
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/JT1078.Flv.Test/Metadata/Amf3MetadataTest.cs b/src/JT1078.Flv.Test/Metadata/Amf3MetadataTest.cs
new file mode 100644
index 0000000..f7643ee
--- /dev/null
+++ b/src/JT1078.Flv.Test/Metadata/Amf3MetadataTest.cs
@@ -0,0 +1,29 @@
+using JT1078.Flv.Metadata;
+using JT1078.Flv.Extensions;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Xunit;
+
+namespace JT1078.Flv.Test.Metadata
+{
+ public class Amf3MetadataTest
+ {
+ [Fact]
+ public void Amf3Metadata_Duration_Test_1_1()
+ {
+ Amf3Metadata_Duration amf3Metadata = new Amf3Metadata_Duration();
+ amf3Metadata.Value = 7.22100;
+ var hex=amf3Metadata.ToBuffer().ToArray().ToHexString();
+ Assert.Equal("00086475726174696F6E00401CE24DD2F1A9FC", hex);
+ }
+
+ [Fact]
+ public void Test1()
+ {
+ byte[] d1 = new byte[] { 0xFC, 0xA9, 0xF1, 0xD2, 0x4D, 0xE2, 0x1c, 0x40 };
+ var buffer = BitConverter.GetBytes(7.22100);
+ //flv需要倒序的
+ }
+ }
+}
diff --git a/src/JT1078.Flv/Enums/AVCPacketType.cs b/src/JT1078.Flv/Enums/AVCPacketType.cs
index 9d5b557..86744cd 100644
--- a/src/JT1078.Flv/Enums/AVCPacketType.cs
+++ b/src/JT1078.Flv/Enums/AVCPacketType.cs
@@ -4,9 +4,9 @@ using System.Text;
namespace JT1078.Flv.Enums
{
- public enum AvcPacketType
+ public enum AvcPacketType:byte
{
- SequenceHeader=1,
+ SequenceHeader = 0,
Raw,
AVCEndSequence
}
diff --git a/src/JT1078.Flv/Enums/Amf3Type.cs b/src/JT1078.Flv/Enums/Amf3Type.cs
new file mode 100644
index 0000000..4b0b2ca
--- /dev/null
+++ b/src/JT1078.Flv/Enums/Amf3Type.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT1078.Flv.Enums
+{
+ public enum Amf3Type : byte
+ {
+ Undefined,
+ Null,
+ False,
+ True,
+ Integer,
+ Double,
+ String,
+ XmlDocument,
+ Date,
+ Array,
+ Object,
+ Xml,
+ ByteArray,
+ VectorInt,
+ VectorUInt,
+ VectorDouble,
+ VectorObject,
+ Dictionary
+ }
+}
diff --git a/src/JT1078.Flv/Enums/CodecId.cs b/src/JT1078.Flv/Enums/CodecId.cs
index 4c9893f..eabd71a 100644
--- a/src/JT1078.Flv/Enums/CodecId.cs
+++ b/src/JT1078.Flv/Enums/CodecId.cs
@@ -12,6 +12,6 @@ namespace JT1078.Flv.Enums
Vp6,
Vp6WithAlpha,
ScreenVideo2,
- Avc
+ AvcVideoPacke
}
}
diff --git a/src/JT1078.Flv/Enums/FrameType.cs b/src/JT1078.Flv/Enums/FrameType.cs
index 4913d15..772fb5b 100644
--- a/src/JT1078.Flv/Enums/FrameType.cs
+++ b/src/JT1078.Flv/Enums/FrameType.cs
@@ -4,7 +4,7 @@ using System.Text;
namespace JT1078.Flv.Enums
{
- public enum FrameType
+ public enum FrameType:byte
{
KeyFrame = 1,
InterFrame,
diff --git a/src/JT1078.Flv/Extensions/Amf3Extensions.cs b/src/JT1078.Flv/Extensions/Amf3Extensions.cs
new file mode 100644
index 0000000..1928842
--- /dev/null
+++ b/src/JT1078.Flv/Extensions/Amf3Extensions.cs
@@ -0,0 +1,19 @@
+using JT1078.Flv.Metadata;
+using System;
+using System.Buffers.Binary;
+using System.Collections.Generic;
+using System.Text;
+using System.Linq;
+
+namespace JT1078.Flv.Extensions
+{
+ public static class Amf3Extensions
+ {
+ public static void WriteDouble(this IAmf3Metadata metadata, Span value)
+ {
+ var flvBuffer = BitConverter.GetBytes((double)metadata.Value).AsSpan();
+ flvBuffer.Reverse();
+ flvBuffer.CopyTo(value);
+ }
+ }
+}
diff --git a/src/JT1078.Flv/Extensions/HexExtensions.cs b/src/JT1078.Flv/Extensions/HexExtensions.cs
new file mode 100644
index 0000000..719d32f
--- /dev/null
+++ b/src/JT1078.Flv/Extensions/HexExtensions.cs
@@ -0,0 +1,129 @@
+using System;
+
+namespace JT1078.Flv.Extensions
+{
+ ///
+ ///
+ /// ref:"www.codeproject.com/tips/447938/high-performance-csharp-byte-array-to-hex-string-t"
+ ///
+ public static partial class HexExtensions
+ {
+ public static string ToHexString(this byte[] source)
+ {
+ return HexUtil.DoHexDump(source, 0, source.Length).ToUpper();
+ }
+
+ public static int WriteHexStringLittle(byte[] bytes, int offset, string data, int len)
+ {
+ if (data == null) data = "";
+ data = data.Replace(" ", "");
+ int startIndex = 0;
+ if (data.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
+ {
+ startIndex = 2;
+ }
+ int length = len;
+ if (length == -1)
+ {
+ length = (data.Length - startIndex) / 2;
+ }
+ int noOfZero = length * 2 + startIndex - data.Length;
+ if (noOfZero > 0)
+ {
+ data = data.Insert(startIndex, new string('0', noOfZero));
+ }
+ int byteIndex = 0;
+ while (startIndex < data.Length && byteIndex < length)
+ {
+ bytes[offset + byteIndex] = Convert.ToByte(data.Substring(startIndex, 2), 16);
+ startIndex += 2;
+ byteIndex++;
+ }
+ return length;
+ }
+
+ ///
+ /// 16进制字符串转16进制数组
+ ///
+ ///
+ ///
+ ///
+ public static byte[] ToHexBytes(this string hexString)
+ {
+ hexString = hexString.Replace(" ", "");
+ byte[] buf = new byte[hexString.Length / 2];
+ ReadOnlySpan readOnlySpan = hexString.AsSpan();
+ for (int i = 0; i < hexString.Length; i++)
+ {
+ if (i % 2 == 0)
+ {
+ buf[i / 2] = Convert.ToByte(readOnlySpan.Slice(i, 2).ToString(), 16);
+ }
+ }
+ return buf;
+ }
+
+ public static string ReadHexStringLittle(ReadOnlySpan read, ref int offset, int len)
+ {
+ ReadOnlySpan source = read.Slice(offset, len);
+ string hex = HexUtil.DoHexDump(read, offset, len);
+ offset += len;
+ return hex;
+ }
+
+ ///
+ /// Copyright (c) Microsoft. All rights reserved.
+ /// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ ///
+ ///
+
+ }
+
+ public static class HexUtil
+ {
+ static readonly char[] HexdumpTable = new char[256 * 4];
+ static HexUtil()
+ {
+ char[] digits = "0123456789ABCDEF".ToCharArray();
+ for (int i = 0; i < 256; i++)
+ {
+ HexdumpTable[i << 1] = digits[(int)((uint)i >> 4 & 0x0F)];
+ HexdumpTable[(i << 1) + 1] = digits[i & 0x0F];
+ }
+ }
+
+ public static string DoHexDump(ReadOnlySpan buffer, int fromIndex, int length)
+ {
+ if (length == 0)
+ {
+ return "";
+ }
+ int endIndex = fromIndex + length;
+ var buf = new char[length << 1];
+ int srcIdx = fromIndex;
+ int dstIdx = 0;
+ for (; srcIdx < endIndex; srcIdx++, dstIdx += 2)
+ {
+ Array.Copy(HexdumpTable, buffer[srcIdx] << 1, buf, dstIdx, 2);
+ }
+ return new string(buf);
+ }
+
+ public static string DoHexDump(byte[] array, int fromIndex, int length)
+ {
+ if (length == 0)
+ {
+ return "";
+ }
+ int endIndex = fromIndex + length;
+ var buf = new char[length << 1];
+ int srcIdx = fromIndex;
+ int dstIdx = 0;
+ for (; srcIdx < endIndex; srcIdx++, dstIdx += 2)
+ {
+ Array.Copy(HexdumpTable, (array[srcIdx] & 0xFF) << 1, buf, dstIdx, 2);
+ }
+ return new string(buf);
+ }
+ }
+}
diff --git a/src/JT1078.Flv/FlvBody.cs b/src/JT1078.Flv/FlvBody.cs
index 7084343..efc36a3 100644
--- a/src/JT1078.Flv/FlvBody.cs
+++ b/src/JT1078.Flv/FlvBody.cs
@@ -10,6 +10,6 @@ namespace JT1078.Flv
/// 前一个tag的长度
///
public uint PreviousTagSize { get; set; }
- public FlvTag Tag { get; set; }
+ public FlvTags Tag { get; set; }
}
}
diff --git a/src/JT1078.Flv/FlvTag.cs b/src/JT1078.Flv/FlvTags.cs
similarity index 64%
rename from src/JT1078.Flv/FlvTag.cs
rename to src/JT1078.Flv/FlvTags.cs
index e16d8ce..13376e1 100644
--- a/src/JT1078.Flv/FlvTag.cs
+++ b/src/JT1078.Flv/FlvTags.cs
@@ -1,8 +1,11 @@
-namespace JT1078.Flv
+using JT1078.Flv.Enums;
+using JT1078.Flv.Metadata;
+
+namespace JT1078.Flv
{
- public class FlvTag
+ public class FlvTags
{
- public byte Type { get; set; }
+ public TagType Type { get; set; }
///
/// Tag Data部分大小
/// 3个字节
@@ -22,6 +25,10 @@
///
/// 根据tag类型
///
- public byte[] TagData { get; set; }
+ public VideoTags VideoTagsData { get; set; }
+ ///
+ /// 根据tag类型
+ ///
+ public Amf3 DataTagsData { get; set; }
}
}
\ No newline at end of file
diff --git a/src/JT1078.Flv/JT1078.Flv.csproj b/src/JT1078.Flv/JT1078.Flv.csproj
index 474afd8..ba75397 100644
--- a/src/JT1078.Flv/JT1078.Flv.csproj
+++ b/src/JT1078.Flv/JT1078.Flv.csproj
@@ -1,10 +1,12 @@
- netstandard2.0
+ netstandard2.0;netstandard2.1
+ 8.0
-
+
+
diff --git a/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf0.cs b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf0.cs
index b942c05..e0d77b7 100644
--- a/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf0.cs
+++ b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf0.cs
@@ -7,13 +7,14 @@ namespace JT1078.Flv.MessagePack
ref partial struct FlvMessagePackWriter
{
private readonly static byte[] FixedAmf0Data = new byte[] { 0x6F, 0x6E, 0x4D, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61 };
- public void WriteAmf0()
+ public void WriteAmf1()
{
var span = writer.Free;
span[0] = 0x02;
span[1] = 0;
span[2] = 10;
FixedAmf0Data.CopyTo(span.Slice(3));
+ writer.Advance(13);
}
}
}
diff --git a/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf3.cs b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf3.cs
index bed39b2..0486a20 100644
--- a/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf3.cs
+++ b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf3.cs
@@ -1,4 +1,5 @@
-using System;
+using JT1078.Flv.Metadata;
+using System;
using System.Collections.Generic;
using System.Text;
@@ -6,7 +7,22 @@ namespace JT1078.Flv.MessagePack
{
ref partial struct FlvMessagePackWriter
{
-
-
+ public void WriteAmf3(Amf3 amf3)
+ {
+ WriteByte(amf3.DataType);
+ if(amf3.Amf3Metadatas!=null && amf3.Amf3Metadatas.Count > 0)
+ {
+ WriteInt32(amf3.Amf3Metadatas.Count);
+ foreach(var item in amf3.Amf3Metadatas)
+ {
+ //根据数据类型
+ WriteArray(item.ToBuffer());
+ }
+ }
+ else
+ {
+ WriteInt32(0);
+ }
+ }
}
}
diff --git a/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Flv.cs b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Flv.cs
index 8f74492..aac079f 100644
--- a/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Flv.cs
+++ b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Flv.cs
@@ -1,4 +1,5 @@
using JT1078.Flv.Enums;
+using JT1078.Flv.Metadata;
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
@@ -17,40 +18,84 @@ namespace JT1078.Flv.MessagePack
}
}
- public void WriteFlvTag(FlvTag tag)
+ public void WriteFlvTag(FlvTags tag)
{
- WriteByte(tag.Type);
+ WriteByte((byte)tag.Type);
Skip(3, out int DataSizePosition);
WriteUInt24(tag.Timestamp);
WriteByte(tag.TimestampExt);
WriteUInt24(tag.StreamId);
- switch ((TagType)tag.Type)
+ switch (tag.Type)
{
case TagType.Video:
-
+ //VideoTag
+ WriteVideoTags(tag.VideoTagsData);
break;
case TagType.ScriptData:
-
+ //DataTags
//flv Amf0
- WriteAmf0();
+ WriteAmf1();
//flv Amf3
+ WriteAmf3(tag.DataTagsData);
break;
case TagType.Audio:
+ //VIDEODATA
break;
}
- WriteInt32Return(GetCurrentPosition() - DataSizePosition - 3, DataSizePosition);
+ WriteInt24Return(GetCurrentPosition() - DataSizePosition - 3, DataSizePosition);
}
public void WriteUInt24(uint value)
{
- BinaryPrimitives.WriteUInt32BigEndian(writer.Free, value);
+ var span = writer.Free;
+ span[0] = (byte)(value >> 16);
+ span[1] = (byte)(value >> 8);
+ span[2] = (byte)value;
writer.Advance(3);
}
- public void WriteInt32Return(int value, int position)
+ public void WriteInt24Return(int value, int position)
+ {
+ var span = writer.Written.Slice(position, 3);
+ span[0] = (byte)(value >> 16);
+ span[1] = (byte)(value >> 8);
+ span[2] = (byte)value;
+ }
+
+ public void WriteVideoTags(VideoTags videoTags)
{
- BinaryPrimitives.WriteInt32BigEndian(writer.Written.Slice(position, 3), value);
+ WriteByte((byte)((byte)videoTags.FrameType | (byte)videoTags.CodecId));
+#warning 只处理H.264媒体数据
+ if (videoTags.CodecId== CodecId.AvcVideoPacke)
+ {
+ WriteAvcVideoPacke(videoTags.VideoData);
+ }
}
+ public void WriteAvcVideoPacke(AvcVideoPacke videoPacke)
+ {
+ WriteByte((byte)videoPacke.AvcPacketType);
+ if (videoPacke.AvcPacketType== AvcPacketType.SequenceHeader)
+ {
+ videoPacke.CompositionTime = 0;
+ WriteUInt24(videoPacke.CompositionTime);
+ //AVCDecoderConfigurationRecord
+#warning AVCDecoderConfigurationRecord
+ WriteArray(videoPacke.Data);
+ }
+ else if(videoPacke.AvcPacketType == AvcPacketType.Raw)
+ {
+ WriteUInt24(videoPacke.CompositionTime);
+#warning One or more NALUs
+ //One or more NALUs
+ WriteArray(videoPacke.Data);
+ }
+ else
+ {
+ videoPacke.CompositionTime = 0;
+ WriteUInt24(videoPacke.CompositionTime);
+ //Empty
+ }
+ }
}
}
diff --git a/src/JT1078.Flv/Metadata/Amf3.cs b/src/JT1078.Flv/Metadata/Amf3.cs
new file mode 100644
index 0000000..a622f58
--- /dev/null
+++ b/src/JT1078.Flv/Metadata/Amf3.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT1078.Flv.Metadata
+{
+ public class Amf3
+ {
+ ///
+ /// AMF3数据类型
+ ///
+ public byte DataType { get; set; } = 0x08;
+ ///
+ /// 元素个数
+ ///
+ public uint Count { get; set; }
+ public List Amf3Metadatas { get; set; }
+ }
+}
diff --git a/src/JT1078.Flv/Metadata/Amf3Metadata_Duration.cs b/src/JT1078.Flv/Metadata/Amf3Metadata_Duration.cs
new file mode 100644
index 0000000..c64841f
--- /dev/null
+++ b/src/JT1078.Flv/Metadata/Amf3Metadata_Duration.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Buffers.Binary;
+using JT1078.Flv.Extensions;
+
+namespace JT1078.Flv.Metadata
+{
+ public class Amf3Metadata_Duration : IAmf3Metadata
+ {
+ public ushort FieldNameLength { get; set; }
+ public string FieldName { get; set; } = "duration";
+ public byte DataType { get; set; } = 0x00;
+ public object Value { get; set; }
+
+ public ReadOnlySpan ToBuffer()
+ {
+ Span tmp = new byte[2+8+1+8];
+ var b1 = Encoding.ASCII.GetBytes(FieldName);
+ BinaryPrimitives.WriteUInt16BigEndian(tmp,(ushort)b1.Length);
+ b1.CopyTo(tmp.Slice(2));
+ tmp[10] = DataType;
+ this.WriteDouble(tmp.Slice(11));
+ return tmp;
+ }
+ }
+}
diff --git a/src/JT1078.Flv/Metadata/Amf3Metadata_FileSize.cs b/src/JT1078.Flv/Metadata/Amf3Metadata_FileSize.cs
new file mode 100644
index 0000000..4a94386
--- /dev/null
+++ b/src/JT1078.Flv/Metadata/Amf3Metadata_FileSize.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Buffers.Binary;
+
+namespace JT1078.Flv.Metadata
+{
+ public class Amf3Metadata_FileSize : IAmf3Metadata
+ {
+ public ushort FieldNameLength { get; set; }
+ public string FieldName { get; set; } = "filesize";
+ public byte DataType { get; set; } = 0x00;
+ public object Value { get; set; }
+
+ public ReadOnlySpan ToBuffer()
+ {
+ Span tmp = new byte[2+8+1+8];
+ var b1 = Encoding.ASCII.GetBytes(FieldName);
+ BinaryPrimitives.WriteUInt16BigEndian(tmp, (ushort)b1.Length);
+ b1.CopyTo(tmp.Slice(4));
+ tmp[11] = DataType;
+ BinaryPrimitives.WriteInt64BigEndian(tmp.Slice(12), (long)Value);
+ return tmp;
+ }
+ }
+}
diff --git a/src/JT1078.Flv/Metadata/Amf3Metadata_FrameRate.cs b/src/JT1078.Flv/Metadata/Amf3Metadata_FrameRate.cs
new file mode 100644
index 0000000..baf88bc
--- /dev/null
+++ b/src/JT1078.Flv/Metadata/Amf3Metadata_FrameRate.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Buffers.Binary;
+
+namespace JT1078.Flv.Metadata
+{
+ public class Amf3Metadata_FrameRate : IAmf3Metadata
+ {
+ public ushort FieldNameLength { get; set; }
+ public string FieldName { get; set; } = "framerate";
+ public byte DataType { get; set; } = 0x00;
+ public object Value { get; set; }
+
+ public ReadOnlySpan ToBuffer()
+ {
+ Span tmp = new byte[4+9+1+8];
+ var b1 = Encoding.ASCII.GetBytes(FieldName);
+ BinaryPrimitives.WriteUInt16BigEndian(tmp, (ushort)b1.Length);
+ b1.CopyTo(tmp.Slice(4));
+ tmp[11] = DataType;
+ BinaryPrimitives.WriteInt64BigEndian(tmp.Slice(12), (long)Value);
+ return tmp;
+ }
+ }
+}
diff --git a/src/JT1078.Flv/Metadata/Amf3Metadata_Height.cs b/src/JT1078.Flv/Metadata/Amf3Metadata_Height.cs
new file mode 100644
index 0000000..1f46f04
--- /dev/null
+++ b/src/JT1078.Flv/Metadata/Amf3Metadata_Height.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Buffers.Binary;
+
+namespace JT1078.Flv.Metadata
+{
+ public class Amf3Metadata_Height : IAmf3Metadata
+ {
+ public ushort FieldNameLength { get; set; }
+ public string FieldName { get; set; } = "height";
+ public byte DataType { get; set; } = 0x00;
+ public object Value { get; set; }
+
+ public ReadOnlySpan ToBuffer()
+ {
+ Span tmp = new byte[4+6+1+8];
+ var b1 = Encoding.ASCII.GetBytes(FieldName);
+ BinaryPrimitives.WriteUInt16BigEndian(tmp, (ushort)b1.Length);
+ b1.CopyTo(tmp.Slice(3));
+ tmp[11] = DataType;
+ BinaryPrimitives.WriteInt64BigEndian(tmp.Slice(12), (long)Value);
+ return tmp;
+ }
+ }
+}
diff --git a/src/JT1078.Flv/Metadata/Amf3Metadata_VideoCodecId.cs b/src/JT1078.Flv/Metadata/Amf3Metadata_VideoCodecId.cs
new file mode 100644
index 0000000..a44a25b
--- /dev/null
+++ b/src/JT1078.Flv/Metadata/Amf3Metadata_VideoCodecId.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Buffers.Binary;
+
+namespace JT1078.Flv.Metadata
+{
+ public class Amf3Metadata_VideoCodecId : IAmf3Metadata
+ {
+ public ushort FieldNameLength { get; set; }
+ public string FieldName { get; set; } = "videocodecid";
+ public byte DataType { get; set; } = 0x00;
+ public object Value { get; set; }
+
+ public ReadOnlySpan ToBuffer()
+ {
+ Span tmp = new byte[4+12+1+8];
+ var b1 = Encoding.ASCII.GetBytes(FieldName);
+ BinaryPrimitives.WriteUInt16BigEndian(tmp, (ushort)b1.Length);
+ b1.CopyTo(tmp.Slice(4));
+ tmp[11] = DataType;
+ BinaryPrimitives.WriteInt64BigEndian(tmp.Slice(12), (long)Value);
+ return tmp;
+ }
+ }
+}
diff --git a/src/JT1078.Flv/Metadata/Amf3Metadata_VideoDataRate.cs b/src/JT1078.Flv/Metadata/Amf3Metadata_VideoDataRate.cs
new file mode 100644
index 0000000..f62a900
--- /dev/null
+++ b/src/JT1078.Flv/Metadata/Amf3Metadata_VideoDataRate.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Buffers.Binary;
+
+namespace JT1078.Flv.Metadata
+{
+ public class Amf3Metadata_VideoDataRate : IAmf3Metadata
+ {
+ public ushort FieldNameLength { get; set; }
+ public string FieldName { get; set; } = "videodatarate";
+ public byte DataType { get; set; } = 0x00;
+ public object Value { get; set; }
+
+ public ReadOnlySpan ToBuffer()
+ {
+ Span tmp = new byte[4+13+1+8];
+ var b1 = Encoding.ASCII.GetBytes(FieldName);
+ BinaryPrimitives.WriteUInt16BigEndian(tmp, (ushort)b1.Length);
+ b1.CopyTo(tmp.Slice(4));
+ tmp[11] = DataType;
+ BinaryPrimitives.WriteInt64BigEndian(tmp.Slice(12), (long)Value);
+ return tmp;
+ }
+ }
+}
diff --git a/src/JT1078.Flv/Metadata/Amf3Metadata_Width.cs b/src/JT1078.Flv/Metadata/Amf3Metadata_Width.cs
new file mode 100644
index 0000000..e133ff8
--- /dev/null
+++ b/src/JT1078.Flv/Metadata/Amf3Metadata_Width.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Buffers.Binary;
+
+namespace JT1078.Flv.Metadata
+{
+ public class Amf3Metadata_Width : IAmf3Metadata
+ {
+ public ushort FieldNameLength { get; set; }
+ public string FieldName { get; set; } = "width";
+ public byte DataType { get; set; } = 0x00;
+ public object Value { get; set; }
+
+ public ReadOnlySpan ToBuffer()
+ {
+ Span tmp = new byte[4+5+1+8];
+ var b1 = Encoding.ASCII.GetBytes(FieldName);
+ BinaryPrimitives.WriteUInt16BigEndian(tmp, (ushort)b1.Length);
+ b1.CopyTo(tmp.Slice(3));
+ tmp[11] = DataType;
+ BinaryPrimitives.WriteInt64BigEndian(tmp.Slice(12), (long)Value);
+ return tmp;
+ }
+ }
+}
diff --git a/src/JT1078.Flv/Metadata/IAmf3Metadata.cs b/src/JT1078.Flv/Metadata/IAmf3Metadata.cs
new file mode 100644
index 0000000..9b6ddab
--- /dev/null
+++ b/src/JT1078.Flv/Metadata/IAmf3Metadata.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT1078.Flv.Metadata
+{
+ public interface IAmf3Metadata
+ {
+ ushort FieldNameLength { get; set; }
+ string FieldName { get; set; }
+ byte DataType { get; set; }
+ object Value { get; set; }
+ ReadOnlySpan ToBuffer();
+ }
+}
diff --git a/src/JT1078.Flv/Metadata/VideoTag.cs b/src/JT1078.Flv/Metadata/VideoTags.cs
similarity index 78%
rename from src/JT1078.Flv/Metadata/VideoTag.cs
rename to src/JT1078.Flv/Metadata/VideoTags.cs
index 2d45d39..db921e6 100644
--- a/src/JT1078.Flv/Metadata/VideoTag.cs
+++ b/src/JT1078.Flv/Metadata/VideoTags.cs
@@ -5,7 +5,7 @@ using System.Text;
namespace JT1078.Flv.Metadata
{
- public class VideoTag
+ public class VideoTags
{
///
/// 1: keyframe(for AVC, a seekable frame) —— 即H.264的IDR帧;
@@ -15,7 +15,7 @@ namespace JT1078.Flv.Metadata
///
/// 当 CodecID 为 7 时,VideoData 为 AVCVIDEOPACKE,也即 H.264媒体数据
///
- public CodecId CodecId { get; set; }
- public byte[] VideoData { get; set; }
+ public CodecId CodecId { get; set; } = CodecId.AvcVideoPacke;
+ public AvcVideoPacke VideoData { get; set; }
}
}
diff --git a/src/JT1078.Protocol/JT1078.Protocol.csproj b/src/JT1078.Protocol/JT1078.Protocol.csproj
index c89122c..7edd394 100644
--- a/src/JT1078.Protocol/JT1078.Protocol.csproj
+++ b/src/JT1078.Protocol/JT1078.Protocol.csproj
@@ -1,8 +1,8 @@
- netstandard2.0
- 7.3
+ netstandard2.0;netstandard2.1
+ 8.0
Copyright 2019.
SmallChi(Koike)
JT1078
@@ -14,16 +14,17 @@
https://github.com/SmallChi/JT1078/blob/master/LICENSE
https://github.com/SmallChi/JT1078/blob/master/LICENSE
false
- 1.0.0
+ 1.0.1
false
true
LICENSE
-
+
+
-
+
True
diff --git a/src/JT1078.sln b/src/JT1078.sln
index 7aebf90..3e17536 100644
--- a/src/JT1078.sln
+++ b/src/JT1078.sln
@@ -27,7 +27,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Protocol.Extensions.WebApiTest", "JT808.Protocol.Extensions.WebApiTest\JT808.Protocol.Extensions.WebApiTest.csproj", "{9DB37370-AC73-434B-9CE2-6659321858C8}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT1078.Flv", "JT1078.Flv\JT1078.Flv.csproj", "{33E54FFC-7D91-42E5-9DC1-853738AB8980}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.Flv", "JT1078.Flv\JT1078.Flv.csproj", "{33E54FFC-7D91-42E5-9DC1-853738AB8980}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT1078.Flv.Test", "JT1078.Flv.Test\JT1078.Flv.Test.csproj", "{D13FE092-1D11-4545-A322-9F06BCDAC0FD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -71,6 +73,10 @@ Global
{33E54FFC-7D91-42E5-9DC1-853738AB8980}.Debug|Any CPU.Build.0 = Debug|Any CPU
{33E54FFC-7D91-42E5-9DC1-853738AB8980}.Release|Any CPU.ActiveCfg = Release|Any CPU
{33E54FFC-7D91-42E5-9DC1-853738AB8980}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D13FE092-1D11-4545-A322-9F06BCDAC0FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D13FE092-1D11-4545-A322-9F06BCDAC0FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D13FE092-1D11-4545-A322-9F06BCDAC0FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D13FE092-1D11-4545-A322-9F06BCDAC0FD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -80,6 +86,7 @@ Global
{E9FF2716-EF30-4180-879B-E8AB979ACFF3} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
{9ADD82F9-E0B2-4263-8573-151F673BB33F} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
{9DB37370-AC73-434B-9CE2-6659321858C8} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
+ {D13FE092-1D11-4545-A322-9F06BCDAC0FD} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FAE1656D-226F-4B4B-8C33-615D7E632B26}