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}