Pārlūkot izejas kodu

将1078转fmp4_13

master
SmallChi(Koike) pirms 4 gadiem
vecāks
revīzija
e498216231
12 mainītis faili ar 384 papildinājumiem un 18 dzēšanām
  1. +2
    -0
      doc/ffmpeginfo.txt
  2. +68
    -8
      src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs
  3. +6
    -0
      src/JT1078.FMp4/Boxs/MovieFragmentBox.cs
  4. +1
    -1
      src/JT1078.FMp4/Boxs/MovieFragmentRandomAccessBox.cs
  5. +10
    -1
      src/JT1078.FMp4/Boxs/TrackFragmentHeaderBox.cs
  6. +171
    -2
      src/JT1078.FMp4/FMp4Encoder.cs
  7. +18
    -0
      src/JT1078.FMp4/JT1078.FMp4.xml
  8. +23
    -1
      src/JT1078.FMp4/MessagePack/FMp4MessagePackWriter.cs
  9. +2
    -2
      src/JT1078.Protocol.Test/JT1078SerializerTest.cs
  10. +63
    -3
      src/JT1078.Protocol/H264/H264Decoder.cs
  11. +5
    -0
      src/JT1078.Protocol/H264/H264NALU.cs
  12. +15
    -0
      src/JT1078.Protocol/JT1078.Protocol.xml

+ 2
- 0
doc/ffmpeginfo.txt Parādīt failu

@@ -10,4 +10,6 @@ ffmpeg -i ipc.264 -vcodec copy -f mp4 -movflags frag_keyframe+empty_moov ipc_fra

ffmpeg -i jt1078_3.h264 -c:v copy -f mp4 -movflags empty_moov+default_base_moof+frag_keyframe fragmented_base_moof_demo.mp4

ffprobe -of json -show_frames jt1078_3.h264 > jt1078_3.json

chrome://media-internals/

+ 68
- 8
src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs Parādīt failu

@@ -456,6 +456,7 @@ namespace JT1078.FMp4.Test
NalUnitType.PPS,
NalUnitType.AUD};
int i = 0;
List<H264NALU> h264NALUs = new List<H264NALU>();
foreach (var package in packages)
{
var otherStypBuffer = fMp4Encoder.EncoderStypBox();
@@ -467,14 +468,6 @@ namespace JT1078.FMp4.Test
// continue;
//}
//int length = filterOtherNalus.Sum(s => s.RawData.Length);
foreach(var nalu in otherNalus)
{
//H264 NALU slice first_mb_in_slice
if ((nalu.RawData[1] & 0x80) == 0x80)
{

}
}
var flag = package.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧 ? 1u : 0u;
var otherMoofBuffer = fMp4Encoder.EncoderMoofBox(otherNalus, package.Bodies.Length, package.Timestamp, package.LastFrameInterval, package.LastIFrameInterval, flag);
var otherMdatBuffer = fMp4Encoder.EncoderMdatBox(otherNalus, package.Bodies.Length);
@@ -488,6 +481,73 @@ namespace JT1078.FMp4.Test
fileStream.Close();
}

[Fact]
public void Test5()
{
FMp4Encoder fMp4Encoder = new FMp4Encoder();
H264Decoder h264Decoder = new H264Decoder();
var packages = ParseNALUTests();
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_5.mp4");
if (File.Exists(filepath))
{
File.Delete(filepath);
}
using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
var ftyp = fMp4Encoder.EncoderFtypBox();
fileStream.Write(ftyp);
List<NalUnitType> filter = new List<NalUnitType>() {
NalUnitType.SPS,
NalUnitType.PPS,
NalUnitType.AUD
};
var iNalus=h264Decoder.ParseNALU(packages[0]);
//判断第一帧是否关键帧
var moov = fMp4Encoder.EncoderMoovBox(
iNalus.FirstOrDefault(f=>f.NALUHeader.NalUnitType== NalUnitType.SPS),
iNalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.PPS));
fileStream.Write(moov);

List<H264NALU> nalus = new List<H264NALU>();
foreach (var package in packages)
{
List<H264NALU> h264NALUs = h264Decoder.ParseNALU(package);
foreach (var nalu in h264NALUs)
{
if (nalu.Slice)
{
//H264 NALU slice first_mb_in_slice
nalus.Add(nalu);
}
else
{
if (nalus.Count > 0)
{
var iStypBuffer = fMp4Encoder.EncoderStypBox();
fileStream.Write(iStypBuffer);
var firstNalu = nalus[0];
var flag = firstNalu.DataType == Protocol.Enums.JT1078DataType.视频I帧 ? 1u : 0u;
int iSize = nalus.Where(w => w.DataType == Protocol.Enums.JT1078DataType.视频I帧)
.Sum(s => s.RawData.Length + s.StartCodePrefix.Length);
List<int> sizes = new List<int>();
sizes.Add(iSize);
sizes = sizes.Concat(nalus.Where(w => w.DataType != Protocol.Enums.JT1078DataType.视频I帧)
.Select(s => s.RawData.Length + s.StartCodePrefix.Length).ToList())
.ToList();
var iMoofBuffer = fMp4Encoder.EncoderMoofBox(sizes, firstNalu.Timestamp, firstNalu.LastFrameInterval, firstNalu.LastIFrameInterval, flag);
var iMdatBuffer = fMp4Encoder.EncoderMdatBox(nalus.Select(s => s.RawData).ToList());
var iSidxBuffer = fMp4Encoder.EncoderSidxBox(iMoofBuffer.Length + iMdatBuffer.Length, firstNalu.Timestamp, firstNalu.LastIFrameInterval, firstNalu.LastFrameInterval);
fileStream.Write(iSidxBuffer);
fileStream.Write(iMoofBuffer);
fileStream.Write(iMdatBuffer);
nalus.Clear();
}
nalus.Add(nalu);
}
}
}
fileStream.Close();
}

[Fact]
public void tkhd_width_height_test()
{


+ 6
- 0
src/JT1078.FMp4/Boxs/MovieFragmentBox.cs Parādīt failu

@@ -38,6 +38,12 @@ namespace JT1078.FMp4
TrackFragmentBox.ToBuffer(ref writer);
}
End(ref writer);
var moofOffsetPosition = writer.GetMoofOffsetPosition();
if (moofOffsetPosition > 0)
{
writer.WriteUInt64Return((ulong)writer.GetCurrentPosition(), moofOffsetPosition);
}
writer.ClearMoofOffsetPosition();
var trunOffsetPosition = writer.GetTrunOffsetPosition();
if (trunOffsetPosition > 0)
{


+ 1
- 1
src/JT1078.FMp4/Boxs/MovieFragmentRandomAccessBox.cs Parādīt failu

@@ -38,7 +38,7 @@ namespace JT1078.FMp4
MovieFragmentRandomAccessOffsetBox.ToBuffer(ref writer);
}
End(ref writer);
var mfraSizePosition = writer.GetMfraSizePositionn();
var mfraSizePosition = writer.GetMfraSizePosition();
if (mfraSizePosition > 0)
{
writer.WriteInt32Return(writer.GetCurrentPosition() - SizePosition, mfraSizePosition);


+ 10
- 1
src/JT1078.FMp4/Boxs/TrackFragmentHeaderBox.cs Parādīt failu

@@ -60,7 +60,16 @@ namespace JT1078.FMp4
writer.WriteUInt32(TrackID);
if ((FMp4Constants.TFHD_FLAG_BASE_DATA_OFFSET & Flags) > 0)
{
writer.WriteUInt64(BaseDataOffset);
if (BaseDataOffset > 0)
{
writer.WriteUInt64(BaseDataOffset);
}
else
{
//程序自动计算
writer.CreateMoofOffsetPosition();
writer.Skip(8, out _);
}
}
if ((FMp4Constants.TFHD_FLAG_SAMPLE_DESCRIPTION_INDEX & Flags) > 0)
{


+ 171
- 2
src/JT1078.FMp4/FMp4Encoder.cs Parādīt failu

@@ -108,7 +108,9 @@ namespace JT1078.FMp4
}
}

uint IframeIntervalCache = 259960;
ulong IframeIntervalCache = 259960;

ulong cts = 0;

/// <summary>
/// 编码sidx盒子
@@ -122,7 +124,9 @@ namespace JT1078.FMp4
{
SegmentIndexBox segmentIndexBox = new SegmentIndexBox(1);
segmentIndexBox.ReferenceID = 1;
segmentIndexBox.EarliestPresentationTime = timestamp;
cts = cts == 0 ? 2160000 : (cts + cts);
segmentIndexBox.EarliestPresentationTime = cts;
IframeIntervalCache += frameInterval;
segmentIndexBox.SegmentIndexs = new List<SegmentIndexBox.SegmentIndex>()
{
new SegmentIndexBox.SegmentIndex
@@ -228,6 +232,88 @@ namespace JT1078.FMp4
}
}

/// <summary>
/// 编码moov盒子
/// </summary>
/// <returns></returns>
public byte[] EncoderMoovBox(in H264NALU sps, in H264NALU pps)
{
byte[] buffer = FMp4ArrayPool.Rent(sps.RawData.Length+ pps.RawData.Length + 4096);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer);
try
{
ExpGolombReader h264GolombReader = new ExpGolombReader(sps.RawData);
var spsInfo = h264GolombReader.ReadSPS();
//moov
MovieBox movieBox = new MovieBox();
movieBox.MovieHeaderBox = new MovieHeaderBox(0, 2);
movieBox.MovieHeaderBox.CreationTime = 0;
movieBox.MovieHeaderBox.ModificationTime = 0;
movieBox.MovieHeaderBox.Duration = 0;
movieBox.MovieHeaderBox.Timescale = 1000;
movieBox.MovieHeaderBox.NextTrackID = 99;
movieBox.TrackBox = new TrackBox();
movieBox.TrackBox.TrackHeaderBox = new TrackHeaderBox(0, 3);
movieBox.TrackBox.TrackHeaderBox.CreationTime = 0;
movieBox.TrackBox.TrackHeaderBox.ModificationTime = 0;
movieBox.TrackBox.TrackHeaderBox.TrackID = 1;
movieBox.TrackBox.TrackHeaderBox.Duration = 0;
movieBox.TrackBox.TrackHeaderBox.TrackIsAudio = false;
movieBox.TrackBox.TrackHeaderBox.Width = (uint)spsInfo.width;
movieBox.TrackBox.TrackHeaderBox.Height = (uint)spsInfo.height;
movieBox.TrackBox.MediaBox = new MediaBox();
movieBox.TrackBox.MediaBox.MediaHeaderBox = new MediaHeaderBox();
movieBox.TrackBox.MediaBox.MediaHeaderBox.CreationTime = 0;
movieBox.TrackBox.MediaBox.MediaHeaderBox.ModificationTime = 0;
movieBox.TrackBox.MediaBox.MediaHeaderBox.Timescale = 1200000;
movieBox.TrackBox.MediaBox.MediaHeaderBox.Duration = 0;
movieBox.TrackBox.MediaBox.HandlerBox = new HandlerBox();
movieBox.TrackBox.MediaBox.HandlerBox.HandlerType = HandlerType.vide;
movieBox.TrackBox.MediaBox.HandlerBox.Name = "VideoHandler";
movieBox.TrackBox.MediaBox.MediaInformationBox = new MediaInformationBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.VideoMediaHeaderBox = new VideoMediaHeaderBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox = new DataInformationBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox = new DataReferenceBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes = new List<DataEntryBox>();
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes.Add(new DataEntryUrlBox(1));
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox = new SampleTableBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries = new List<SampleEntry>();
AVC1SampleEntry avc1 = new AVC1SampleEntry();
avc1.AVCConfigurationBox = new AVCConfigurationBox();
//h264
avc1.Width = (ushort)movieBox.TrackBox.TrackHeaderBox.Width;
avc1.Height = (ushort)movieBox.TrackBox.TrackHeaderBox.Height;
avc1.AVCConfigurationBox.AVCLevelIndication = spsInfo.levelIdc;
avc1.AVCConfigurationBox.AVCProfileIndication = spsInfo.profileIdc;
avc1.AVCConfigurationBox.ProfileCompatibility = (byte)spsInfo.profileCompat;
avc1.AVCConfigurationBox.PPSs = new List<byte[]>() { pps.RawData };
avc1.AVCConfigurationBox.SPSs = new List<byte[]>() { sps.RawData };
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries.Add(avc1);
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.TimeToSampleBox = new TimeToSampleBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SyncSampleBox = new SyncSampleBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleToChunkBox = new SampleToChunkBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleSizeBox = new SampleSizeBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.ChunkOffsetBox = new ChunkOffsetBox();
movieBox.MovieExtendsBox = new MovieExtendsBox();
movieBox.MovieExtendsBox.TrackExtendsBoxs = new List<TrackExtendsBox>();
TrackExtendsBox trex = new TrackExtendsBox();
trex.TrackID = 1;
trex.DefaultSampleDescriptionIndex = 1;
trex.DefaultSampleDuration = 0;
trex.DefaultSampleSize = 0;
trex.DefaultSampleFlags = 0;
movieBox.MovieExtendsBox.TrackExtendsBoxs.Add(trex);
movieBox.ToBuffer(ref writer);
var data = writer.FlushAndGetArray();
return data;
}
finally
{
FMp4ArrayPool.Return(buffer);
}
}

/// <summary>
/// 编码Moof盒子
/// </summary>
@@ -283,6 +369,67 @@ namespace JT1078.FMp4
}
}

/// <summary>
/// 编码Moof盒子
/// </summary>
/// <returns></returns>
public byte[] EncoderMoofBox(List<int> naluSzies, ulong timestamp, uint frameInterval, uint IframeInterval, uint keyframeFlag)
{
byte[] buffer = FMp4ArrayPool.Rent(4096);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer);
try
{
var movieFragmentBox = new MovieFragmentBox();
movieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox();
movieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = sn++;
movieFragmentBox.TrackFragmentBox = new TrackFragmentBox();
//0x39 写文件
//0x02 分段
//0x2003a
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(0x2003a);
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = 1;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.SampleDescriptionIndex = 1;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = frameInterval;
//movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = 48000;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleSize = (uint)naluSzies[0];
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = 0x1010000;
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox();
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = cts;
//trun
//0x39 写文件
//0x02 分段
//0x205
//uint flag = 0x000200 | 0x000800 | 0x000400 | 0x000100;
uint flag = 0x0001;
if (!first)
{
flag |= 0x0004;
first = true;
}
flag |= 0x000200;
movieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: flag);
movieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = 33554432;
movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = new List<TrackRunBox.TrackRunInfo>();
foreach(var size in naluSzies)
{
movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos.Add(new TrackRunBox.TrackRunInfo()
{
//SampleDuration= frameInterval,
SampleSize = (uint)size,
//SampleCompositionTimeOffset = frameInterval,
//SampleFlags = movieFragmentBox.TrackFragmentBox.TrackRunBox.Flags
});
}
movieFragmentBox.ToBuffer(ref writer);
var data = writer.FlushAndGetArray();
return data;
}
finally
{
FMp4ArrayPool.Return(buffer);
}
}

/// <summary>
/// 编码Mdat盒子
/// </summary>
@@ -305,6 +452,28 @@ namespace JT1078.FMp4
}
}

/// <summary>
/// 编码Mdat盒子
/// </summary>
/// <returns></returns>
public byte[] EncoderMdatBox(List<byte[]> nalus)
{
byte[] buffer = FMp4ArrayPool.Rent(nalus.Sum(s=>s.Length) + 4096);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer);
try
{
var mediaDataBox = new MediaDataBox();
mediaDataBox.Data = nalus;
mediaDataBox.ToBuffer(ref writer);
var data = writer.FlushAndGetArray();
return data;
}
finally
{
FMp4ArrayPool.Return(buffer);
}
}

/// <summary>
/// 编码首个视频盒子
/// </summary>


+ 18
- 0
src/JT1078.FMp4/JT1078.FMp4.xml Parādīt failu

@@ -1348,18 +1348,36 @@
</summary>
<returns></returns>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderMoovBox(JT1078.Protocol.H264.H264NALU@,JT1078.Protocol.H264.H264NALU@)">
<summary>
编码moov盒子
</summary>
<returns></returns>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderMoofBox(System.Collections.Generic.List{JT1078.Protocol.H264.H264NALU},System.Int32,System.UInt64,System.UInt32,System.UInt32,System.UInt32)">
<summary>
编码Moof盒子
</summary>
<returns></returns>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderMoofBox(System.Collections.Generic.List{System.Int32},System.UInt64,System.UInt32,System.UInt32,System.UInt32)">
<summary>
编码Moof盒子
</summary>
<returns></returns>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderMdatBox(System.Collections.Generic.List{JT1078.Protocol.H264.H264NALU},System.Int32)">
<summary>
编码Mdat盒子
</summary>
<returns></returns>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderMdatBox(System.Collections.Generic.List{System.Byte[]})">
<summary>
编码Mdat盒子
</summary>
<returns></returns>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderFirstVideoBox(JT1078.Protocol.JT1078Package)">
<summary>
编码首个视频盒子


+ 23
- 1
src/JT1078.FMp4/MessagePack/FMp4MessagePackWriter.cs Parādīt failu

@@ -13,12 +13,14 @@ namespace JT1078.FMp4.MessagePack
private int TrunDataOffsetPosition;

private int MfraSizePosition;
private int MoofOffsetPosition;

public FMp4MessagePackWriter(Span<byte> buffer)
{
this.writer = new FMp4BufferWriter(buffer);
TrunDataOffsetPosition = 0;
MfraSizePosition = 0;
MoofOffsetPosition = 0;
}
public byte[] FlushAndGetArray()
{
@@ -109,6 +111,10 @@ namespace JT1078.FMp4.MessagePack
{
BinaryPrimitives.WriteUInt32BigEndian(writer.Written.Slice(position, 4), value);
}
public void WriteUInt64Return(ulong value, int position)
{
BinaryPrimitives.WriteUInt64BigEndian(writer.Written.Slice(position, 8), value);
}
public void WriteByteReturn(byte value, int position)
{
writer.Written[position] = value;
@@ -139,7 +145,7 @@ namespace JT1078.FMp4.MessagePack
MfraSizePosition = writer.WrittenCount;
}

public int GetMfraSizePositionn()
public int GetMfraSizePosition()
{
return MfraSizePosition;
}
@@ -149,6 +155,22 @@ namespace JT1078.FMp4.MessagePack
MfraSizePosition = 0;
}

public void CreateMoofOffsetPosition()
{
MoofOffsetPosition = writer.WrittenCount;
}

public int GetMoofOffsetPosition()
{
return MoofOffsetPosition;
}

public void ClearMoofOffsetPosition()
{
MoofOffsetPosition = 0;
}


/// <summary>
/// ref
/// </summary>


+ 2
- 2
src/JT1078.Protocol.Test/JT1078SerializerTest.cs Parādīt failu

@@ -336,13 +336,13 @@ namespace JT1078.Protocol.Test
[Fact]
public void MergeTest()
{
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "JT1078.txt"));
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "h264","JT1078_1.txt"));
JT1078Package merge=null;
int mergeBodyLength=0;
foreach (var line in lines)
{
var data = line.Split(',');
var bytes = data[5].ToHexBytes();
var bytes = data[6].ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
mergeBodyLength += package.DataBodyLength;
merge = JT1078Serializer.Merge(package);


+ 63
- 3
src/JT1078.Protocol/H264/H264Decoder.cs Parādīt failu

@@ -18,7 +18,7 @@ namespace JT1078.Protocol.H264
public List<H264NALU> ParseNALU(JT1078Package package, string key = null)
{
List<H264NALU> h264NALUs = new List<H264NALU>();
int i=0,state=0;
int i=0,state=0,laststate=0;
int? lastIndex=null;
int length = package.Bodies.Length;
byte value;
@@ -45,9 +45,10 @@ namespace JT1078.Protocol.H264
if (lastIndex.HasValue)
{
var tmp = buffer.Slice(lastIndex.Value, i - state - 1 - lastIndex.Value);
h264NALUs.Add(Create(package, tmp, state));
h264NALUs.Add(Create(package, tmp, state+1));
}
lastIndex = i;
laststate = state+1;
state = 0;
}
else
@@ -61,11 +62,69 @@ namespace JT1078.Protocol.H264
}
if (lastIndex.HasValue)
{
h264NALUs.Add(Create(package, buffer.Slice(lastIndex.Value), 4));
h264NALUs.Add(Create(package, buffer.Slice(lastIndex.Value), laststate));
}
return h264NALUs;
}

/// <summary>
///
/// <see cref="https://github.com/samirkumardas/jmuxer/blob/master/src/parsers/h264.js"/>
/// </summary>
/// <param name="package"></param>
/// <param name="h264NALUs"></param>
/// <param name="key"></param>
/// <returns></returns>
public void ParseNALU(JT1078Package package, List<H264NALU> h264NALUs,string key = null)
{
int i = 0, state = 0, laststate = 0;
int? lastIndex = null;
int length = package.Bodies.Length;
byte value;
ReadOnlySpan<byte> buffer = package.Bodies;
while (i < length)
{
value = buffer[i++];
switch (state)
{
case 0:
if (value == 0) state = 1;
break;
case 1:
state = value == 0 ? 2 : 0;
break;
case 2:
case 3:
if (value == 0)
{
state = 3;
}
else if (value == 1 && i < length)
{
if (lastIndex.HasValue)
{
var tmp = buffer.Slice(lastIndex.Value, i - state - 1 - lastIndex.Value);
h264NALUs.Add(Create(package, tmp, lastIndex.Value));
}
lastIndex = i;
laststate = state + 1;
state = 0;
}
else
{
state = 0;
}
break;
default:
break;
}
}
if (lastIndex.HasValue)
{
h264NALUs.Add(Create(package, buffer.Slice(lastIndex.Value), laststate));
}
}

private H264NALU Create(JT1078Package package,ReadOnlySpan<byte> nalu, int startCodePrefix)
{
H264NALU nALU = new H264NALU();
@@ -75,6 +134,7 @@ namespace JT1078.Protocol.H264
nALU.LastFrameInterval = package.LastFrameInterval;
nALU.LastIFrameInterval = package.LastIFrameInterval;
nALU.Timestamp = package.Timestamp;
nALU.Slice = (nalu[1] & 0x80)== 0x80;
nALU.RawData = nalu.ToArray();
if (startCodePrefix == 3)
{


+ 5
- 0
src/JT1078.Protocol/H264/H264NALU.cs Parādīt failu

@@ -40,6 +40,11 @@ namespace JT1078.Protocol.H264
/// 当数据类型为01000时,则没有该字段
/// </summary>
public ulong Timestamp { get; set; }

/// <summary>
/// 是否切片 0x80
/// </summary>
public bool Slice { get; set; }
/// <summary>
/// 数据体
/// </summary>


+ 15
- 0
src/JT1078.Protocol/JT1078.Protocol.xml Parādīt failu

@@ -122,6 +122,16 @@
<param name="key"></param>
<returns></returns>
</member>
<member name="M:JT1078.Protocol.H264.H264Decoder.ParseNALU(JT1078.Protocol.JT1078Package,System.Collections.Generic.List{JT1078.Protocol.H264.H264NALU},System.String)">
<summary>
<see cref="!:https://github.com/samirkumardas/jmuxer/blob/master/src/parsers/h264.js"/>
</summary>
<param name="package"></param>
<param name="h264NALUs"></param>
<param name="key"></param>
<returns></returns>
</member>
<member name="M:JT1078.Protocol.H264.H264Decoder.DiscardEmulationPreventionBytes(System.ReadOnlySpan{System.Byte})">
<summary>
Expunge any "Emulation Prevention" bytes from a "Raw Byte Sequence Payload"
@@ -166,6 +176,11 @@
当数据类型为01000时,则没有该字段
</summary>
</member>
<member name="P:JT1078.Protocol.H264.H264NALU.Slice">
<summary>
是否切片 0x80
</summary>
</member>
<member name="P:JT1078.Protocol.H264.H264NALU.RawData">
<summary>
数据体


Notiek ielāde…
Atcelt
Saglabāt