@@ -42,7 +42,7 @@ namespace JT1078.AV.Benchmark | |||||
Package = JT1078Serializer.Merge(package); | Package = JT1078Serializer.Merge(package); | ||||
} | } | ||||
H264NALUs = h264Decoder.ParseNALU(Package); | H264NALUs = h264Decoder.ParseNALU(Package); | ||||
SPSNALu = H264NALUs.FirstOrDefault(f => f.NALUHeader.NalUnitType == 7); | |||||
SPSNALu = H264NALUs.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS); | |||||
SPSNALu.RawData = h264Decoder.DiscardEmulationPreventionBytes(SPSNALu.RawData); | SPSNALu.RawData = h264Decoder.DiscardEmulationPreventionBytes(SPSNALu.RawData); | ||||
} | } | ||||
@@ -96,17 +96,17 @@ | |||||
// otherwise insert it to queue | // otherwise insert it to queue | ||||
var memview = new Uint8Array(arr); | var memview = new Uint8Array(arr); | ||||
if (verbose) { console.log("got", arr.byteLength, "bytes. Values=", memview[0], memview[1], memview[2], memview[3], memview[4]); } | if (verbose) { console.log("got", arr.byteLength, "bytes. Values=", memview[0], memview[1], memview[2], memview[3], memview[4]); } | ||||
//res = getBox(memview, 0); | |||||
//main_length = res[0]; name = res[1]; // this boxes length and name | |||||
//if ((name == "ftyp") && (pass == 0)) { | |||||
res = getBox(memview, 0); | |||||
main_length = res[0]; name = res[1]; // this boxes length and name | |||||
// if ((name == "ftyp") && (pass == 0)) { | |||||
// pass = pass + 1; | // pass = pass + 1; | ||||
// console.log("got ftyp"); | // console.log("got ftyp"); | ||||
//} | |||||
//else if ((name == "moov") && (pass == 1)) { | |||||
// } | |||||
// else if ((name == "moov") && (pass == 1)) { | |||||
// pass = pass + 1; | // pass = pass + 1; | ||||
// console.log("got moov"); | // console.log("got moov"); | ||||
//} | |||||
//else if ((name == "moof") && (pass == 2)) { | |||||
// } | |||||
// else if ((name == "moof") && (pass == 2)) { | |||||
// if (hasFirstSampleFlag(memview)) { | // if (hasFirstSampleFlag(memview)) { | ||||
// pass = pass + 1; | // pass = pass + 1; | ||||
// console.log("got that special moof"); | // console.log("got that special moof"); | ||||
@@ -114,10 +114,10 @@ | |||||
// else { | // else { | ||||
// return; | // return; | ||||
// } | // } | ||||
//} | |||||
//else if (pass < 3) { | |||||
// } | |||||
// else if (pass < 3) { | |||||
// return; | // return; | ||||
//} | |||||
// } | |||||
// keep the latency to minimum | // keep the latency to minimum | ||||
let latest = stream_live.duration; | let latest = stream_live.duration; | ||||
if ((stream_live.duration >= buffering_sec) && | if ((stream_live.duration >= buffering_sec) && | ||||
@@ -24,10 +24,10 @@ namespace JT1078.FMp4.Test | |||||
var jT1078Package = ParseNALUTest(); | var jT1078Package = ParseNALUTest(); | ||||
H264Decoder decoder = new H264Decoder(); | H264Decoder decoder = new H264Decoder(); | ||||
var nalus = decoder.ParseNALU(jT1078Package); | var nalus = decoder.ParseNALU(jT1078Package); | ||||
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7); | |||||
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS); | |||||
//SPS | //SPS | ||||
spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); | spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); | ||||
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8); | |||||
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS); | |||||
ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData); | ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData); | ||||
//ftyp | //ftyp | ||||
FileTypeBox fileTypeBox = new FileTypeBox(); | FileTypeBox fileTypeBox = new FileTypeBox(); | ||||
@@ -176,10 +176,10 @@ namespace JT1078.FMp4.Test | |||||
var jT1078Package = ParseNALUTest(); | var jT1078Package = ParseNALUTest(); | ||||
H264Decoder decoder = new H264Decoder(); | H264Decoder decoder = new H264Decoder(); | ||||
var nalus = decoder.ParseNALU(jT1078Package); | var nalus = decoder.ParseNALU(jT1078Package); | ||||
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7); | |||||
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS); | |||||
//SPS | //SPS | ||||
spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); | spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); | ||||
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8); | |||||
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS); | |||||
ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData); | ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData); | ||||
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(new byte[65535]); | FMp4MessagePackWriter writer = new FMp4MessagePackWriter(new byte[65535]); | ||||
//ftyp | //ftyp | ||||
@@ -324,10 +324,10 @@ namespace JT1078.FMp4.Test | |||||
using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write); | using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write); | ||||
var jT1078Package = packages.FirstOrDefault(); | var jT1078Package = packages.FirstOrDefault(); | ||||
var nalus = decoder.ParseNALU(jT1078Package); | var nalus = decoder.ParseNALU(jT1078Package); | ||||
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7); | |||||
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS); | |||||
//SPS | //SPS | ||||
spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); | spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); | ||||
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8); | |||||
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS); | |||||
ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData); | ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData); | ||||
ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData); | ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData); | ||||
var spsInfo = h264GolombReader.ReadSPS(); | var spsInfo = h264GolombReader.ReadSPS(); | ||||
@@ -455,15 +455,16 @@ namespace JT1078.FMp4.Test | |||||
{ | { | ||||
var otherStypBuffer = fMp4Encoder.EncoderStypBox(); | var otherStypBuffer = fMp4Encoder.EncoderStypBox(); | ||||
fileStream.Write(otherStypBuffer); | fileStream.Write(otherStypBuffer); | ||||
var otherSidxBuffer = fMp4Encoder.EncoderSidxBox(package.Timestamp, package.LastIFrameInterval); | |||||
fileStream.Write(otherSidxBuffer); | |||||
var otherNalus = h264Decoder.ParseNALU(package); | var otherNalus = h264Decoder.ParseNALU(package); | ||||
var flag = package.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧 ? 1u : 0u; | var flag = package.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧 ? 1u : 0u; | ||||
var otherMoofBuffer = fMp4Encoder.EncoderMoofBox(otherNalus, package.Bodies.Length, package.Timestamp, package.LastIFrameInterval, flag); | var otherMoofBuffer = fMp4Encoder.EncoderMoofBox(otherNalus, package.Bodies.Length, package.Timestamp, package.LastIFrameInterval, flag); | ||||
var otherMdatBuffer = fMp4Encoder.EncoderMdatBox(otherNalus, package.Bodies.Length); | var otherMdatBuffer = fMp4Encoder.EncoderMdatBox(otherNalus, package.Bodies.Length); | ||||
var otherSidxBuffer = fMp4Encoder.EncoderSidxBox(otherMoofBuffer.Length + otherMdatBuffer.Length, package.Timestamp, package.LastIFrameInterval); | |||||
fileStream.Write(otherSidxBuffer); | |||||
fileStream.Write(otherMoofBuffer); | fileStream.Write(otherMoofBuffer); | ||||
fileStream.Write(otherMdatBuffer); | fileStream.Write(otherMdatBuffer); | ||||
} | } | ||||
fileStream.Close(); | fileStream.Close(); | ||||
} | } | ||||
@@ -28,6 +28,7 @@ namespace JT1078.FMp4 | |||||
/// </summary> | /// </summary> | ||||
public uint Timescale { get; set; } = 1000; | public uint Timescale { get; set; } = 1000; | ||||
/// <summary> | /// <summary> | ||||
/// pts | |||||
/// if(version==0) | /// if(version==0) | ||||
/// version==0 32 bit | /// version==0 32 bit | ||||
/// version>0 64 bit | /// version>0 64 bit | ||||
@@ -100,6 +101,7 @@ namespace JT1078.FMp4 | |||||
public bool ReferenceType { get; set; } = false; | public bool ReferenceType { get; set; } = false; | ||||
/// <summary> | /// <summary> | ||||
/// 4byte 32 - 31 | /// 4byte 32 - 31 | ||||
/// ReferencedSize=(moof size) + (mdat size) | |||||
/// </summary> | /// </summary> | ||||
public uint ReferencedSize { get; set; } = 0; | public uint ReferencedSize { get; set; } = 0; | ||||
/// <summary> | /// <summary> | ||||
@@ -24,6 +24,7 @@ namespace JT1078.FMp4 | |||||
/// 0x000200-0010 0000 0000: 每个 sample 有自己的 sample_size,否则使用默认的。 | /// 0x000200-0010 0000 0000: 每个 sample 有自己的 sample_size,否则使用默认的。 | ||||
/// 0x000400-0100 0000 0000: 对每个 sample 使用自己的 flags。否则,使用默认的。 | /// 0x000400-0100 0000 0000: 对每个 sample 使用自己的 flags。否则,使用默认的。 | ||||
/// 0x000800-1000 0000 0000: 每个 sample 都有自己的 cts 值 | /// 0x000800-1000 0000 0000: 每个 sample 都有自己的 cts 值 | ||||
/// 0x000f01-1111 0000 0001 | |||||
/// </summary> | /// </summary> | ||||
/// <param name="version"></param> | /// <param name="version"></param> | ||||
/// <param name="flags"></param> | /// <param name="flags"></param> | ||||
@@ -101,11 +102,11 @@ namespace JT1078.FMp4 | |||||
{ | { | ||||
if (Version == 0) | if (Version == 0) | ||||
{ | { | ||||
writer.WriteUInt32(trun.SampleCompositionTimeOffset); | |||||
writer.WriteUInt32((uint)trun.SampleCompositionTimeOffset); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
writer.WriteInt32(trun.SignedSampleCompositionTimeOffset); | |||||
writer.WriteInt32((int)trun.SampleCompositionTimeOffset); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -120,9 +121,10 @@ namespace JT1078.FMp4 | |||||
public uint SampleFlags { get; set; } | public uint SampleFlags { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// version == 0 | /// version == 0 | ||||
/// 0:uint | |||||
/// >0:int | |||||
/// </summary> | /// </summary> | ||||
public uint SampleCompositionTimeOffset { get; set; } | |||||
public int SignedSampleCompositionTimeOffset { get; set; } | |||||
public long SampleCompositionTimeOffset { get; set; } | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -31,6 +31,7 @@ namespace JT1078.FMp4 | |||||
public class FMp4Encoder | public class FMp4Encoder | ||||
{ | { | ||||
readonly H264Decoder h264Decoder; | readonly H264Decoder h264Decoder; | ||||
/// <summary> | /// <summary> | ||||
/// | /// | ||||
/// </summary> | /// </summary> | ||||
@@ -111,7 +112,7 @@ namespace JT1078.FMp4 | |||||
/// 编码sidx盒子 | /// 编码sidx盒子 | ||||
/// </summary> | /// </summary> | ||||
/// <returns></returns> | /// <returns></returns> | ||||
public byte[] EncoderSidxBox(ulong timestamp, uint frameInterval) | |||||
public byte[] EncoderSidxBox(int moofAndMdatLength, ulong timestamp, uint frameInterval) | |||||
{ | { | ||||
byte[] buffer = FMp4ArrayPool.Rent(4096); | byte[] buffer = FMp4ArrayPool.Rent(4096); | ||||
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer); | FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer); | ||||
@@ -119,11 +120,12 @@ namespace JT1078.FMp4 | |||||
{ | { | ||||
SegmentIndexBox segmentIndexBox = new SegmentIndexBox(1); | SegmentIndexBox segmentIndexBox = new SegmentIndexBox(1); | ||||
segmentIndexBox.ReferenceID = 1; | segmentIndexBox.ReferenceID = 1; | ||||
segmentIndexBox.EarliestPresentationTime = timestamp; | |||||
segmentIndexBox.EarliestPresentationTime = timestamp*1000; | |||||
segmentIndexBox.SegmentIndexs = new List<SegmentIndexBox.SegmentIndex>() | segmentIndexBox.SegmentIndexs = new List<SegmentIndexBox.SegmentIndex>() | ||||
{ | { | ||||
new SegmentIndexBox.SegmentIndex | new SegmentIndexBox.SegmentIndex | ||||
{ | { | ||||
ReferencedSize=(uint)moofAndMdatLength, | |||||
SubsegmentDuration=frameInterval | SubsegmentDuration=frameInterval | ||||
} | } | ||||
}; | }; | ||||
@@ -147,10 +149,10 @@ namespace JT1078.FMp4 | |||||
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer); | FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer); | ||||
try | try | ||||
{ | { | ||||
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7); | |||||
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS); | |||||
//SPS | //SPS | ||||
spsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); | spsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); | ||||
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8); | |||||
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS); | |||||
ppsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData); | ppsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData); | ||||
ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData); | ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData); | ||||
var spsInfo = h264GolombReader.ReadSPS(); | var spsInfo = h264GolombReader.ReadSPS(); | ||||
@@ -242,37 +244,29 @@ namespace JT1078.FMp4 | |||||
//0x02 分段 | //0x02 分段 | ||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(0x20038); | movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(0x20038); | ||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = 1; | movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = 1; | ||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = 48000; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = frameInterval; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleSize = (uint)naluLength; | movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleSize = (uint)naluLength; | ||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = 0x1010000; | movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = 0x1010000; | ||||
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox(); | movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox(); | ||||
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = timestamp*1000; | |||||
//trun | //trun | ||||
//0x39 写文件 | //0x39 写文件 | ||||
//0x02 分段 | //0x02 分段 | ||||
//0x205 | |||||
//uint flag = 0x000200 | 0x000800 | 0x000400 | 0x000100; | //uint flag = 0x000200 | 0x000800 | 0x000400 | 0x000100; | ||||
uint flag = 4u; | |||||
if (!first) | |||||
{ | |||||
//sdtp.IsLeading = 1; | |||||
//flag = 4u; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = 0; | |||||
movieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: 5); | |||||
first = true; | |||||
} | |||||
else | |||||
{ | |||||
//flag = 0x000400; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = timestamp*1000; | |||||
movieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: 5); | |||||
} | |||||
movieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(); | |||||
movieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = 33554432; | movieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = 33554432; | ||||
movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = new List<TrackRunBox.TrackRunInfo>(); | movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = new List<TrackRunBox.TrackRunInfo>(); | ||||
if (frameIntervalCache == 0) | |||||
{ | |||||
frameIntervalCache += frameInterval; | |||||
} | |||||
movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos.Add(new TrackRunBox.TrackRunInfo() | movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos.Add(new TrackRunBox.TrackRunInfo() | ||||
{ | { | ||||
SampleDuration= frameInterval, | |||||
SampleDuration= frameIntervalCache, | |||||
SampleSize = (uint)naluLength, | SampleSize = (uint)naluLength, | ||||
SampleCompositionTimeOffset = frameInterval, | |||||
SampleFlags = flag | |||||
SampleCompositionTimeOffset = (long)timestamp , | |||||
SampleFlags = movieFragmentBox.TrackFragmentBox.TrackRunBox.Flags | |||||
}); | }); | ||||
movieFragmentBox.ToBuffer(ref writer); | movieFragmentBox.ToBuffer(ref writer); | ||||
var data = writer.FlushAndGetArray(); | var data = writer.FlushAndGetArray(); | ||||
@@ -318,10 +312,10 @@ namespace JT1078.FMp4 | |||||
try | try | ||||
{ | { | ||||
var nalus = h264Decoder.ParseNALU(package); | var nalus = h264Decoder.ParseNALU(package); | ||||
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7); | |||||
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS); | |||||
//SPS | //SPS | ||||
spsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); | spsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); | ||||
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8); | |||||
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS); | |||||
ppsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData); | ppsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData); | ||||
ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData); | ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData); | ||||
var spsInfo = h264GolombReader.ReadSPS(); | var spsInfo = h264GolombReader.ReadSPS(); | ||||
@@ -405,7 +399,7 @@ namespace JT1078.FMp4 | |||||
} | } | ||||
uint sn = 1; | uint sn = 1; | ||||
uint frameIntervalCache = 0; | |||||
bool first = false; | bool first = false; | ||||
/// <summary> | /// <summary> | ||||
@@ -700,6 +700,7 @@ | |||||
</member> | </member> | ||||
<member name="P:JT1078.FMp4.SegmentIndexBox.EarliestPresentationTime"> | <member name="P:JT1078.FMp4.SegmentIndexBox.EarliestPresentationTime"> | ||||
<summary> | <summary> | ||||
pts | |||||
if(version==0) | if(version==0) | ||||
version==0 32 bit | version==0 32 bit | ||||
version>0 64 bit | version>0 64 bit | ||||
@@ -723,6 +724,7 @@ | |||||
<member name="P:JT1078.FMp4.SegmentIndexBox.SegmentIndex.ReferencedSize"> | <member name="P:JT1078.FMp4.SegmentIndexBox.SegmentIndex.ReferencedSize"> | ||||
<summary> | <summary> | ||||
4byte 32 - 31 | 4byte 32 - 31 | ||||
ReferencedSize=(moof size) + (mdat size) | |||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<member name="P:JT1078.FMp4.SegmentIndexBox.SegmentIndex.SubsegmentDuration"> | <member name="P:JT1078.FMp4.SegmentIndexBox.SegmentIndex.SubsegmentDuration"> | ||||
@@ -1062,6 +1064,7 @@ | |||||
0x000200-0010 0000 0000: 每个 sample 有自己的 sample_size,否则使用默认的。 | 0x000200-0010 0000 0000: 每个 sample 有自己的 sample_size,否则使用默认的。 | ||||
0x000400-0100 0000 0000: 对每个 sample 使用自己的 flags。否则,使用默认的。 | 0x000400-0100 0000 0000: 对每个 sample 使用自己的 flags。否则,使用默认的。 | ||||
0x000800-1000 0000 0000: 每个 sample 都有自己的 cts 值 | 0x000800-1000 0000 0000: 每个 sample 都有自己的 cts 值 | ||||
0x000f01-1111 0000 0001 | |||||
</summary> | </summary> | ||||
<param name="version"></param> | <param name="version"></param> | ||||
<param name="flags"></param> | <param name="flags"></param> | ||||
@@ -1092,6 +1095,8 @@ | |||||
<member name="P:JT1078.FMp4.TrackRunBox.TrackRunInfo.SampleCompositionTimeOffset"> | <member name="P:JT1078.FMp4.TrackRunBox.TrackRunInfo.SampleCompositionTimeOffset"> | ||||
<summary> | <summary> | ||||
version == 0 | version == 0 | ||||
0:uint | |||||
>0:int | |||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<member name="T:JT1078.FMp4.URIBox"> | <member name="T:JT1078.FMp4.URIBox"> | ||||
@@ -1330,7 +1335,7 @@ | |||||
</summary> | </summary> | ||||
<returns></returns> | <returns></returns> | ||||
</member> | </member> | ||||
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderSidxBox(System.UInt64,System.UInt32)"> | |||||
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderSidxBox(System.Int32,System.UInt64,System.UInt32)"> | |||||
<summary> | <summary> | ||||
编码sidx盒子 | 编码sidx盒子 | ||||
</summary> | </summary> | ||||
@@ -207,9 +207,9 @@ namespace JT1078.Flv | |||||
var nalus = h264Decoder.ParseNALU(package); | var nalus = h264Decoder.ParseNALU(package); | ||||
if (nalus != null && nalus.Count > 0) | if (nalus != null && nalus.Count > 0) | ||||
{ | { | ||||
var sei = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == 6); | |||||
var sps = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == 7); | |||||
var pps = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == 8); | |||||
var sei = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == NalUnitType.SEI); | |||||
var sps = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == NalUnitType.SPS); | |||||
var pps = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == NalUnitType.PPS); | |||||
nalus.Remove(sps); | nalus.Remove(sps); | ||||
nalus.Remove(pps); | nalus.Remove(pps); | ||||
nalus.Remove(sei); | nalus.Remove(sei); | ||||
@@ -297,7 +297,7 @@ namespace JT1078.Flv | |||||
//1: keyframe (for AVC, a seekable frame) —— 即H.264的IDR帧; | //1: keyframe (for AVC, a seekable frame) —— 即H.264的IDR帧; | ||||
//2: inter frame(for AVC, a non - seekable frame) —— H.264的普通I帧; | //2: inter frame(for AVC, a non - seekable frame) —— H.264的普通I帧; | ||||
//ref:https://www.cnblogs.com/chyingp/p/flv-getting-started.html | //ref:https://www.cnblogs.com/chyingp/p/flv-getting-started.html | ||||
if (nALU.NALUHeader.NalUnitType == 5) | |||||
if (nALU.NALUHeader.NalUnitType == NalUnitType.IDR) | |||||
{ | { | ||||
flvTags.VideoTagsData.FrameType = FrameType.KeyFrame; | flvTags.VideoTagsData.FrameType = FrameType.KeyFrame; | ||||
} | } | ||||
@@ -41,7 +41,7 @@ namespace JT1078.Flv.Benchmark | |||||
Package = JT1078Serializer.Merge(package); | Package = JT1078Serializer.Merge(package); | ||||
} | } | ||||
H264NALUs = h264Decoder.ParseNALU(Package); | H264NALUs = h264Decoder.ParseNALU(Package); | ||||
SPSNALu = H264NALUs.FirstOrDefault(f => f.NALUHeader.NalUnitType == 7); | |||||
SPSNALu = H264NALUs.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS); | |||||
SPSNALu.RawData = h264Decoder.DiscardEmulationPreventionBytes(SPSNALu.RawData); | SPSNALu.RawData = h264Decoder.DiscardEmulationPreventionBytes(SPSNALu.RawData); | ||||
} | } | ||||
@@ -26,7 +26,7 @@ namespace JT1078.Protocol.Test.H264 | |||||
var nalu = nalus[0]; | var nalu = nalus[0]; | ||||
Assert.Equal(0, nalu.NALUHeader.ForbiddenZeroBit); | Assert.Equal(0, nalu.NALUHeader.ForbiddenZeroBit); | ||||
Assert.Equal(3, nalu.NALUHeader.NalRefIdc); | Assert.Equal(3, nalu.NALUHeader.NalRefIdc); | ||||
Assert.Equal(1, nalu.NALUHeader.NalUnitType); | |||||
Assert.Equal(NalUnitType.SLICE, nalu.NALUHeader.NalUnitType); | |||||
} | } | ||||
[Fact] | [Fact] | ||||
@@ -48,7 +48,7 @@ namespace JT1078.Protocol.Test.H264 | |||||
Assert.Equal(4, nalus.Count); | Assert.Equal(4, nalus.Count); | ||||
//SPS -> 7 | //SPS -> 7 | ||||
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7); | |||||
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS); | |||||
Assert.NotNull(spsNALU); | Assert.NotNull(spsNALU); | ||||
spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); | spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); | ||||
//"Z00AFJWoWCWQ" | //"Z00AFJWoWCWQ" | ||||
@@ -63,15 +63,15 @@ namespace JT1078.Protocol.Test.H264 | |||||
Assert.Equal(352, spsInfo.width); | Assert.Equal(352, spsInfo.width); | ||||
//PPS -> 8 | //PPS -> 8 | ||||
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8); | |||||
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS); | |||||
Assert.NotNull(ppsNALU); | Assert.NotNull(ppsNALU); | ||||
//IDR -> 5 关键帧 | //IDR -> 5 关键帧 | ||||
var idrNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 5); | |||||
var idrNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.IDR); | |||||
Assert.NotNull(idrNALU); | Assert.NotNull(idrNALU); | ||||
//SEI -> 6 | //SEI -> 6 | ||||
var seiNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 6); | |||||
var seiNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SEI); | |||||
Assert.NotNull(seiNALU); | Assert.NotNull(seiNALU); | ||||
} | } | ||||
@@ -14,7 +14,7 @@ namespace JT1078.Flv.Test.H264 | |||||
NALUHeader header = new NALUHeader(0xc0); | NALUHeader header = new NALUHeader(0xc0); | ||||
Assert.Equal(1, header.ForbiddenZeroBit); | Assert.Equal(1, header.ForbiddenZeroBit); | ||||
Assert.Equal(2, header.NalRefIdc); | Assert.Equal(2, header.NalRefIdc); | ||||
Assert.Equal(0, header.NalUnitType); | |||||
Assert.Equal(NalUnitType.None, header.NalUnitType); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -10,16 +10,33 @@ namespace JT1078.Protocol.H264 | |||||
{ | { | ||||
ForbiddenZeroBit = (value & 0x80) >> 7; | ForbiddenZeroBit = (value & 0x80) >> 7; | ||||
NalRefIdc = (value & 0x60) >> 5; | NalRefIdc = (value & 0x60) >> 5; | ||||
NalUnitType = value & 0x1f; | |||||
NalUnitType = (NalUnitType)(value & 0x1f); | |||||
} | } | ||||
public NALUHeader(ReadOnlySpan<byte> value) | public NALUHeader(ReadOnlySpan<byte> value) | ||||
{ | { | ||||
ForbiddenZeroBit = (value[0] & 0x80) >> 7; | ForbiddenZeroBit = (value[0] & 0x80) >> 7; | ||||
NalRefIdc = (value[0] & 0x60) >> 5; | NalRefIdc = (value[0] & 0x60) >> 5; | ||||
NalUnitType = value[0] & 0x1f; | |||||
NalUnitType = (NalUnitType)(value[0] & 0x1f); | |||||
} | } | ||||
public int ForbiddenZeroBit { get; set; } | public int ForbiddenZeroBit { get; set; } | ||||
public int NalRefIdc { get; set; } | public int NalRefIdc { get; set; } | ||||
public int NalUnitType { get; set; } | |||||
public NalUnitType NalUnitType { get; set; } | |||||
} | |||||
public enum NalUnitType : int | |||||
{ | |||||
None=0, | |||||
SLICE = 1, | |||||
DPA = 2, | |||||
DPB = 3, | |||||
DPC = 4, | |||||
IDR = 5, | |||||
SEI = 6, | |||||
SPS = 7, | |||||
PPS = 8, | |||||
AUD = 9, | |||||
EOSEQ = 10, | |||||
EOSTREAM = 11, | |||||
FILL = 12, | |||||
} | } | ||||
} | } |
@@ -17,6 +17,7 @@ using JT1078.Protocol; | |||||
using System.IO; | using System.IO; | ||||
using JT1078.Protocol.Extensions; | using JT1078.Protocol.Extensions; | ||||
using JT1078.Protocol.H264; | using JT1078.Protocol.H264; | ||||
using System.Net.WebSockets; | |||||
namespace JT1078.SignalR.Test.Services | namespace JT1078.SignalR.Test.Services | ||||
{ | { | ||||
@@ -78,7 +79,7 @@ namespace JT1078.SignalR.Test.Services | |||||
//q.Enqueue(moov); | //q.Enqueue(moov); | ||||
first.Add(moov); | first.Add(moov); | ||||
q.Add(first.SelectMany(s=>s).ToArray()); | q.Add(first.SelectMany(s=>s).ToArray()); | ||||
List<int> filter = new List<int>() { 6,7,8}; | |||||
List<NalUnitType> filter = new List<NalUnitType>() { NalUnitType.SEI,NalUnitType.SPS,NalUnitType.PPS}; | |||||
foreach (var package in packages) | foreach (var package in packages) | ||||
{ | { | ||||
List<byte[]> other = new List<byte[]>(); | List<byte[]> other = new List<byte[]>(); | ||||
@@ -97,6 +98,7 @@ namespace JT1078.SignalR.Test.Services | |||||
} | } | ||||
} | } | ||||
public Dictionary<string,int> flag = new Dictionary<string, int>(); | public Dictionary<string,int> flag = new Dictionary<string, int>(); | ||||
protected async override Task ExecuteAsync(CancellationToken stoppingToken) | protected async override Task ExecuteAsync(CancellationToken stoppingToken) | ||||