diff --git a/src/JT1078.Flv/FlvEncoder.cs b/src/JT1078.Flv/FlvEncoder.cs index 086bdcc..e24da09 100644 --- a/src/JT1078.Flv/FlvEncoder.cs +++ b/src/JT1078.Flv/FlvEncoder.cs @@ -45,175 +45,7 @@ namespace JT1078.Flv { logger = loggerFactory.CreateLogger("FlvEncoder"); } - internal byte[] CreateScriptTagFrame(int width, int height, double frameRate = 25d) - { - byte[] buffer = FlvArrayPool.Rent(1024); - try - { - FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); - //flv body script tag - //flv body tag header - FlvTags flvTags = new FlvTags(); - flvTags.Type = TagType.ScriptData; - flvTags.Timestamp = 0; - flvTags.TimestampExt = 0; - flvTags.StreamId = 0; - //flv body tag body - flvTags.DataTagsData = new Amf3(); - flvTags.DataTagsData.Amf3Metadatas = new List(); - flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_Duration - { - Value = 0d - }); - flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_VideoDataRate - { - Value = 0d - }); - flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_VideoCodecId - { - Value = 7d - }); - flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_FrameRate - { - Value = frameRate - }); - flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_Width - { - Value = width - }); - flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_Height - { - Value = height - }); - flvMessagePackWriter.WriteFlvTag(flvTags); - return flvMessagePackWriter.FlushAndGetArray(); - } - finally - { - FlvArrayPool.Return(buffer); - } - } - internal byte[] CreateVideoTag0Frame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo) - { - byte[] buffer = FlvArrayPool.Rent(2048); - try - { - FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); - //flv body video tag - //flv body tag header - FlvTags flvTags = new FlvTags(); - flvTags.Type = TagType.Video; - flvTags.Timestamp = 0; - flvTags.TimestampExt = 0; - flvTags.StreamId = 0; - //flv body tag body - flvTags.VideoTagsData = new VideoTags(); - flvTags.VideoTagsData.FrameType = FrameType.KeyFrame; - flvTags.VideoTagsData.VideoData = new AvcVideoPacke(); - flvTags.VideoTagsData.VideoData.AvcPacketType = AvcPacketType.SequenceHeader; - flvTags.VideoTagsData.VideoData.CompositionTime = 0; - AVCDecoderConfigurationRecord aVCDecoderConfigurationRecord = new AVCDecoderConfigurationRecord(); - aVCDecoderConfigurationRecord.AVCProfileIndication = spsInfo.profileIdc; - aVCDecoderConfigurationRecord.ProfileCompatibility = (byte)spsInfo.profileCompat; - aVCDecoderConfigurationRecord.AVCLevelIndication = spsInfo.levelIdc; - aVCDecoderConfigurationRecord.NumOfPictureParameterSets = 1; - aVCDecoderConfigurationRecord.PPSBuffer = ppsRawData; - aVCDecoderConfigurationRecord.SPSBuffer = spsRawData; - flvTags.VideoTagsData.VideoData.AVCDecoderConfiguration = aVCDecoderConfigurationRecord; - flvMessagePackWriter.WriteFlvTag(flvTags); - return flvMessagePackWriter.FlushAndGetArray(); - } - finally - { - FlvArrayPool.Return(buffer); - } - } - internal byte[] CreateSecondVideoTag0Frame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo) - { - byte[] buffer = FlvArrayPool.Rent(2048); - try - { - FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); - //flv body video tag - //flv body tag header - FlvTags flvTags = new FlvTags(); - flvTags.Type = TagType.Video; - flvTags.Timestamp =0; - flvTags.TimestampExt = 0; - flvTags.StreamId = 0; - //flv body tag body - flvTags.VideoTagsData = new VideoTags(); - flvTags.VideoTagsData.FrameType = FrameType.KeyFrame; - flvTags.VideoTagsData.VideoData = new AvcVideoPacke(); - flvTags.VideoTagsData.VideoData.AvcPacketType = AvcPacketType.SequenceHeader; - flvTags.VideoTagsData.VideoData.CompositionTime = 0; - AVCDecoderConfigurationRecord aVCDecoderConfigurationRecord = new AVCDecoderConfigurationRecord(); - aVCDecoderConfigurationRecord.AVCProfileIndication = spsInfo.profileIdc; - aVCDecoderConfigurationRecord.ProfileCompatibility = (byte)spsInfo.profileCompat; - aVCDecoderConfigurationRecord.AVCLevelIndication = spsInfo.levelIdc; - aVCDecoderConfigurationRecord.NumOfPictureParameterSets = 1; - aVCDecoderConfigurationRecord.PPSBuffer = ppsRawData; - aVCDecoderConfigurationRecord.SPSBuffer = spsRawData; - flvTags.VideoTagsData.VideoData.AVCDecoderConfiguration = aVCDecoderConfigurationRecord; - flvMessagePackWriter.WriteFlvTag(flvTags); - return flvMessagePackWriter.FlushAndGetArray(); - } - finally - { - FlvArrayPool.Return(buffer); - } - } - internal byte[] CreateVideoTagOtherFrame(FlvFrameInfo flvFrameInfo, H264NALU nALU, H264NALU sei) - { - byte[] buffer = FlvArrayPool.Rent(65535); - try - { - FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); - //flv body video tag - //flv body tag header - FlvTags flvTags = new FlvTags(); - flvTags.Type = TagType.Video; - //pts - flvTags.Timestamp = flvFrameInfo.Interval; - flvTags.TimestampExt = 0; - flvTags.StreamId = 0; - //flv body tag body - flvTags.VideoTagsData = new VideoTags(); - flvTags.VideoTagsData.VideoData = new AvcVideoPacke(); - flvTags.VideoTagsData.VideoData.AvcPacketType = AvcPacketType.Raw; - if (nALU.NALUHeader.NalUnitType == 5 || nALU.DataType == JT1078DataType.视频I帧) - { - flvTags.VideoTagsData.FrameType = FrameType.KeyFrame; - } - else - { - flvTags.VideoTagsData.FrameType = FrameType.InterFrame; - } - if(flvFrameInfo.DataType== JT1078DataType.视频I帧) - { - //cts - flvTags.VideoTagsData.VideoData.CompositionTime = nALU.LastIFrameInterval; - } - else - { - //cts - flvTags.VideoTagsData.VideoData.CompositionTime = nALU.LastFrameInterval; - } - flvTags.VideoTagsData.VideoData.MultiData = new List(); - flvTags.VideoTagsData.VideoData.MultiData.Add(nALU.RawData); - //忽略sei - //if (sei != null && sei.RawData != null && sei.RawData.Length > 0) - //{ - // flvTags.VideoTagsData.VideoData.MultiData.Add(sei.RawData); - //} - flvMessagePackWriter.WriteFlvTag(flvTags); - return flvMessagePackWriter.FlushAndGetArray(); - } - finally - { - FlvArrayPool.Return(buffer); - } - } + /// /// /// @@ -227,7 +59,7 @@ namespace JT1078.Flv try { FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); - H264NALU sps=null, pps=null, sei=null; + H264NALU sps = null, pps = null, sei = null; foreach (var naln in nALUs) { key = key ?? naln.GetKey(); @@ -260,11 +92,11 @@ namespace JT1078.Flv logger.LogDebug($"Cache:{spsInfoCache.height}-{spsInfoCache.width},Current:{spsInfo.height}-{spsInfo.width}"); } } - var secondFlvKeyFrame=CreateSecondFlvKeyFrame(sps.RawData, pps.RawData, spsInfo, flvFrameInfo); + var secondFlvKeyFrame = CreateFirstFlvKeyFrame(sps.RawData, pps.RawData, spsInfo, flvFrameInfo.PreviousTagSize); flvMessagePackWriter.WriteArray(secondFlvKeyFrame.Buffer); flvFrameInfo.PreviousTagSize = secondFlvKeyFrame.PreviousTagSize; FlvFrameInfoDict.TryUpdate(key, flvFrameInfo, flvFrameInfo); - if(FirstFlvFrameCache.TryGetValue(key,out var firstFlvFrameCacche)) + if (FirstFlvFrameCache.TryGetValue(key, out var firstFlvFrameCacche)) { FirstFlvFrameCache.TryUpdate(key, (secondFlvKeyFrame.PreviousTagSize, secondFlvKeyFrame.Buffer, true), firstFlvFrameCacche); } @@ -283,13 +115,14 @@ namespace JT1078.Flv } } //cache PreviousTagSize - FlvFrameInfoDict.TryAdd(key, new FlvFrameInfo{ - PreviousTagSize = firstFlvKeyFrame.PreviousTagSize, - Interval = (uint)(pps.Timestamp - sps.Timestamp), - Timestamp= pps.Timestamp, - } - ); - FirstFlvFrameCache.TryAdd(key, (firstFlvKeyFrame.PreviousTagSize, firstFlvKeyFrame.Buffer, false)); + FlvFrameInfoDict.TryAdd(key, new FlvFrameInfo + { + PreviousTagSize = firstFlvKeyFrame.PreviousTagSize, + Interval = (uint)(pps.Timestamp - sps.Timestamp), + Timestamp = pps.Timestamp, + } + ); + FirstFlvFrameCache.TryAdd(key, (firstFlvKeyFrame.PreviousTagSize, firstFlvKeyFrame.Buffer, false)); VideoSPSDict.TryAdd(key, spsInfo); } sps = null; @@ -306,9 +139,26 @@ namespace JT1078.Flv //7 8 6 5 1 1 1 1 7 8 6 5 1 1 1 1 1 7 8 6 5 1 1 1 1 1 switch (naln.NALUHeader.NalUnitType) { +#warning 是否需要IDR帧? 每次发送IDR帧? 在测试的时候,是否由于图像变化不大所以不需要IDR帧? case 5:// IDR + if (FlvFrameInfoDict.TryGetValue(key, out FlvFrameInfo idrInfo)) + { + //当前的1078包与上一包1078的时间戳相减再进行累加 + uint interval = (uint)(naln.Timestamp - idrInfo.Timestamp); + idrInfo.Interval += interval; + idrInfo.Timestamp = naln.Timestamp; + // PreviousTagSize + flvMessagePackWriter.WriteUInt32(idrInfo.PreviousTagSize); + // Data Tag Frame + var flvFrameBuffer = CreateVideoTagOtherFrame(idrInfo, naln, sei); + flvMessagePackWriter.WriteArray(flvFrameBuffer); + idrInfo.PreviousTagSize = (uint)flvFrameBuffer.Length; + idrInfo.LastDataType = naln.DataType; + FlvFrameInfoDict.TryUpdate(key, idrInfo, idrInfo); + } + break; case 1:// I/P/B - if (FlvFrameInfoDict.TryGetValue(key, out FlvFrameInfo flvFrameInfo)) + if (FlvFrameInfoDict.TryGetValue(key, out FlvFrameInfo flvFrameInfo)) { //当前的1078包与上一包1078的时间戳相减再进行累加 uint interval = (uint)(naln.Timestamp - flvFrameInfo.Timestamp); @@ -320,7 +170,7 @@ namespace JT1078.Flv var flvFrameBuffer = CreateVideoTagOtherFrame(flvFrameInfo, naln, sei); flvMessagePackWriter.WriteArray(flvFrameBuffer); flvFrameInfo.PreviousTagSize = (uint)flvFrameBuffer.Length; - flvFrameInfo.DataType = naln.DataType; + flvFrameInfo.LastDataType = naln.DataType; FlvFrameInfoDict.TryUpdate(key, flvFrameInfo, flvFrameInfo); } break; @@ -344,56 +194,7 @@ namespace JT1078.Flv FlvArrayPool.Return(buffer); } } - internal (byte[] Buffer, uint PreviousTagSize) CreateFirstFlvKeyFrame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo) - { - byte[] buffer = FlvArrayPool.Rent(65535); - try - { - FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); - //flv body PreviousTagSize awalys 0 - flvMessagePackWriter.WriteUInt32(0); - //flv body script tag - var scriptTagFrameBuffer= CreateScriptTagFrame(spsInfo.width, spsInfo.height); - flvMessagePackWriter.WriteArray(scriptTagFrameBuffer); - //flv script tag PreviousTagSize - flvMessagePackWriter.WriteUInt32((uint)scriptTagFrameBuffer.Length); - //flv body video tag 0 - var videoTagFrame0Buffer= CreateVideoTag0Frame(spsRawData, ppsRawData, spsInfo); - flvMessagePackWriter.WriteArray(videoTagFrame0Buffer); - uint videoTag0PreviousTagSize = (uint)videoTagFrame0Buffer.Length; - return (flvMessagePackWriter.FlushAndGetArray(), videoTag0PreviousTagSize); - } - finally - { - FlvArrayPool.Return(buffer); - } - } - internal (byte[] Buffer,uint PreviousTagSize) CreateSecondFlvKeyFrame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo, FlvFrameInfo flvFrameInfo) - { - byte[] buffer = FlvArrayPool.Rent(65535); - try - { - FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); - //flv body PreviousTagSize awalys 0 - //当首包的时候为 0 - //当切花主次码流的时候需要根据上一包的大小 - flvMessagePackWriter.WriteUInt32(flvFrameInfo.PreviousTagSize); - //flv body script tag - var scriptTagFrameBuffer = CreateScriptTagFrame(spsInfo.width, spsInfo.height); - flvMessagePackWriter.WriteArray(scriptTagFrameBuffer); - //flv script tag PreviousTagSize - flvMessagePackWriter.WriteUInt32((uint)scriptTagFrameBuffer.Length); - //flv body video tag 0 - var videoTagFrame0Buffer = CreateSecondVideoTag0Frame(spsRawData, ppsRawData, spsInfo); - flvMessagePackWriter.WriteArray(videoTagFrame0Buffer); - uint videoTag0PreviousTagSize = (uint)videoTagFrame0Buffer.Length; - return (flvMessagePackWriter.FlushAndGetArray(), videoTag0PreviousTagSize); - } - finally - { - FlvArrayPool.Return(buffer); - } - } + /// /// /// @@ -449,6 +250,168 @@ namespace JT1078.Flv } return default; } + + internal byte[] CreateScriptTagFrame(int width, int height, double frameRate = 25d) + { + byte[] buffer = FlvArrayPool.Rent(1024); + try + { + FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); + //flv body script tag + //flv body tag header + FlvTags flvTags = new FlvTags(); + flvTags.Type = TagType.ScriptData; + flvTags.Timestamp = 0; + flvTags.TimestampExt = 0; + flvTags.StreamId = 0; + //flv body tag body + flvTags.DataTagsData = new Amf3(); + flvTags.DataTagsData.Amf3Metadatas = new List(); + flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_Duration + { + Value = 0d + }); + flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_VideoDataRate + { + Value = 0d + }); + flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_VideoCodecId + { + Value = 7d + }); + flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_FrameRate + { + Value = frameRate + }); + flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_Width + { + Value = width + }); + flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_Height + { + Value = height + }); + flvMessagePackWriter.WriteFlvTag(flvTags); + return flvMessagePackWriter.FlushAndGetArray(); + } + finally + { + FlvArrayPool.Return(buffer); + } + } + internal byte[] CreateVideoTag0Frame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo) + { + byte[] buffer = FlvArrayPool.Rent(2048); + try + { + FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); + //flv body video tag + //flv body tag header + FlvTags flvTags = new FlvTags(); + flvTags.Type = TagType.Video; + flvTags.Timestamp = 0; + flvTags.TimestampExt = 0; + flvTags.StreamId = 0; + //flv body tag body + flvTags.VideoTagsData = new VideoTags(); + flvTags.VideoTagsData.FrameType = FrameType.KeyFrame; + flvTags.VideoTagsData.VideoData = new AvcVideoPacke(); + flvTags.VideoTagsData.VideoData.AvcPacketType = AvcPacketType.SequenceHeader; + flvTags.VideoTagsData.VideoData.CompositionTime = 0; + AVCDecoderConfigurationRecord aVCDecoderConfigurationRecord = new AVCDecoderConfigurationRecord(); + aVCDecoderConfigurationRecord.AVCProfileIndication = spsInfo.profileIdc; + aVCDecoderConfigurationRecord.ProfileCompatibility = (byte)spsInfo.profileCompat; + aVCDecoderConfigurationRecord.AVCLevelIndication = spsInfo.levelIdc; + aVCDecoderConfigurationRecord.NumOfPictureParameterSets = 1; + aVCDecoderConfigurationRecord.PPSBuffer = ppsRawData; + aVCDecoderConfigurationRecord.SPSBuffer = spsRawData; + flvTags.VideoTagsData.VideoData.AVCDecoderConfiguration = aVCDecoderConfigurationRecord; + flvMessagePackWriter.WriteFlvTag(flvTags); + return flvMessagePackWriter.FlushAndGetArray(); + } + finally + { + FlvArrayPool.Return(buffer); + } + } + internal byte[] CreateVideoTagOtherFrame(FlvFrameInfo flvFrameInfo, H264NALU nALU, H264NALU sei) + { + byte[] buffer = FlvArrayPool.Rent(65535); + try + { + FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); + //flv body video tag + //flv body tag header + FlvTags flvTags = new FlvTags(); + flvTags.Type = TagType.Video; + //pts + flvTags.Timestamp = flvFrameInfo.Interval; + flvTags.TimestampExt = 0; + flvTags.StreamId = 0; + //flv body tag body + flvTags.VideoTagsData = new VideoTags(); + flvTags.VideoTagsData.VideoData = new AvcVideoPacke(); + flvTags.VideoTagsData.VideoData.AvcPacketType = AvcPacketType.Raw; + //1: keyframe (for AVC, a seekable frame) —— 即H.264的IDR帧; + //2: inter frame(for AVC, a non - seekable frame) —— H.264的普通I帧; + //ref:https://www.cnblogs.com/chyingp/p/flv-getting-started.html + if (nALU.NALUHeader.NalUnitType == 5) + { + flvTags.VideoTagsData.FrameType = FrameType.KeyFrame; + } + else + { + flvTags.VideoTagsData.FrameType = FrameType.InterFrame; + } + if (flvFrameInfo.LastDataType == JT1078DataType.视频I帧) + { + //cts + flvTags.VideoTagsData.VideoData.CompositionTime = nALU.LastIFrameInterval; + } + else + { + //cts + flvTags.VideoTagsData.VideoData.CompositionTime = nALU.LastFrameInterval; + } + flvTags.VideoTagsData.VideoData.MultiData = new List(); + flvTags.VideoTagsData.VideoData.MultiData.Add(nALU.RawData); + //忽略sei + //if (sei != null && sei.RawData != null && sei.RawData.Length > 0) + //{ + // flvTags.VideoTagsData.VideoData.MultiData.Add(sei.RawData); + //} + flvMessagePackWriter.WriteFlvTag(flvTags); + return flvMessagePackWriter.FlushAndGetArray(); + } + finally + { + FlvArrayPool.Return(buffer); + } + } + internal (byte[] Buffer, uint PreviousTagSize) CreateFirstFlvKeyFrame(byte[] spsRawData, byte[] ppsRawData, SPSInfo spsInfo, uint previousTagSize = 0) + { + byte[] buffer = FlvArrayPool.Rent(65535); + try + { + FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); + //flv body PreviousTagSize awalys 0 + flvMessagePackWriter.WriteUInt32(previousTagSize); + //flv body script tag + var scriptTagFrameBuffer = CreateScriptTagFrame(spsInfo.width, spsInfo.height); + flvMessagePackWriter.WriteArray(scriptTagFrameBuffer); + //flv script tag PreviousTagSize + flvMessagePackWriter.WriteUInt32((uint)scriptTagFrameBuffer.Length); + //flv body video tag 0 + var videoTagFrame0Buffer = CreateVideoTag0Frame(spsRawData, ppsRawData, spsInfo); + flvMessagePackWriter.WriteArray(videoTagFrame0Buffer); + uint videoTag0PreviousTagSize = (uint)videoTagFrame0Buffer.Length; + return (flvMessagePackWriter.FlushAndGetArray(), videoTag0PreviousTagSize); + } + finally + { + FlvArrayPool.Return(buffer); + } + } } internal class FlvFrameInfo @@ -456,6 +419,6 @@ namespace JT1078.Flv public uint PreviousTagSize { get; set; } public ulong Timestamp { get; set; } public uint Interval { get; set; } - public JT1078DataType DataType { get; set; } + public JT1078DataType LastDataType { get; set; } } } diff --git a/src/JT1078.Flv/JT1078.Flv.csproj b/src/JT1078.Flv/JT1078.Flv.csproj index 0d3ae5f..8201170 100644 --- a/src/JT1078.Flv/JT1078.Flv.csproj +++ b/src/JT1078.Flv/JT1078.Flv.csproj @@ -14,7 +14,7 @@ https://github.com/SmallChi/JT1078/blob/master/LICENSE https://github.com/SmallChi/JT1078/blob/master/LICENSE false - 1.0.0-preview2 + 1.0.0-preview3 false true LICENSE diff --git a/src/JT1078.Flv/JT1078.Flv.xml b/src/JT1078.Flv/JT1078.Flv.xml index 5ebe50b..d340b69 100644 --- a/src/JT1078.Flv/JT1078.Flv.xml +++ b/src/JT1078.Flv/JT1078.Flv.xml @@ -53,11 +53,21 @@ Flv固定头部数据 - + + + + + + 由于获取的SIM卡可能为000000000000,所以如果有替换JT1078Package.GetKey()的值 + + + + 完整的1078包 + 由于获取的SIM卡可能为000000000000,所以如果有替换JT1078Package.GetKey()的值 默认65535 @@ -97,12 +107,13 @@ 根据tag类型 - + +