Selaa lähdekoodia

1.修改flv编码的方法访问级别

2.修改测试用例要入Flv头部数据
tags/v1.1.0
smallchi 5 vuotta sitten
vanhempi
commit
51f1e4b8ac
4 muutettua tiedostoa jossa 253 lisäystä ja 21 poistoa
  1. +13
    -7
      src/JT1078.Flv.Test/FlvEncoderTest.cs
  2. +28
    -13
      src/JT1078.Flv/FlvEncoder.cs
  3. +9
    -1
      src/JT1078.Flv/JT1078.Flv.csproj
  4. +203
    -0
      src/JT1078.Flv/JT1078.Flv.xml

+ 13
- 7
src/JT1078.Flv.Test/FlvEncoderTest.cs Näytä tiedosto

@@ -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();


+ 28
- 13
src/JT1078.Flv/FlvEncoder.cs Näytä tiedosto

@@ -19,6 +19,9 @@ namespace JT1078.Flv
{
public class FlvEncoder
{
/// <summary>
/// Flv固定头部数据
/// </summary>
public static readonly byte[] VideoFlvHeaderBuffer;
private static readonly Flv.H264.H264Decoder H264Decoder;
private static readonly ConcurrentDictionary<string, SPSInfo> 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);
}
}
/// <summary>
///
/// </summary>
/// <param name="package">完整的1078包</param>
/// <param name="minimumLength">默认65535</param>
/// <returns></returns>
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)
/// <summary>
///
/// </summary>
/// <param name="key">设备号+通道号(1111111_1)</param>
/// <param name="currentBufferFlvFrame">当前接收到的flv数据</param>
/// <returns></returns>
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; }


+ 9
- 1
src/JT1078.Flv/JT1078.Flv.csproj Näytä tiedosto

@@ -14,12 +14,20 @@
<licenseUrl>https://github.com/SmallChi/JT1078/blob/master/LICENSE</licenseUrl>
<license>https://github.com/SmallChi/JT1078/blob/master/LICENSE</license>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>1.0.0-preview1</Version>
<Version>1.0.0-preview2</Version>
<SignAssembly>false</SignAssembly>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
<DocumentationFile>JT1078.Flv.xml</DocumentationFile>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
<DocumentationFile>JT1078.Flv.xml</DocumentationFile>
</PropertyGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="System.Memory" Version="4.5.3" />
</ItemGroup>


+ 203
- 0
src/JT1078.Flv/JT1078.Flv.xml Näytä tiedosto

@@ -0,0 +1,203 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>JT1078.Flv</name>
</assembly>
<members>
<member name="T:JT1078.Flv.FlvBufferWriter">
<summary>
<see cref="!:System.Buffers.Writer"/>
</summary>
</member>
<member name="F:JT1078.Flv.Enums.FrameType.KeyFrame">
<summary>
‭00010000‬
</summary>
</member>
<member name="F:JT1078.Flv.Enums.FrameType.InterFrame">
<summary>
‭00100000‬
</summary>
</member>
<member name="F:JT1078.Flv.Enums.FrameType.DisposableInterFrame">
<summary>
‭00110000‬
</summary>
</member>
<member name="F:JT1078.Flv.Enums.FrameType.GeneratedKeyFrame">
<summary>
01000000
</summary>
</member>
<member name="F:JT1078.Flv.Enums.FrameType.VideoInfoOrCommandFrame">
<summary>
01010000
</summary>
</member>
<member name="T:JT1078.Flv.Extensions.HexExtensions">
<summary>
ref:"www.codeproject.com/tips/447938/high-performance-csharp-byte-array-to-hex-string-t"
</summary>
</member>
<member name="M:JT1078.Flv.Extensions.HexExtensions.ToHexBytes(System.String)">
<summary>
16进制字符串转16进制数组
</summary>
<param name="hexString"></param>
<param name="separator"></param>
<returns></returns>
</member>
<member name="F:JT1078.Flv.FlvEncoder.VideoFlvHeaderBuffer">
<summary>
Flv固定头部数据
</summary>
</member>
<member name="M:JT1078.Flv.FlvEncoder.CreateFlvFrame(JT1078.Protocol.JT1078Package,System.Int32)">
<summary>
</summary>
<param name="package">完整的1078包</param>
<param name="minimumLength">默认65535</param>
<returns></returns>
</member>
<member name="M:JT1078.Flv.FlvEncoder.GetFirstFlvFrame(System.String,System.Byte[])">
<summary>
</summary>
<param name="key">设备号+通道号(1111111_1)</param>
<param name="currentBufferFlvFrame">当前接收到的flv数据</param>
<returns></returns>
</member>
<member name="P:JT1078.Flv.FlvTags.DataSize">
<summary>
Tag Data部分大小
3个字节
</summary>
</member>
<member name="P:JT1078.Flv.FlvTags.Timestamp">
<summary>
Tag时间戳
3个字节
</summary>
</member>
<member name="P:JT1078.Flv.FlvTags.StreamId">
<summary>
stream id 总是0
3个字节
</summary>
</member>
<member name="P:JT1078.Flv.FlvTags.VideoTagsData">
<summary>
根据tag类型
</summary>
</member>
<member name="P:JT1078.Flv.FlvTags.DataTagsData">
<summary>
根据tag类型
</summary>
</member>
<member name="M:JT1078.Flv.H264.H264Decoder.ParseNALU(JT1078.Protocol.JT1078Package)">
<summary>
<see cref="!:https://github.com/samirkumardas/jmuxer/blob/master/src/parsers/h264.js"/>
</summary>
<param name="package"></param>
<returns></returns>
</member>
<member name="M:JT1078.Flv.H264.H264Decoder.DiscardEmulationPreventionBytes(System.ReadOnlySpan{System.Byte})">
<summary>
Expunge any "Emulation Prevention" bytes from a "Raw Byte Sequence Payload"
<see cref="!:https://blog.csdn.net/u011399342/article/details/80472084"/>
防止竞争插入0x03
</summary>
<param name="srcBuffer"></param>
<returns></returns>
</member>
<member name="P:JT1078.Flv.H264.H264NALU.SIM">
<summary>
终端设备SIM卡号
BCD[6]
</summary>
</member>
<member name="P:JT1078.Flv.H264.H264NALU.LogicChannelNumber">
<summary>
逻辑通道号
</summary>
</member>
<member name="P:JT1078.Flv.H264.H264NALU.DataType">
<summary>
数据类型
</summary>
</member>
<member name="P:JT1078.Flv.H264.H264NALU.LastIFrameInterval">
<summary>
该帧与上一个关键帧之间的时间间隔,单位毫秒(ms),
当数据类型为非视频帧时,则没有该字段
</summary>
</member>
<member name="P:JT1078.Flv.H264.H264NALU.LastFrameInterval">
<summary>
该帧与上一个帧之间的时间间隔,单位毫秒(ms),
当数据类型为非视频帧时,则没有该字段
</summary>
</member>
<member name="P:JT1078.Flv.H264.H264NALU.Timestamp">
<summary>
时间戳
标识此RTP数据包当前帧的相对时间,单位毫秒(ms)。
当数据类型为01000时,则没有该字段
</summary>
</member>
<member name="P:JT1078.Flv.H264.H264NALU.RawData">
<summary>
数据体
</summary>
</member>
<member name="T:JT1078.Flv.MessagePack.ExpGolombReader">
<summary>
Exp-Golomb指数哥伦布编码
</summary>
</member>
<member name="M:JT1078.Flv.MessagePack.ExpGolombReader.SkipScalingList(System.Int32)">
<summary>
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
</summary>
<param name="count"></param>
</member>
<member name="P:JT1078.Flv.Metadata.Amf3.DataType">
<summary>
AMF3数据类型
</summary>
</member>
<member name="P:JT1078.Flv.Metadata.Amf3.Count">
<summary>
元素个数
</summary>
</member>
<member name="P:JT1078.Flv.Metadata.Amf3Metadata_VideoCodecId.Value">
<summary>
<see cref="!:typeof(JT1078.Flv.Enums.CodecId.AvcVideoPacke)"/>
</summary>
</member>
<!-- Badly formed XML comment ignored for member "T:JT1078.Flv.Metadata.AVCDecoderConfigurationRecord" -->
<member name="P:JT1078.Flv.Metadata.VideoTags.FrameType">
<summary>
高4位
1: keyframe(for AVC, a seekable frame) —— 即H.264的IDR帧;
2: inter frame(for AVC, a non- seekable frame) —— H.264的普通I帧;
</summary>
</member>
<member name="P:JT1078.Flv.Metadata.VideoTags.CodecId">
<summary>
第四位
当 CodecID 为 7 时,VideoData 为 AVCVIDEOPACKE,也即 H.264媒体数据
</summary>
</member>
</members>
</doc>

Ladataan…
Peruuta
Tallenna