From 1c0c850ac29d79a4d49a850b968d3551041561c1 Mon Sep 17 00:00:00 2001 From: "SmallChi(Koike)" <564952747@qq.com> Date: Mon, 23 Sep 2019 23:22:44 +0800 Subject: [PATCH] =?UTF-8?q?flv=E5=8C=85=E8=A3=85=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/JT1078.Flv/Amf/Amf0.cs | 21 ------- src/JT1078.Flv/Buffers/FlvBufferWriter.cs | 24 ++++++++ src/JT1078.Flv/Enums/AVCPacketType.cs | 13 ++++ src/JT1078.Flv/Enums/AacPacketType.cs | 12 ---- src/JT1078.Flv/Enums/CodecId.cs | 2 +- src/JT1078.Flv/Enums/FrameType.cs | 2 +- src/JT1078.Flv/Enums/TagType.cs | 13 ++++ src/JT1078.Flv/FlvMuxer.cs | 27 ++++++++- src/JT1078.Flv/FlvTag.cs | 18 +++++- src/JT1078.Flv/FlvTagHeader.cs | 27 --------- .../MessagePack/FlvMessagePackWriter.cs | 60 +++++++++++++++++++ .../MessagePack/FlvMessagePackWriter_Amf0.cs | 19 ++++++ .../FlvMessagePackWriter_Amf3.cs} | 5 +- .../MessagePack/FlvMessagePackWriter_Flv.cs | 56 +++++++++++++++++ src/JT1078.Flv/Metadata/AvcVideoPacke.cs | 16 +++++ src/JT1078.Flv/Metadata/VideoTag.cs | 21 +++++++ 16 files changed, 268 insertions(+), 68 deletions(-) delete mode 100644 src/JT1078.Flv/Amf/Amf0.cs create mode 100644 src/JT1078.Flv/Buffers/FlvBufferWriter.cs create mode 100644 src/JT1078.Flv/Enums/AVCPacketType.cs delete mode 100644 src/JT1078.Flv/Enums/AacPacketType.cs create mode 100644 src/JT1078.Flv/Enums/TagType.cs delete mode 100644 src/JT1078.Flv/FlvTagHeader.cs create mode 100644 src/JT1078.Flv/MessagePack/FlvMessagePackWriter.cs create mode 100644 src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf0.cs rename src/JT1078.Flv/{Amf/Amf3.cs => MessagePack/FlvMessagePackWriter_Amf3.cs} (52%) create mode 100644 src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Flv.cs create mode 100644 src/JT1078.Flv/Metadata/AvcVideoPacke.cs create mode 100644 src/JT1078.Flv/Metadata/VideoTag.cs diff --git a/src/JT1078.Flv/Amf/Amf0.cs b/src/JT1078.Flv/Amf/Amf0.cs deleted file mode 100644 index 60c4d16..0000000 --- a/src/JT1078.Flv/Amf/Amf0.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT1078.Flv -{ - public static class Amf0 - { - public readonly static byte[] Buffer; - - public readonly static byte[] FixedData = new byte[] { 0x6F, 0x6E, 0x4D, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61 }; - static Amf0() - { - Buffer = new byte[13]; - Buffer[0] = 0x02; - Buffer[1] = 0; - Buffer[2] = 10; - Array.Copy(FixedData, 0, Buffer, 3, 10); - } - } -} diff --git a/src/JT1078.Flv/Buffers/FlvBufferWriter.cs b/src/JT1078.Flv/Buffers/FlvBufferWriter.cs new file mode 100644 index 0000000..502339c --- /dev/null +++ b/src/JT1078.Flv/Buffers/FlvBufferWriter.cs @@ -0,0 +1,24 @@ +using System; + +namespace JT1078.Flv +{ + /// + /// + /// + ref partial struct FlvBufferWriter + { + private Span _buffer; + public FlvBufferWriter(Span buffer) + { + _buffer = buffer; + WrittenCount = 0; + } + public Span Free => _buffer.Slice(WrittenCount); + public Span Written => _buffer.Slice(0, WrittenCount); + public int WrittenCount { get; private set; } + public void Advance(int count) + { + WrittenCount += count; + } + } +} diff --git a/src/JT1078.Flv/Enums/AVCPacketType.cs b/src/JT1078.Flv/Enums/AVCPacketType.cs new file mode 100644 index 0000000..9d5b557 --- /dev/null +++ b/src/JT1078.Flv/Enums/AVCPacketType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT1078.Flv.Enums +{ + public enum AvcPacketType + { + SequenceHeader=1, + Raw, + AVCEndSequence + } +} diff --git a/src/JT1078.Flv/Enums/AacPacketType.cs b/src/JT1078.Flv/Enums/AacPacketType.cs deleted file mode 100644 index ba928de..0000000 --- a/src/JT1078.Flv/Enums/AacPacketType.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT1078.Flv -{ - public enum AacPacketType - { - SequenceHeader, - Raw - } -} diff --git a/src/JT1078.Flv/Enums/CodecId.cs b/src/JT1078.Flv/Enums/CodecId.cs index 2697103..4c9893f 100644 --- a/src/JT1078.Flv/Enums/CodecId.cs +++ b/src/JT1078.Flv/Enums/CodecId.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace JT1078.Flv +namespace JT1078.Flv.Enums { public enum CodecId { diff --git a/src/JT1078.Flv/Enums/FrameType.cs b/src/JT1078.Flv/Enums/FrameType.cs index a4cdd1b..4913d15 100644 --- a/src/JT1078.Flv/Enums/FrameType.cs +++ b/src/JT1078.Flv/Enums/FrameType.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace JT1078.Flv +namespace JT1078.Flv.Enums { public enum FrameType { diff --git a/src/JT1078.Flv/Enums/TagType.cs b/src/JT1078.Flv/Enums/TagType.cs new file mode 100644 index 0000000..d35626e --- /dev/null +++ b/src/JT1078.Flv/Enums/TagType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT1078.Flv.Enums +{ + public enum TagType:byte + { + Audio= 0x08, + Video= 0x09, + ScriptData= 0x12, + } +} diff --git a/src/JT1078.Flv/FlvMuxer.cs b/src/JT1078.Flv/FlvMuxer.cs index 034a9a0..a9b0589 100644 --- a/src/JT1078.Flv/FlvMuxer.cs +++ b/src/JT1078.Flv/FlvMuxer.cs @@ -1,4 +1,5 @@ -using System; +using JT1078.Flv.MessagePack; +using System; using System.Collections.Generic; using System.Text; @@ -7,9 +8,29 @@ namespace JT1078.Flv public class FlvMuxer { private readonly FlvHeader VideoFlvHeader = new FlvHeader(true, false); - public void FlvVideoMuxer() + public byte[] FlvFirstFrame() { - + byte[] buffer = FlvArrayPool.Rent(10240); + try + { + FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); + //flv header + flvMessagePackWriter.WriteArray(VideoFlvHeader.ToArray()); + //flv body + //flv body PreviousTagSize + flvMessagePackWriter.WriteUInt32(0); + //flv body tag + + //flv body tag header + + //flv body tag body + + return flvMessagePackWriter.FlushAndGetArray(); + } + finally + { + FlvArrayPool.Return(buffer); + } } } } diff --git a/src/JT1078.Flv/FlvTag.cs b/src/JT1078.Flv/FlvTag.cs index 64ad666..e16d8ce 100644 --- a/src/JT1078.Flv/FlvTag.cs +++ b/src/JT1078.Flv/FlvTag.cs @@ -2,7 +2,23 @@ { public class FlvTag { - public FlvTagHeader TagHeader { get; set; } + public byte Type { get; set; } + /// + /// Tag Data部分大小 + /// 3个字节 + /// + public uint DataSize { get; set; } + /// + /// Tag时间戳 + /// 3个字节 + /// + public uint Timestamp { get; set; } = 0; + public byte TimestampExt { get; set; } = 0; + /// + /// stream id 总是0 + /// 3个字节 + /// + public uint StreamId { get; set; } = 0; /// /// 根据tag类型 /// diff --git a/src/JT1078.Flv/FlvTagHeader.cs b/src/JT1078.Flv/FlvTagHeader.cs deleted file mode 100644 index d298727..0000000 --- a/src/JT1078.Flv/FlvTagHeader.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT1078.Flv -{ - public class FlvTagHeader - { - public byte Type { get; set; } - /// - /// Tag Data部分大小 - /// 3个字节 - /// - public uint DataSize { get; set; } - /// - /// Tag时间戳 - /// 3个字节 - /// - public uint Timestamp { get; set; } - public byte TimestampExt { get; set; } = 0; - /// - /// stream id 总是0 - /// 3个字节 - /// - public uint StreamId { get; set; } = 0; - } -} diff --git a/src/JT1078.Flv/MessagePack/FlvMessagePackWriter.cs b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter.cs new file mode 100644 index 0000000..72a6410 --- /dev/null +++ b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter.cs @@ -0,0 +1,60 @@ +using System; +using System.Buffers.Binary; + +namespace JT1078.Flv.MessagePack +{ + ref partial struct FlvMessagePackWriter + { + private FlvBufferWriter writer; + public FlvMessagePackWriter(Span buffer) + { + this.writer = new FlvBufferWriter(buffer); + } + public byte[] FlushAndGetArray() + { + return writer.Written.ToArray(); + } + public void WriteByte(byte value) + { + var span = writer.Free; + span[0] = value; + writer.Advance(1); + } + public void WriteUInt16(ushort value) + { + BinaryPrimitives.WriteUInt16BigEndian(writer.Free, value); + writer.Advance(2); + } + public void WriteInt32(int value) + { + BinaryPrimitives.WriteInt32BigEndian(writer.Free, value); + writer.Advance(4); + } + public void WriteUInt64(ulong value) + { + BinaryPrimitives.WriteUInt64BigEndian(writer.Free, value); + writer.Advance(8); + } + public void WriteUInt32(uint value) + { + BinaryPrimitives.WriteUInt32BigEndian(writer.Free, value); + writer.Advance(4); + } + public void WriteArray(ReadOnlySpan src) + { + src.CopyTo(writer.Free); + writer.Advance(src.Length); + } + public void Skip(int count, out int position) + { + position = writer.WrittenCount; + byte[] tmp = new byte[count]; + tmp.CopyTo(writer.Free); + writer.Advance(count); + } + public int GetCurrentPosition() + { + return writer.WrittenCount; + } + } +} diff --git a/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf0.cs b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf0.cs new file mode 100644 index 0000000..b942c05 --- /dev/null +++ b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf0.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +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() + { + var span = writer.Free; + span[0] = 0x02; + span[1] = 0; + span[2] = 10; + FixedAmf0Data.CopyTo(span.Slice(3)); + } + } +} diff --git a/src/JT1078.Flv/Amf/Amf3.cs b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf3.cs similarity index 52% rename from src/JT1078.Flv/Amf/Amf3.cs rename to src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf3.cs index 4d22c65..bed39b2 100644 --- a/src/JT1078.Flv/Amf/Amf3.cs +++ b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Amf3.cs @@ -2,10 +2,11 @@ using System.Collections.Generic; using System.Text; -namespace JT1078.Flv +namespace JT1078.Flv.MessagePack { - public static class Amf3 + ref partial struct FlvMessagePackWriter { + } } diff --git a/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Flv.cs b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Flv.cs new file mode 100644 index 0000000..8f74492 --- /dev/null +++ b/src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Flv.cs @@ -0,0 +1,56 @@ +using JT1078.Flv.Enums; +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Text; + +namespace JT1078.Flv.MessagePack +{ + ref partial struct FlvMessagePackWriter + { + public void WriteFlvBody(FlvBody body) + { + WriteUInt32(body.PreviousTagSize); + if (body.Tag != null) + { + WriteFlvTag(body.Tag); + } + } + + public void WriteFlvTag(FlvTag tag) + { + WriteByte(tag.Type); + Skip(3, out int DataSizePosition); + WriteUInt24(tag.Timestamp); + WriteByte(tag.TimestampExt); + WriteUInt24(tag.StreamId); + switch ((TagType)tag.Type) + { + case TagType.Video: + + break; + case TagType.ScriptData: + + //flv Amf0 + WriteAmf0(); + //flv Amf3 + break; + case TagType.Audio: + break; + } + WriteInt32Return(GetCurrentPosition() - DataSizePosition - 3, DataSizePosition); + } + + public void WriteUInt24(uint value) + { + BinaryPrimitives.WriteUInt32BigEndian(writer.Free, value); + writer.Advance(3); + } + + public void WriteInt32Return(int value, int position) + { + BinaryPrimitives.WriteInt32BigEndian(writer.Written.Slice(position, 3), value); + } + + } +} diff --git a/src/JT1078.Flv/Metadata/AvcVideoPacke.cs b/src/JT1078.Flv/Metadata/AvcVideoPacke.cs new file mode 100644 index 0000000..415e521 --- /dev/null +++ b/src/JT1078.Flv/Metadata/AvcVideoPacke.cs @@ -0,0 +1,16 @@ +using JT1078.Flv.Enums; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT1078.Flv.Metadata +{ + public class AvcVideoPacke + { + public AvcPacketType AvcPacketType { get; set; } + + public uint CompositionTime { get; set; } + + public byte[] Data { get; set; } + } +} diff --git a/src/JT1078.Flv/Metadata/VideoTag.cs b/src/JT1078.Flv/Metadata/VideoTag.cs new file mode 100644 index 0000000..2d45d39 --- /dev/null +++ b/src/JT1078.Flv/Metadata/VideoTag.cs @@ -0,0 +1,21 @@ +using JT1078.Flv.Enums; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT1078.Flv.Metadata +{ + public class VideoTag + { + /// + /// 1: keyframe(for AVC, a seekable frame) —— 即H.264的IDR帧; + /// 2: inter frame(for AVC, a non- seekable frame) —— H.264的普通I帧; + /// + public FrameType FrameType { get; set; } + /// + /// 当 CodecID 为 7 时,VideoData 为 AVCVIDEOPACKE,也即 H.264媒体数据 + /// + public CodecId CodecId { get; set; } + public byte[] VideoData { get; set; } + } +}