Browse Source

包装FLV

tags/v1.1.0
smallchi 5 years ago
parent
commit
43db0f4fa6
9 changed files with 203 additions and 29 deletions
  1. +2
    -2
      src/JT1078.Flv.Test/FlvEncoderTest.cs
  2. +1
    -5
      src/JT1078.Flv.Test/JT1078.Flv.Test.csproj
  3. +11
    -11
      src/JT1078.Flv.Test/MessagePack/FlvMessagePackWriter_FlvBody_Test.cs
  4. +41
    -0
      src/JT1078.Flv.Test/Metadata/AVCDecoderConfigurationRecordTest.cs
  5. +138
    -5
      src/JT1078.Flv/FlvEncoder.cs
  6. +3
    -4
      src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Flv.cs
  7. +2
    -2
      src/JT1078.Flv/Metadata/AVCDecoderConfigurationRecord.cs
  8. +3
    -0
      src/JT1078.Flv/Metadata/Amf3Metadata_VideoCodecId.cs
  9. +2
    -0
      src/JT1078.Flv/Metadata/AvcVideoPacke.cs

+ 2
- 2
src/JT1078.Flv.Test/FlvEncoderTest.cs View File

@@ -12,8 +12,8 @@ namespace JT1078.Flv.Test
public void FlvMuxer_Test_1()
{
FlvEncoder encoder = new FlvEncoder();
var buff = encoder.FlvFirstFrame();
var hex= buff.ToHexString();
//var buff = encoder.FlvFirstFrame();
//var hex= buff.ToHexString();
}
}
}

+ 1
- 5
src/JT1078.Flv.Test/JT1078.Flv.Test.csproj View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
@@ -15,10 +15,6 @@
<ProjectReference Include="..\JT1078.Flv\JT1078.Flv.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="Metadata\" />
</ItemGroup>

<ItemGroup>
<None Update="H264\JT1078.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>


+ 11
- 11
src/JT1078.Flv.Test/MessagePack/FlvMessagePackWriter_FlvBody_Test.cs View File

@@ -18,14 +18,14 @@ namespace JT1078.Flv.Test.MessagePack
FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer);
FlvBody flvBody = new FlvBody()
{
PreviousTagSize=0,
Tag = new FlvTags
{
Type = Enums.TagType.ScriptData,
DataSize = 156,
DataTagsData = new Amf3
{
Amf3Metadatas = new List<Flv.Metadata.IAmf3Metadata> {
PreviousTagSize = 0,
Tag = new FlvTags
{
Type = Enums.TagType.ScriptData,
DataSize = 156,
DataTagsData = new Amf3
{
Amf3Metadatas = new List<Flv.Metadata.IAmf3Metadata> {
new Amf3Metadata_Duration{
Value=7.22100
},
@@ -48,11 +48,11 @@ namespace JT1078.Flv.Test.MessagePack
Value=544.00000
}
}
}
}
}
}
};
flvMessagePackWriter.WriteFlvBody(flvBody);
var hex=flvMessagePackWriter.FlushAndGetArray().ToHexString();
var hex = flvMessagePackWriter.FlushAndGetArray().ToHexString();
Assert.Equal("00000000120000A00000000000000002000A6F6E4D65746144617461080000000700086475726174696F6E00401CE24DD2F1A9FC000866696C6573697A6500413E99AD0000000000096672616D657261746500403D2AAAE297396D000668656967687400408E000000000000000C766964656F636F646563696400401C000000000000000D766964656F646174617261746500000000000000000000057769647468004081000000000000", hex);
}
}


+ 41
- 0
src/JT1078.Flv.Test/Metadata/AVCDecoderConfigurationRecordTest.cs View File

@@ -0,0 +1,41 @@
using JT1078.Flv.MessagePack;
using JT1078.Flv.Metadata;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using JT1078.Flv.Extensions;

namespace JT1078.Flv.Test.Metadata
{
public class AVCDecoderConfigurationRecordTest
{
[Fact]
public void Test1()
{
Span<byte> buffer = new byte[1024];
FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer);
AVCDecoderConfigurationRecord aVCDecoderConfigurationRecord = new AVCDecoderConfigurationRecord();
aVCDecoderConfigurationRecord.AVCProfileIndication = 0x64;
aVCDecoderConfigurationRecord.ProfileCompatibility = 0;
aVCDecoderConfigurationRecord.AVCLevelIndication =0x1F;
aVCDecoderConfigurationRecord.NumOfPictureParameterSets = 1;
aVCDecoderConfigurationRecord.SPSBuffer = new byte[] {
0x67,0x64,0x00,0x1F,
0xAC,0xD9,0x40,0x88,
0x1E,0x68,0x40,0x00,
0x00,0x03,0x01,0x80,
0x00,0x00,0x57,0x83,
0xC6,0x0C,0x65,0x80
};
aVCDecoderConfigurationRecord.PPSBuffer = new byte[] {
0x68,0xEB,0xE3,0xCB,0x22,0xC0
};
flvMessagePackWriter.WriteAVCDecoderConfigurationRecord(aVCDecoderConfigurationRecord);
var hexData = flvMessagePackWriter.FlushAndGetArray().ToHexString();
Assert.Equal("0164001FFFE100186764001FACD940881E6840000003018000005783C60C658001000668EBE3CB22C0", hexData);
//0164001FFFE100186764001FACD940881E6840000003018000005783C60C658001000668EBE3CB22C0
//0164001FFFE100186764001FACD940881E6840000003018000005783C60C658001000668EBE3CB22C0
}
}
}

+ 138
- 5
src/JT1078.Flv/FlvEncoder.cs View File

@@ -1,6 +1,10 @@
using JT1078.Flv.MessagePack;
using JT1078.Flv.Enums;
using JT1078.Flv.H264;
using JT1078.Flv.MessagePack;
using JT1078.Flv.Metadata;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace JT1078.Flv
@@ -8,7 +12,8 @@ namespace JT1078.Flv
public class FlvEncoder
{
private static readonly FlvHeader VideoFlvHeader = new FlvHeader(true, false);
public byte[] FlvFirstFrame()
private static readonly H264Decoder h264Decoder = new H264Decoder();
public byte[] FlvFirstFrame(List<H264NALU> nALUs)
{
byte[] buffer = FlvArrayPool.Rent(10240);
try
@@ -16,15 +21,142 @@ namespace JT1078.Flv
FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer);
//flv header
flvMessagePackWriter.WriteArray(VideoFlvHeader.ToArray());
//flv body
//SPS -> 7
var spsNALU = nALUs.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7);
spsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(spsNALU.RawData);
ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData);
var spsInfo = h264GolombReader.ReadSPS();
//PPS -> 8
var ppsNALU = nALUs.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8);
//IDR -> 5 关键帧
var idrNALU = nALUs.FirstOrDefault(n => n.NALUHeader.NalUnitType == 5);
//SEI -> 6
//var seiNALU = nALUs.FirstOrDefault(n => n.NALUHeader.NalUnitType == 6);
//flv body script tag
var scriptTag = CreateScriptTagFrame(spsInfo.width, spsInfo.height);
//flv body video tag
AVCDecoderConfigurationRecord aVCDecoderConfigurationRecord = new AVCDecoderConfigurationRecord();
aVCDecoderConfigurationRecord.AVCProfileIndication = spsInfo.profileIdc;
aVCDecoderConfigurationRecord.ProfileCompatibility =(byte)spsInfo.profileCompat;
aVCDecoderConfigurationRecord.AVCLevelIndication = spsInfo.levelIdc;
aVCDecoderConfigurationRecord.NumOfPictureParameterSets = 1;
aVCDecoderConfigurationRecord.PPSBuffer = spsNALU.RawData;
aVCDecoderConfigurationRecord.SPSBuffer = ppsNALU.RawData;
var videoTag = CreateVideoTag0Frame((uint)scriptTag.Length, aVCDecoderConfigurationRecord);


return flvMessagePackWriter.FlushAndGetArray();
}
finally
{
FlvArrayPool.Return(buffer);
}
}

public byte[] CreateScriptTagFrame(int width,int height)
{
byte[] buffer = FlvArrayPool.Rent(1024);
try
{
FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer);
//flv body PreviousTagSize awalys 0
flvMessagePackWriter.WriteUInt32(0);
//flv body tag
//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.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 = 25d
});
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);
}
}

public byte[] CreateVideoTag0Frame(uint previousTagSize,AVCDecoderConfigurationRecord aVCDecoderConfigurationRecord)
{
byte[] buffer = FlvArrayPool.Rent(1024);
try
{
FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer);
//flv body PreviousTagSize ScriptTag
flvMessagePackWriter.WriteUInt32(previousTagSize);
//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;
flvTags.VideoTagsData.VideoData.AVCDecoderConfiguration = aVCDecoderConfigurationRecord;
flvMessagePackWriter.WriteFlvTag(flvTags);
return flvMessagePackWriter.FlushAndGetArray();
}
finally
{
FlvArrayPool.Return(buffer);
}
}

public byte[] CreateVideoTagOtherFrame(uint previousTagSize, H264NALU nALU)
{
byte[] buffer = FlvArrayPool.Rent(2048);
try
{
FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer);
//flv body PreviousTagSize ScriptTag
flvMessagePackWriter.WriteUInt32(previousTagSize);
//flv body video tag
//flv body tag header
FlvTags flvTags = new FlvTags();
flvTags.Type = TagType.Video;
flvTags.Timestamp = nALU.LastIFrameInterval;
flvTags.TimestampExt = 0;
flvTags.StreamId = 0;
//flv body tag body
flvTags.VideoTagsData = new VideoTags();
flvTags.VideoTagsData.FrameType = FrameType.InterFrame;
flvTags.VideoTagsData.VideoData = new AvcVideoPacke();
flvTags.VideoTagsData.VideoData.AvcPacketType = AvcPacketType.Raw;
flvTags.VideoTagsData.VideoData.CompositionTime = nALU.LastIFrameInterval;
flvTags.VideoTagsData.VideoData.Data = nALU.RawData;
flvMessagePackWriter.WriteFlvTag(flvTags);
return flvMessagePackWriter.FlushAndGetArray();
}
finally
@@ -32,6 +164,7 @@ namespace JT1078.Flv
FlvArrayPool.Return(buffer);
}
}

public byte[] FlvOtherFrame()
{
byte[] buffer = FlvArrayPool.Rent(10240);


+ 3
- 4
src/JT1078.Flv/MessagePack/FlvMessagePackWriter_Flv.cs View File

@@ -80,13 +80,11 @@ namespace JT1078.Flv.MessagePack
videoPacke.CompositionTime = 0;
WriteUInt24(videoPacke.CompositionTime);
//AVCDecoderConfigurationRecord
#warning AVCDecoderConfigurationRecord
WriteArray(videoPacke.Data);
WriteAVCDecoderConfigurationRecord(videoPacke.AVCDecoderConfiguration);
}
else if(videoPacke.AvcPacketType == AvcPacketType.Raw)
{
WriteUInt24(videoPacke.CompositionTime);
#warning One or more NALUs
//One or more NALUs
WriteArray(videoPacke.Data);
}
@@ -104,7 +102,8 @@ namespace JT1078.Flv.MessagePack
WriteByte(configurationRecord.AVCProfileIndication);
WriteByte(configurationRecord.ProfileCompatibility);
WriteByte(configurationRecord.AVCLevelIndication);
WriteByte((byte)configurationRecord.LengthSizeMinusOne);
#warning reserved(6bits)+LengthSizeMinusOne(2bits)
WriteByte(0xFF);
WriteByte((byte)configurationRecord.NumOfSequenceParameterSets);
WriteUInt16((ushort)configurationRecord.SPSBuffer.Length);
WriteArray(configurationRecord.SPSBuffer);


+ 2
- 2
src/JT1078.Flv/Metadata/AVCDecoderConfigurationRecord.cs View File

@@ -38,9 +38,9 @@ namespace JT1078.Flv.Metadata
public byte ProfileCompatibility { get; set; }
public byte AVCLevelIndication { get; set; }
public int LengthSizeMinusOne { get; set; }
public int NumOfSequenceParameterSets { get; set; }
public int NumOfSequenceParameterSets { get; set; }= 0xE0 | 1;
public byte[] SPSBuffer { get; set; }
public byte NumOfPictureParameterSets { get; set; } = 1;
public byte NumOfPictureParameterSets { get; set; }
public byte[] PPSBuffer { get; set; }
#region Just for non-spec-conform encoders ref:org.mp4parser.boxes.iso14496.part15.AvcDecoderConfigurationRecord
public const int LengthSizeMinusOnePaddingBits = 63;


+ 3
- 0
src/JT1078.Flv/Metadata/Amf3Metadata_VideoCodecId.cs View File

@@ -11,6 +11,9 @@ namespace JT1078.Flv.Metadata
public ushort FieldNameLength { get; set; }
public string FieldName { get; set; } = "videocodecid";
public byte DataType { get; set; } = 0x00;
/// <summary>
/// <see cref="typeof(JT1078.Flv.Enums.CodecId.AvcVideoPacke)"/>
/// </summary>
public object Value { get; set; }

public ReadOnlySpan<byte> ToBuffer()


+ 2
- 0
src/JT1078.Flv/Metadata/AvcVideoPacke.cs View File

@@ -11,6 +11,8 @@ namespace JT1078.Flv.Metadata

public uint CompositionTime { get; set; }

public AVCDecoderConfigurationRecord AVCDecoderConfiguration { get; set; }

public byte[] Data { get; set; }
}
}

Loading…
Cancel
Save